}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
- // Convert to RGBA if there is a transparency chunk.
png_set_tRNS_to_alpha(png_ptr);
- png_set_gray_to_rgb(png_ptr);
+
+ // We will recommend kN32 here since we do not support kGray
+ // with alpha.
colorType = kN32_SkColorType;
alphaType = kUnpremul_SkAlphaType;
} else {
}
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
- // Convert to RGBA if the image has alpha.
- png_set_gray_to_rgb(png_ptr);
+ // We will recommend kN32 here since we do not support anything
+ // similar to GRAY_ALPHA.
colorType = kN32_SkColorType;
alphaType = kUnpremul_SkAlphaType;
break;
}
png_read_update_info(fPng_ptr, fInfo_ptr);
- // srcColorType was determined in read_header() which determined png color type
- const SkColorType srcColorType = this->getInfo().colorType();
+ // suggestedColorType was determined in read_header() based on the encodedColorType
+ const SkColorType suggestedColorType = this->getInfo().colorType();
- switch (srcColorType) {
+ switch (suggestedColorType) {
case kIndex_8_SkColorType:
//decode palette to Skia format
fSrcConfig = SkSwizzler::kIndex;
case kGray_8_SkColorType:
fSrcConfig = SkSwizzler::kGray;
break;
- case kN32_SkColorType:
- if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
+ case kN32_SkColorType: {
+ const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_ptr);
+ if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType ||
+ PNG_COLOR_TYPE_GRAY == encodedColorType) {
+ // If encodedColorType is GRAY, there must be a transparent chunk.
+ // Otherwise, suggestedColorType would be kGray. We have already
+ // instructed libpng to convert the transparent chunk to alpha,
+ // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha.
+ SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA ||
+ png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS));
+
+ fSrcConfig = SkSwizzler::kGrayAlpha;
+ } else {
+ if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
fSrcConfig = SkSwizzler::kRGB;
} else {
fSrcConfig = SkSwizzler::kRGBA;
+ }
}
break;
+ }
default:
// We will always recommend one of the above colorTypes.
SkASSERT(false);
}
}
+// kGrayAlpha
+
+static void swizzle_grayalpha_to_n32_unpremul(
+ void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset,
+ const SkPMColor ctable[]) {
+
+ src += offset;
+ SkPMColor* dst32 = (SkPMColor*) dst;
+ for (int x = 0; x < width; x++) {
+ dst32[x] = SkPackARGB32NoCheck(src[1], src[0], src[0], src[0]);
+ src += deltaSrc;
+ }
+}
+
+static void swizzle_grayalpha_to_n32_premul(
+ void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset,
+ const SkPMColor ctable[]) {
+
+ src += offset;
+ SkPMColor* dst32 = (SkPMColor*) dst;
+ for (int x = 0; x < width; x++) {
+ uint8_t pmgray = SkMulDiv255Round(src[1], src[0]);
+ dst32[x] = SkPackARGB32NoCheck(src[1], pmgray, pmgray, pmgray);
+ src += deltaSrc;
+ }
+}
+
// kBGRX
static void swizzle_bgrx_to_n32(
}
template <SkSwizzler::RowProc proc>
+void SkSwizzler::SkipLeadingGrayAlphaZerosThen(
+ void* dst, const uint8_t* src, int width,
+ int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) {
+ SkASSERT(!ctable);
+
+ const uint16_t* src16 = (const uint16_t*) (src + offset);
+ uint32_t* dst32 = (uint32_t*) dst;
+
+ // This may miss opportunities to skip when the output is premultiplied,
+ // e.g. for a src pixel 0x00FF which is not zero but becomes zero after premultiplication.
+ while (width > 0 && *src16 == 0x0000) {
+ width--;
+ dst32++;
+ src16 += deltaSrc / 2;
+ }
+ proc(dst32, (const uint8_t*)src16, width, bpp, deltaSrc, 0, ctable);
+}
+
+template <SkSwizzler::RowProc proc>
void SkSwizzler::SkipLeading8888ZerosThen(
void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth,
int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) {
break;
}
break;
+ case kGrayAlpha:
+ switch (dstInfo.colorType()) {
+ case kN32_SkColorType:
+ if (dstInfo.alphaType() == kUnpremul_SkAlphaType) {
+ if (SkCodec::kYes_ZeroInitialized == zeroInit) {
+ proc = &SkipLeadingGrayAlphaZerosThen
+ <swizzle_grayalpha_to_n32_unpremul>;
+ } else {
+ proc = &swizzle_grayalpha_to_n32_unpremul;
+ }
+ } else {
+ if (SkCodec::kYes_ZeroInitialized == zeroInit) {
+ proc = &SkipLeadingGrayAlphaZerosThen<swizzle_grayalpha_to_n32_premul>;
+ } else {
+ proc = &swizzle_grayalpha_to_n32_premul;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
case kBGR:
case kBGRX:
switch (dstInfo.colorType()) {
kUnknown, // Invalid type.
kBit, // A single bit to distinguish between white and black.
kGray,
+ kGrayAlpha,
kIndex1,
kIndex2,
kIndex4,
case kIndex:
case kNoOp8:
return 8;
+ case kGrayAlpha:
case kNoOp16:
return 16;
case kRGB:
int dstWidth, int bpp, int deltaSrc, int offset,
const SkPMColor ctable[]);
+ template <RowProc Proc>
+ static void SkipLeadingGrayAlphaZerosThen(void* dst, const uint8_t* src, int width, int bpp,
+ int deltaSrc, int offset, const SkPMColor ctable[]);
+
// May be NULL. We have not implemented optimized functions for all supported transforms.
const RowProc fFastProc;
// Always non-NULL. Supports sampling.