嘆き
全ては、内部処理が48bit-colorになったからって、それをスクショ時にそのまま書き出すiOSが悪い!
そんなあっさり48bit-colorのPNGなんて渡ってくると思わねえよ!
bitmapのpixel formatの基本
各ピクセルのRGBAのデータがひたすら並んでいる。
RGBAの順番については色々。
大概は24bit-color(RGB各8bit)+alpha(8bit)で32bit/pixel。
iOSでbitmap読むとき
CGBitmapContextGetAlphaInfo()
とCGBitmapContextGetBitmapInfo()
の値を見比べてやる
AlphaInfo
typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {
kCGImageAlphaNone, /* For example, RGB. */
kCGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */
kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
kCGImageAlphaLast, /* For example, non-premultiplied RGBA */
kCGImageAlphaFirst, /* For example, non-premultiplied ARGB */
kCGImageAlphaNoneSkipLast, /* For example, RGBX. */
kCGImageAlphaNoneSkipFirst, /* For example, XRGB. */
kCGImageAlphaOnly /* No color data, alpha data only */
};
↑ 元のヘッダファイルのkCGImageAlphaNoneSkipLastのコメント、「R B G X」は奴らのtypoなので注意。 (上の引用では修正済)
- Aの位置がどこにあるか
- Aはあるのか
- premultiplied(アルファ乗算済み)かどうか
ByteOrderInfo
typedef CF_ENUM(uint32_t, CGImageByteOrderInfo) {
kCGImageByteOrderMask = 0x7000,
kCGImageByteOrder16Little = (1 << 12),
kCGImageByteOrder32Little = (2 << 12),
kCGImageByteOrder16Big = (3 << 12),
kCGImageByteOrder32Big = (4 << 12)
};
- 区切りが16bitか32bitか。
- byteorderがbig(そのまま)かlittle(逆順)か
BitsPer
size_t CGImageGetBitsPerComponent(CGImageRef image);
size_t CGImageGetBitsPerPixel(CGImageRef image);
これが今回のミソ。
普通に8bit/compoment、32bit/pixelが返ってくるものと思っていたが、いやいや。
ただスクショを撮って、それをImagePickerで読み込むだけで。
16bit/component、64bit/pixelのデータが来るわけですよ。まじかよ。さすが未来に生きてるな、Apple。
結論
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|---|
24bit-color RGBA | R | G | B | A | ||||
24bit-color RGBA / LE32 | A | B | G | R | ||||
48bit-color RGBA | R | r | G | g | B | b | A | a |
48bit-color RGBA / LE16 | r | R | g | G | b | B | a | A |
UInt8のポインタでアクセスして、以下な感じで済ますのが良さげだった
#define u16(p,i,le) (le?p[2*i]+(p[2*i+1]<<8):(p[2*i]<<8)+p[2*i+1])
あとpremultipiledな場合は
CGFloat fa = p[3] / UINT8_MAX;
UInt8 r = p[0] / fa;
UInt8 g = p[1] / fa;
UInt8 b = p[2] / fa;
UInt8 a = p[3];
な感じで使う前にalphaを逆算してあげてね
その他
他にも値がUnsigned intでなくfloating pointだったりすることもあるらしい(kCGBitmapFloatInfoMask
)のだが、さすがに対応を割愛。