aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/images
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-09-12 14:30:03 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-09-12 14:30:03 -0700
commitf17b71f6c9b94e93f88e103b3b6cab61cbee76d7 (patch)
tree8195f4651324af98584cd76a6faad60f047741c6 /src/images
parentea5de1ff1dcdbfbf3e4314dc151dd1a03023cbb1 (diff)
Support RGBA/BGRA Premul/Unpremul from SkPNGImageEncoder
Diffstat (limited to 'src/images')
-rw-r--r--src/images/SkPNGImageEncoder.cpp119
-rw-r--r--src/images/transform_scanline.h129
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(&copy, kN32_SkColorType)) {
bitmap = &copy;
@@ -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++;