Swift UIColor Extension でよくある 16進数カラーコードを UIColor に変換する時のビット演算について
前談
import UIKit extension UIColor { convenience init(red: Int, green: Int, blue: Int) { self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) } convenience init(rgb: Int) { self.init( red: (rgb >> 16) & 0xFF, green: (rgb >> 8) & 0xFF, blue: rgb & 0xFF ) } }
16進数カラーコードを UIColor
に変換する時の UIColor Extension
で上記のようなコードを見かけませんか?
UIColor Hex
とかで検索すると上記のような UIColor の Extensionが出てきます。
こんなの
今回は上記のコードで使用されているビット演算についてです。
普段あまりビット演算を使う場面がないので、
自分なりに何をしているか理解した範囲で話します。間違いがありましたらコメントで教えてください。
最低限、2進数、10進数、16進数の理解がないと難しいかもしれません。
例として16進数のカラーコード #3a294b
を入れて説明します。
ちなみに#3a294b
は 10進数 RGB
で表すと Red: 58, Green: 41, Blue: 75
(0 ~ 255) となります。
UIColor.init(rgb: 0x3a294b)
Swiftの 0x
はプリフィックスで、16進数の定数の前には 0x
を付けます。10進数の場合はプリフィックスは不要です。したがって Swiftで let a = 8
と書いた場合は10進数になります。
16進数 3a294b
を2進数に変換すると以下のようになります。
00111010 / 00101001 / 01001011
※わかりやすく 8bitごとに /
で区切って、桁数が揃うように先頭の00
を補っています。
他にも例えば 16進数 FFFFFF
を2進数に変換すると以下のようになります。
11111111 / 11111111 / 11111111
さっと2進数を確認したい場合は、以下のように 16進数から2進数に変換できます
String(0x3a294b, radix: 2) // "1110100010100101001011"
本題
こちらの方から1つずつ見て行きます。
convenience init(rgb: Int) { self.init( red: (rgb >> 16) & 0xFF, green: (rgb >> 8) & 0xFF, blue: rgb & 0xFF ) }
Red
red: (rgb >> 16) & 0xFF,
今回は rgb には 0x3a294b
が入ります。
0x3a294b >> 16
>>
は右ビットシフトを表すビットシフト演算子です。
したがって、式が表す意味は 16進数 3a294b
を 16bit
分を右シフトさせる。
00111010 / 00101001 / 01001011
16進数 3a294b
を 16bit
分を右シフトさせると
00000000 / 00000000 / 00111010
16進数 3a294b
の Redの部分 16進数 3a を取り出せました。
次に
0x3a & 0xFF
&
はビットANDを表すビットシフト演算子です。
したがって、式が表す意味は 16進数 0x3a
を 0xFF
とビットANDする。
これは 0x3a
と 0xFF
で ビットANDすることで最大数を16進数 FF
にするためです。
00111010
と
11111111
の ビットANDをとると
00111010
となり、これを10進数に変換すると58
になり, Red は 58
です。合っていますね。
Green
green: (rgb >> 8) & 0xFF,
同様に見て行くと
0x3a294b >> 8
式が表す意味は 16進数 3a294b
を 8bit
分を右シフトさせる。
00111010 / 00101001 / 01001011
16進数 3a294b
を 8bit
分を右シフトさせると
00000000 / 00111010 / 00101001
16進数 3a294b
の RedとGreenの部分 16進数 3a29 を取り出せました。
次に
0x3a29 & 0xFF
式が表す意味は 16進数 0x3a29
を 0xFF
とビットANDする。
00000000 / 00111010 / 00101001
と
00000000 / 00000000 / 11111111
の ビットANDをとると
00101001
となり、これを10進数に変換すると41
になり, Green は 41
です。合っていますね。
Blue
次に
blue: rgb & 0xFF
同様に見て行くと
0x3a294b & 0xFF
式が表す意味は 16進数 0x3a294b
を 0xFF
とビットANDする。
Blue 特に右シフトせずに、ビットANDを取っています。
Blue は 8bit 部分なので、ビットシフトする必要がありません。
00111010 / 00101001 / 01001011
と
00000000 / 00000000 / 11111111
の ビットANDをとると
00000000 / 00000000 / 01001011
つまり
01001011
となり、これを10進数に変換すると75
になり, Green は 75
です。合っていますね。
よって、今回の例だと
UIColor.init(red: 58, green: 41, blue: 75)
という形で
convenience init(red: Int, green: Int, blue: Int) { self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) }
こちらのメソッドを読んでいることになります。
また
convenience init(red: Int, green: Int, blue: Int) { self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) }
こちらの関数は、UIKit
で実装されている UIColor.init
に合うように
RGB
のそれぞれの値が 0 ~ 1
になるように 255
で 割っています。
以上です。
サンプルソースコードはこちらにあげています。