🎨

透明化されているカラーコードを非透明で同じ色に見えるコードへ変換(hex8桁をhex6桁へ)

使用する言語

Ruby(Rubyon Rails)環境化です。

透明化されているカラーコードとは何か?

"#00000000"のような、8桁で表すカラーコード。style等で使用するアレです
下2桁は透明度を指定しているので、6桁の場合は透明になりません。
RGBAのAの部分です。

具体例


6桁の赤色


6桁の赤色#FF0606を半透明にして作ったピンク


6桁で再現された同じ色に見えるピンク(これにしたい!)

コード(該当メソッドのみ抜粋)


    # 透明化されているカラーコードを非透明で同じ色に見えるコードへ変換(hex8桁をhex6桁へ)
    def self.not_transparent_conversion(color_code)
      formating_color_code = color_code.delete("#")
      return color_code unless formating_color_code.length == 8
      rgba = self.hex_to_rgb_or_rgba(formating_color_code)
      rgb = self.rgba_to_rgb(rgba)
      self.rgb_or_rgba_to_hex(rgb)
    end

    # カラーコードをrgbに変換する。透明化コードならrgbaで返す
    def self.hex_to_rgb_or_rgba(color_code)
      formating_color_code = color_code.delete("#")
      formating_color_code.each_char.each_slice(2).map{|a| a.join.to_i(16)}
    end

    # rgbaをrgbに変換(非透明化)
    def self.rgba_to_rgb(rgba)
        r = rgba[0]
        g = rgba[1]
        b = rgba[2]
        a = rgba[3]

        opacity = a / 255.to_f
        cr = (r * opacity + 255 * ( 1 - opacity)).round
        cg = (g * opacity + 255 * ( 1 - opacity)).round
        cb = (b * opacity + 255 * ( 1 - opacity)).round
        [cr, cg, cb]
    end

    # rgbもしくはrgbaをhexコードにして返す
    def self.rgb_or_rgba_to_hex(rgb)
      "##{rgb.map{|i| i.to_s(16).rjust(2, '0')}.join.upcase}"
    end

実行例

not_transparent_conversion("#FF06064D")
=> "#FFB4B4"

ロジック

ざっくり処理の流れ

・カラーコードを16進数から10進数に変換し、RGBまたはRGBAの配列にする
・RGBA配列をRGB配列に変換。
・RGB配列を各要素16進数の文字列に逆変換し、連結してHEXカラーコードに戻す。

ついでに

透明でないカラーコードを把握できれば、そのカラーを背景に使用した際に、テキストに白色か黒色のどちらが適しているかの判定ができるようになります。

    # 背景色に対し、黒色と白色どちらか文字色として適しているカラーコードを返す
    def black_or_white_judgment(color_code)
      formating_color_code = color_code.delete("#")
      length = formating_color_code.length
      raise 'カラーコードが不正です' unless length == 3 || length == 6 || length == 8

      # 6桁に統一
      if formating_color_code.length == 8
        formating_color_code = self.not_transparent_conversion(formating_color_code)   
      elsif formating_color_code.length == 3
        formating_color_code = self.short_code_to_normal_code(formating_color_code)  
      end

      rgb = self.hex_to_rgb_or_rgba(formating_color_code)
      cr = rgb[0]
      cg = rgb[1]
      cb = rgb[2]

      ((((cr * 299) + (cg * 587) + (cb * 114) ) / 1000 ) < 128 ) ? "#ffffff" : "#000000" ;
    end

    # 3桁の短縮コードを6桁に
    def short_code_to_normal_code(short_color_code)
      formating_color_code = short_color_code.delete("#")
      normal_code = formating_color_code.each_char.map{|c| "#{c}#{c}" }.join
      "##{normal_code}"
    end
OSIRO テックブログ

Discussion