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
This commit is contained in:
parent
ea5de1ff1d
commit
f17b71f6c9
@ -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();
|
||||
}
|
||||
|
@ -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_888(const char* SK_RESTRICT src, int width,
|
||||
char* SK_RESTRICT dst) {
|
||||
const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
|
||||
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++) {
|
||||
SkPMColor c = *srcP++;
|
||||
*dst++ = SkGetPackedR32(c);
|
||||
*dst++ = SkGetPackedG32(c);
|
||||
*dst++ = SkGetPackedB32(c);
|
||||
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_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++) {
|
||||
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];
|
||||
@ -108,15 +127,45 @@ 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++;
|
||||
|
@ -1073,22 +1073,53 @@ DEF_TEST(Codec_ColorXform, r) {
|
||||
check_color_xform(r, "mandrill_512.png");
|
||||
}
|
||||
|
||||
static void check_round_trip(skiatest::Reporter* r, const SkBitmap& bm1) {
|
||||
SkColorType origColorType = bm1.colorType();
|
||||
SkAlphaType origAlphaType = bm1.alphaType();
|
||||
static bool color_type_match(SkColorType origColorType, SkColorType codecColorType) {
|
||||
switch (origColorType) {
|
||||
case kRGBA_8888_SkColorType:
|
||||
case kBGRA_8888_SkColorType:
|
||||
return kRGBA_8888_SkColorType == codecColorType ||
|
||||
kBGRA_8888_SkColorType == codecColorType;
|
||||
default:
|
||||
return origColorType == codecColorType;
|
||||
}
|
||||
}
|
||||
|
||||
static bool alpha_type_match(SkAlphaType origAlphaType, SkAlphaType codecAlphaType) {
|
||||
switch (origAlphaType) {
|
||||
case kUnpremul_SkAlphaType:
|
||||
case kPremul_SkAlphaType:
|
||||
return kUnpremul_SkAlphaType == codecAlphaType ||
|
||||
kPremul_SkAlphaType == codecAlphaType;
|
||||
default:
|
||||
return origAlphaType == codecAlphaType;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_round_trip(skiatest::Reporter* r, SkCodec* origCodec, const SkImageInfo& info) {
|
||||
SkBitmap bm1;
|
||||
SkPMColor colors[256];
|
||||
SkAutoTUnref<SkColorTable> colorTable1(new SkColorTable(colors, 256));
|
||||
bm1.allocPixels(info, nullptr, colorTable1.get());
|
||||
int numColors;
|
||||
SkCodec::Result result = origCodec->getPixels(info, bm1.getPixels(), bm1.rowBytes(), nullptr,
|
||||
const_cast<SkPMColor*>(colorTable1->readColors()),
|
||||
&numColors);
|
||||
// This will fail to update colorTable1->count() but is fine for the purpose of this test.
|
||||
REPORTER_ASSERT(r, SkCodec::kSuccess == result);
|
||||
|
||||
// Encode the image to png.
|
||||
sk_sp<SkData> data =
|
||||
sk_sp<SkData>(SkImageEncoder::EncodeData(bm1, SkImageEncoder::kPNG_Type, 100));
|
||||
|
||||
// Prepare to decode. The codec should recognize that the PNG is 565.
|
||||
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data));
|
||||
REPORTER_ASSERT(r, origColorType == codec->getInfo().colorType());
|
||||
REPORTER_ASSERT(r, origAlphaType == codec->getInfo().alphaType());
|
||||
REPORTER_ASSERT(r, color_type_match(info.colorType(), codec->getInfo().colorType()));
|
||||
REPORTER_ASSERT(r, alpha_type_match(info.alphaType(), codec->getInfo().alphaType()));
|
||||
|
||||
SkBitmap bm2;
|
||||
bm2.allocPixels(codec->getInfo());
|
||||
SkCodec::Result result = codec->getPixels(codec->getInfo(), bm2.getPixels(), bm2.rowBytes());
|
||||
SkAutoTUnref<SkColorTable> colorTable2(new SkColorTable(colors, 256));
|
||||
bm2.allocPixels(info, nullptr, colorTable2.get());
|
||||
result = codec->getPixels(info, bm2.getPixels(), bm2.rowBytes(), nullptr,
|
||||
const_cast<SkPMColor*>(colorTable2->readColors()), &numColors);
|
||||
REPORTER_ASSERT(r, SkCodec::kSuccess == result);
|
||||
|
||||
SkMD5::Digest d1, d2;
|
||||
@ -1098,26 +1129,52 @@ static void check_round_trip(skiatest::Reporter* r, const SkBitmap& bm1) {
|
||||
}
|
||||
|
||||
DEF_TEST(Codec_PngRoundTrip, r) {
|
||||
// Create an arbitrary 565 bitmap.
|
||||
const char* path = "mandrill_512_q075.jpg";
|
||||
SkAutoTDelete<SkStream> stream(resource(path));
|
||||
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
|
||||
SkImageInfo info565 = codec->getInfo().makeColorType(kRGB_565_SkColorType);
|
||||
SkBitmap bm1;
|
||||
bm1.allocPixels(info565);
|
||||
SkCodec::Result result = codec->getPixels(info565, bm1.getPixels(), bm1.rowBytes());
|
||||
REPORTER_ASSERT(r, SkCodec::kSuccess == result);
|
||||
check_round_trip(r, bm1);
|
||||
|
||||
// Create an arbitrary gray bitmap.
|
||||
SkColorType colorTypesOpaque[] = {
|
||||
kRGB_565_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
|
||||
};
|
||||
for (SkColorType colorType : colorTypesOpaque) {
|
||||
SkImageInfo newInfo = codec->getInfo().makeColorType(colorType);
|
||||
check_round_trip(r, codec.get(), newInfo);
|
||||
}
|
||||
|
||||
path = "grayscale.jpg";
|
||||
stream.reset(resource(path));
|
||||
codec.reset(SkCodec::NewFromStream(stream.release()));
|
||||
SkBitmap bm2;
|
||||
bm2.allocPixels(codec->getInfo());
|
||||
result = codec->getPixels(codec->getInfo(), bm2.getPixels(), bm2.rowBytes());
|
||||
REPORTER_ASSERT(r, SkCodec::kSuccess == result);
|
||||
check_round_trip(r, bm2);
|
||||
check_round_trip(r, codec.get(), codec->getInfo());
|
||||
|
||||
path = "yellow_rose.png";
|
||||
stream.reset(resource(path));
|
||||
codec.reset(SkCodec::NewFromStream(stream.release()));
|
||||
|
||||
SkColorType colorTypesWithAlpha[] = {
|
||||
kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
|
||||
};
|
||||
SkAlphaType alphaTypes[] = {
|
||||
kUnpremul_SkAlphaType, kPremul_SkAlphaType
|
||||
};
|
||||
for (SkColorType colorType : colorTypesWithAlpha) {
|
||||
for (SkAlphaType alphaType : alphaTypes) {
|
||||
// Set color space to nullptr because color correct premultiplies do not round trip.
|
||||
SkImageInfo newInfo = codec->getInfo().makeColorType(colorType)
|
||||
.makeAlphaType(alphaType)
|
||||
.makeColorSpace(nullptr);
|
||||
check_round_trip(r, codec.get(), newInfo);
|
||||
}
|
||||
}
|
||||
|
||||
path = "index8.png";
|
||||
stream.reset(resource(path));
|
||||
codec.reset(SkCodec::NewFromStream(stream.release()));
|
||||
|
||||
for (SkAlphaType alphaType : alphaTypes) {
|
||||
SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType)
|
||||
.makeColorSpace(nullptr);
|
||||
check_round_trip(r, codec.get(), newInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_conversion_possible(skiatest::Reporter* r, const char* path,
|
||||
|
Loading…
Reference in New Issue
Block a user