diff options
Diffstat (limited to 'src/codec')
-rw-r--r-- | src/codec/SkPngCodec.cpp | 28 | ||||
-rw-r--r-- | src/codec/SkSwizzler.cpp | 138 |
2 files changed, 155 insertions, 11 deletions
diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index b8576fbc6c..56995801fc 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -874,17 +874,17 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec // FIXME (scroggo): Once SK_GOOGLE3_PNG_HACK is no more, this method can be inline in // AutoCleanPng::infoCallback static void general_info_callback(png_structp png_ptr, png_infop info_ptr, - SkEncodedInfo::Color* outColor, SkEncodedInfo::Alpha* outAlpha) { + SkEncodedInfo::Color* outColor, SkEncodedInfo::Alpha* outAlpha, + int* outBitDepth) { png_uint_32 origWidth, origHeight; int bitDepth, encodedColorType; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, &encodedColorType, nullptr, nullptr, nullptr); - // Tell libpng to strip 16 bit/color files down to 8 bits/color. - // TODO: Should we handle this in SkSwizzler? Could this also benefit - // RAW decodes? - if (bitDepth == 16) { - SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType); + // TODO: Should we support 16-bits of precision for gray images? + if (bitDepth == 16 && (PNG_COLOR_TYPE_GRAY == encodedColorType || + PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType)) { + bitDepth = 8; png_set_strip_16(png_ptr); } @@ -899,6 +899,7 @@ static void general_info_callback(png_structp png_ptr, png_infop info_ptr, // byte into separate bytes (useful for paletted and grayscale images). if (bitDepth < 8) { // TODO: Should we use SkSwizzler here? + bitDepth = 8; png_set_packing(png_ptr); } @@ -922,6 +923,7 @@ static void general_info_callback(png_structp png_ptr, png_infop info_ptr, // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. if (bitDepth < 8) { // TODO: Should we use SkSwizzler here? + bitDepth = 8; png_set_expand_gray_1_2_4_to_8(png_ptr); } @@ -954,11 +956,14 @@ static void general_info_callback(png_structp png_ptr, png_infop info_ptr, if (outAlpha) { *outAlpha = alpha; } + if (outBitDepth) { + *outBitDepth = bitDepth; + } } #ifdef SK_GOOGLE3_PNG_HACK void SkPngCodec::rereadInfoCallback() { - general_info_callback(fPng_ptr, fInfo_ptr, nullptr, nullptr); + general_info_callback(fPng_ptr, fInfo_ptr, nullptr, nullptr, nullptr); png_set_interlace_handling(fPng_ptr); png_read_update_info(fPng_ptr, fInfo_ptr); } @@ -967,7 +972,8 @@ void SkPngCodec::rereadInfoCallback() { void AutoCleanPng::infoCallback() { SkEncodedInfo::Color color; SkEncodedInfo::Alpha alpha; - general_info_callback(fPng_ptr, fInfo_ptr, &color, &alpha); + int bitDepth; + general_info_callback(fPng_ptr, fInfo_ptr, &color, &alpha, &bitDepth); const int numberPasses = png_set_interlace_handling(fPng_ptr); @@ -990,7 +996,7 @@ void AutoCleanPng::infoCallback() { colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); } - SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, 8); + SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, bitDepth); // FIXME (scroggo): Once we get rid of SK_GOOGLE3_PNG_HACK, general_info_callback can // be inlined, so these values will already be set. png_uint_32 origWidth = png_get_image_width(fPng_ptr, fInfo_ptr); @@ -1072,9 +1078,9 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt return false; } - // If the image is RGBA and we have a color xform, we can skip the swizzler. + // If the image is 32-bit RGBA and we have a color xform, we can skip the swizzler. if (this->colorXform() && SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().color() && - !options.fSubset) + 8 == this->getEncodedInfo().bitsPerComponent() && !options.fSubset) { fXformMode = kColorOnly_XformMode; return true; diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp index 9cada7b39d..415f0f1ddc 100644 --- a/src/codec/SkSwizzler.cpp +++ b/src/codec/SkSwizzler.cpp @@ -524,6 +524,113 @@ static void fast_swizzle_rgba_to_bgra_unpremul( SkOpts::RGBA_to_BGRA((uint32_t*) dst, src + offset, width); } +// 16-bits per component kRGB and kRGBA + +static void swizzle_rgb16_to_rgba( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return 0xFF000000 | (ptr[4] << 16) | (ptr[2] << 8) | ptr[0]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgb16_to_bgra( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return 0xFF000000 | (ptr[0] << 16) | (ptr[2] << 8) | ptr[4]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgb16_to_565( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to565 = [](const uint8_t* ptr) { + return SkPack888ToRGB16(ptr[0], ptr[2], ptr[4]); + }; + + src += offset; + uint16_t* dst16 = (uint16_t*) dst; + for (int x = 0; x < width; x++) { + dst16[x] = strip16to565(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_rgba_unpremul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return (ptr[6] << 24) | (ptr[4] << 16) | (ptr[2] << 8) | ptr[0]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_rgba_premul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto stripAndPremul16to8 = [](const uint8_t* ptr) { + return premultiply_argb_as_rgba(ptr[6], ptr[0], ptr[2], ptr[4]); + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = stripAndPremul16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_bgra_unpremul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto strip16to8 = [](const uint8_t* ptr) { + return (ptr[6] << 24) | (ptr[0] << 16) | (ptr[2] << 8) | ptr[4]; + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = strip16to8(src); + src += deltaSrc; + } +} + +static void swizzle_rgba16_to_bgra_premul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + auto stripAndPremul16to8 = [](const uint8_t* ptr) { + return premultiply_argb_as_bgra(ptr[6], ptr[0], ptr[2], ptr[4]); + }; + + src += offset; + uint32_t* dst32 = (uint32_t*) dst; + for (int x = 0; x < width; x++) { + dst32[x] = stripAndPremul16to8(src); + src += deltaSrc; + } +} + // kCMYK // // CMYK is stored as four bytes per pixel. @@ -839,14 +946,31 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, case SkEncodedInfo::kRGB_Color: switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = &swizzle_rgb16_to_rgba; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); proc = &swizzle_rgb_to_rgba; fastProc = &fast_swizzle_rgb_to_rgba; break; case kBGRA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = &swizzle_rgb16_to_bgra; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); proc = &swizzle_rgb_to_bgra; fastProc = &fast_swizzle_rgb_to_bgra; break; case kRGB_565_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = &swizzle_rgb16_to_565; + break; + } + proc = &swizzle_rgb_to_565; break; default: @@ -856,6 +980,13 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, case SkEncodedInfo::kRGBA_Color: switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = premultiply ? &swizzle_rgba16_to_rgba_premul : + &swizzle_rgba16_to_rgba_unpremul; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); if (premultiply) { if (SkCodec::kYes_ZeroInitialized == zeroInit) { proc = &SkipLeading8888ZerosThen<swizzle_rgba_to_rgba_premul>; @@ -876,6 +1007,13 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, } break; case kBGRA_8888_SkColorType: + if (16 == encodedInfo.bitsPerComponent()) { + proc = premultiply ? &swizzle_rgba16_to_bgra_premul : + &swizzle_rgba16_to_bgra_unpremul; + break; + } + + SkASSERT(8 == encodedInfo.bitsPerComponent()); if (premultiply) { if (SkCodec::kYes_ZeroInitialized == zeroInit) { proc = &SkipLeading8888ZerosThen<swizzle_rgba_to_bgra_premul>; |