diff options
author | msarett <msarett@google.com> | 2016-09-12 14:30:03 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-09-12 14:30:03 -0700 |
commit | f17b71f6c9b94e93f88e103b3b6cab61cbee76d7 (patch) | |
tree | 8195f4651324af98584cd76a6faad60f047741c6 /src/images | |
parent | ea5de1ff1dcdbfbf3e4314dc151dd1a03023cbb1 (diff) |
Support RGBA/BGRA Premul/Unpremul from SkPNGImageEncoder
BUG=skia:5616
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2325223002
Review-Url: https://codereview.chromium.org/2325223002
Diffstat (limited to 'src/images')
-rw-r--r-- | src/images/SkPNGImageEncoder.cpp | 119 | ||||
-rw-r--r-- | src/images/transform_scanline.h | 129 |
2 files changed, 161 insertions, 87 deletions
diff --git a/src/images/SkPNGImageEncoder.cpp b/src/images/SkPNGImageEncoder.cpp index a9c8b3d785..b30cd2509a 100644 --- a/src/images/SkPNGImageEncoder.cpp +++ b/src/images/SkPNGImageEncoder.cpp @@ -58,30 +58,30 @@ static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { } } -static transform_scanline_proc choose_proc(SkColorType ct, bool hasAlpha) { - // we don't care about search on alpha if we're kIndex8, since only the - // colortable packing cares about that distinction, not the pixels - if (kIndex_8_SkColorType == ct) { - hasAlpha = false; // we store false in the table entries for kIndex8 - } - +static transform_scanline_proc choose_proc(SkColorType ct, SkAlphaType alphaType) { static const struct { SkColorType fColorType; - bool fHasAlpha; + SkAlphaType fAlphaType; transform_scanline_proc fProc; } gMap[] = { - { kRGB_565_SkColorType, false, transform_scanline_565 }, - { kN32_SkColorType, false, transform_scanline_888 }, - { kN32_SkColorType, true, transform_scanline_8888 }, - { kARGB_4444_SkColorType, false, transform_scanline_444 }, - { kARGB_4444_SkColorType, true, transform_scanline_4444 }, - { kIndex_8_SkColorType, false, transform_scanline_memcpy }, - { kGray_8_SkColorType, false, transform_scanline_memcpy }, + { kRGB_565_SkColorType, kOpaque_SkAlphaType, transform_scanline_565 }, + { kRGBA_8888_SkColorType, kOpaque_SkAlphaType, transform_scanline_RGBX }, + { kBGRA_8888_SkColorType, kOpaque_SkAlphaType, transform_scanline_BGRX }, + { kRGBA_8888_SkColorType, kPremul_SkAlphaType, transform_scanline_rgbA }, + { kBGRA_8888_SkColorType, kPremul_SkAlphaType, transform_scanline_bgrA }, + { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_memcpy }, + { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_BGRA }, + { kARGB_4444_SkColorType, kOpaque_SkAlphaType, transform_scanline_444 }, + { kARGB_4444_SkColorType, kPremul_SkAlphaType, transform_scanline_4444 }, + { kIndex_8_SkColorType, kOpaque_SkAlphaType, transform_scanline_memcpy }, + { kIndex_8_SkColorType, kPremul_SkAlphaType, transform_scanline_memcpy }, + { kIndex_8_SkColorType, kUnpremul_SkAlphaType, transform_scanline_memcpy }, + { kGray_8_SkColorType, kOpaque_SkAlphaType, transform_scanline_memcpy }, }; - for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) { - if (gMap[i].fColorType == ct && gMap[i].fHasAlpha == hasAlpha) { - return gMap[i].fProc; + for (auto entry : gMap) { + if (entry.fColorType == ct && entry.fAlphaType == alphaType) { + return entry.fProc; } } sk_throw(); @@ -112,12 +112,12 @@ static int computeBitDepth(int colorCount) { */ static inline int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT palette, - png_byte* SK_RESTRICT trans, bool hasAlpha) { + png_byte* SK_RESTRICT trans, SkAlphaType alphaType) { const SkPMColor* SK_RESTRICT colors = ctable ? ctable->readColors() : nullptr; const int ctCount = ctable->count(); int i, num_trans = 0; - if (hasAlpha) { + if (kOpaque_SkAlphaType != alphaType) { /* first see if we have some number of fully opaque at the end of the ctable. PNG allows num_trans < num_palette, but all of the trans entries must come first in the palette. If I was smarter, I'd @@ -134,18 +134,27 @@ static inline int pack_palette(SkColorTable* ctable, num_trans -= 1; } - const SkUnPreMultiply::Scale* SK_RESTRICT table = - SkUnPreMultiply::GetScaleTable(); - - for (i = 0; i < num_trans; i++) { - const SkPMColor c = *colors++; - const unsigned a = SkGetPackedA32(c); - const SkUnPreMultiply::Scale s = table[a]; - trans[i] = a; - palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); - palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); - palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); + if (kPremul_SkAlphaType == alphaType) { + const SkUnPreMultiply::Scale* SK_RESTRICT table = SkUnPreMultiply::GetScaleTable(); + for (i = 0; i < num_trans; i++) { + const SkPMColor c = *colors++; + const unsigned a = SkGetPackedA32(c); + const SkUnPreMultiply::Scale s = table[a]; + trans[i] = a; + palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); + palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); + palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); + } + } else { + for (i = 0; i < num_trans; i++) { + const SkPMColor c = *colors++; + trans[i] = SkGetPackedA32(c); + palette[i].red = SkGetPackedR32(c); + palette[i].green = SkGetPackedG32(c); + palette[i].blue = SkGetPackedB32(c); + } } + // now fall out of this if-block to use common code for the trailing // opaque entries } @@ -165,7 +174,7 @@ protected: bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; private: bool doEncode(SkWStream* stream, const SkBitmap& bm, - const bool& hasAlpha, int colorType, + SkAlphaType alphaType, int colorType, int bitDepth, SkColorType ct, png_color_8& sig_bit); @@ -180,12 +189,12 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, switch (originalBitmap.colorType()) { case kIndex_8_SkColorType: case kGray_8_SkColorType: - case kN32_SkColorType: + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: case kARGB_4444_SkColorType: case kRGB_565_SkColorType: break; default: - // TODO(scroggo): support 8888-but-not-N32 natively. // TODO(scroggo): support Alpha_8 as Grayscale(black)+Alpha if (originalBitmap.copyTo(©, kN32_SkColorType)) { bitmap = © @@ -193,7 +202,22 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, } SkColorType ct = bitmap->colorType(); - const bool hasAlpha = !bitmap->isOpaque(); + const SkAlphaType alphaType = bitmap->alphaType(); + switch (alphaType) { + case kUnpremul_SkAlphaType: + if (kARGB_4444_SkColorType == ct) { + return false; + } + + break; + case kOpaque_SkAlphaType: + case kPremul_SkAlphaType: + break; + default: + return false; + } + + const bool isOpaque = (kOpaque_SkAlphaType == alphaType); int bitDepth = 8; // default for color png_color_8 sig_bit; sk_bzero(&sig_bit, sizeof(png_color_8)); @@ -210,28 +234,29 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, case kGray_8_SkColorType: sig_bit.gray = 8; colorType = PNG_COLOR_TYPE_GRAY; - SkASSERT(!hasAlpha); + SkASSERT(isOpaque); break; - case kN32_SkColorType: + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; sig_bit.alpha = 8; - colorType = hasAlpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB; + colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; break; case kARGB_4444_SkColorType: sig_bit.red = 4; sig_bit.green = 4; sig_bit.blue = 4; sig_bit.alpha = 4; - colorType = hasAlpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB; + colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; break; case kRGB_565_SkColorType: sig_bit.red = 5; sig_bit.green = 6; sig_bit.blue = 5; colorType = PNG_COLOR_TYPE_RGB; - SkASSERT(!hasAlpha); + SkASSERT(isOpaque); break; default: return false; @@ -253,11 +278,11 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, bitDepth = computeBitDepth(ctable->count()); } - return doEncode(stream, *bitmap, hasAlpha, colorType, bitDepth, ct, sig_bit); + return doEncode(stream, *bitmap, alphaType, colorType, bitDepth, ct, sig_bit); } bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, - const bool& hasAlpha, int colorType, + SkAlphaType alphaType, int colorType, int bitDepth, SkColorType ct, png_color_8& sig_bit) { @@ -304,9 +329,9 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, png_color paletteColors[256]; png_byte trans[256]; if (kIndex_8_SkColorType == ct) { - SkColorTable* ct = bitmap.getColorTable(); - int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha); - png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); + SkColorTable* colorTable = bitmap.getColorTable(); + int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType); + png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count()); if (numTrans > 0) { png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); } @@ -318,11 +343,11 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, const char* srcImage = (const char*)bitmap.getPixels(); SkAutoSTMalloc<1024, char> rowStorage(bitmap.width() << 2); char* storage = rowStorage.get(); - transform_scanline_proc proc = choose_proc(ct, hasAlpha); + transform_scanline_proc proc = choose_proc(ct, alphaType); for (int y = 0; y < bitmap.height(); y++) { png_bytep row_ptr = (png_bytep)storage; - proc(srcImage, bitmap.width(), storage); + proc(storage, srcImage, bitmap.width(), SkColorTypeBytesPerPixel(ct)); png_write_rows(png_ptr, &row_ptr, 1); srcImage += bitmap.rowBytes(); } diff --git a/src/images/transform_scanline.h b/src/images/transform_scanline.h index 4baf6b6c6b..a02e98ab07 100644 --- a/src/images/transform_scanline.h +++ b/src/images/transform_scanline.h @@ -19,16 +19,17 @@ * Function template for transforming scanlines. * Transform 'width' pixels from 'src' buffer into 'dst' buffer, * repacking color channel data as appropriate for the given transformation. + * 'bpp' is bytes per pixel in the 'src' buffer. */ -typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src, - int width, char* SK_RESTRICT dst); +typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int bpp); /** * Identity transformation: just copy bytes from src to dst. */ -static void transform_scanline_memcpy(const char* SK_RESTRICT src, int width, - char* SK_RESTRICT dst) { - memcpy(dst, src, width); +static void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int bpp) { + memcpy(dst, src, width * bpp); } /** @@ -36,9 +37,9 @@ static void transform_scanline_memcpy(const char* SK_RESTRICT src, int width, * Alpha channel data is not present in kRGB_565_Config format, so there is no * alpha channel data to preserve. */ -static void transform_scanline_565(const char* SK_RESTRICT src, int width, - char* SK_RESTRICT dst) { - const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src; +static void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int) { + const uint16_t* srcP = (const uint16_t*)src; for (int i = 0; i < width; i++) { unsigned c = *srcP++; *dst++ = SkPacked16ToR32(c); @@ -48,17 +49,32 @@ static void transform_scanline_565(const char* SK_RESTRICT src, int width, } /** - * Transform from kARGB_8888_Config to 3-bytes-per-pixel RGB. - * Alpha channel data, if any, is abandoned. + * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB. + * Alpha channel data is abandoned. + */ +static void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int) { + const uint32_t* srcP = (const SkPMColor*)src; + for (int i = 0; i < width; i++) { + uint32_t c = *srcP++; + *dst++ = (c >> 0) & 0xFF; + *dst++ = (c >> 8) & 0xFF; + *dst++ = (c >> 16) & 0xFF; + } +} + +/** + * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB. + * Alpha channel data is abandoned. */ -static void transform_scanline_888(const char* SK_RESTRICT src, int width, - char* SK_RESTRICT dst) { - const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; +static void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int) { + const uint32_t* srcP = (const SkPMColor*)src; for (int i = 0; i < width; i++) { - SkPMColor c = *srcP++; - *dst++ = SkGetPackedR32(c); - *dst++ = SkGetPackedG32(c); - *dst++ = SkGetPackedB32(c); + uint32_t c = *srcP++; + *dst++ = (c >> 16) & 0xFF; + *dst++ = (c >> 8) & 0xFF; + *dst++ = (c >> 0) & 0xFF; } } @@ -66,9 +82,9 @@ static void transform_scanline_888(const char* SK_RESTRICT src, int width, * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB. * Alpha channel data, if any, is abandoned. */ -static void transform_scanline_444(const char* SK_RESTRICT src, int width, - char* SK_RESTRICT dst) { - const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; +static void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int) { + const SkPMColor16* srcP = (const SkPMColor16*)src; for (int i = 0; i < width; i++) { SkPMColor16 c = *srcP++; *dst++ = SkPacked4444ToR32(c); @@ -77,23 +93,26 @@ static void transform_scanline_444(const char* SK_RESTRICT src, int width, } } -/** - * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA. - * (This would be the identity transformation, except for byte-order and - * scaling of RGB based on alpha channel). - */ -static void transform_scanline_8888(const char* SK_RESTRICT src, int width, - char* SK_RESTRICT dst) { - const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; - const SkUnPreMultiply::Scale* SK_RESTRICT table = - SkUnPreMultiply::GetScaleTable(); +template <bool kIsRGBA> +static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst, + const char* SK_RESTRICT src, int width, int) { + const uint32_t* srcP = (const SkPMColor*)src; + const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); for (int i = 0; i < width; i++) { - SkPMColor c = *srcP++; - unsigned a = SkGetPackedA32(c); - unsigned r = SkGetPackedR32(c); - unsigned g = SkGetPackedG32(c); - unsigned b = SkGetPackedB32(c); + uint32_t c = *srcP++; + unsigned r, g, b, a; + if (kIsRGBA) { + r = (c >> 0) & 0xFF; + g = (c >> 8) & 0xFF; + b = (c >> 16) & 0xFF; + a = (c >> 24) & 0xFF; + } else { + r = (c >> 16) & 0xFF; + g = (c >> 8) & 0xFF; + b = (c >> 0) & 0xFF; + a = (c >> 24) & 0xFF; + } if (0 != a && 255 != a) { SkUnPreMultiply::Scale scale = table[a]; @@ -109,14 +128,44 @@ static void transform_scanline_8888(const char* SK_RESTRICT src, int width, } /** + * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int bpp) { + transform_scanline_unpremultiply<true>(dst, src, width, bpp); +} + +/** + * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int bpp) { + transform_scanline_unpremultiply<false>(dst, src, width, bpp); +} + +/** + * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. + */ +static void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int) { + const uint32_t* srcP = (const SkPMColor*)src; + for (int i = 0; i < width; i++) { + uint32_t c = *srcP++; + *dst++ = (c >> 16) & 0xFF; + *dst++ = (c >> 8) & 0xFF; + *dst++ = (c >> 0) & 0xFF; + *dst++ = (c >> 24) & 0xFF; + } +} + +/** * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA, * with scaling of RGB based on alpha channel. */ -static void transform_scanline_4444(const char* SK_RESTRICT src, int width, - char* SK_RESTRICT dst) { - const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; - const SkUnPreMultiply::Scale* SK_RESTRICT table = - SkUnPreMultiply::GetScaleTable(); +static void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, + int width, int) { + const SkPMColor16* srcP = (const SkPMColor16*)src; + const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); for (int i = 0; i < width; i++) { SkPMColor16 c = *srcP++; |