diff options
Diffstat (limited to 'src/codec')
28 files changed, 284 insertions, 96 deletions
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index 3142f1e271..c21a863419 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -622,19 +622,19 @@ int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const { } SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) { + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { if (!conversion_possible(dstInfo, this->getInfo()) || !this->initializeColorXform(dstInfo, options.fPremulBehavior)) { return kInvalidConversion; } - return this->onPrepareToDecode(dstInfo, options); + return this->onPrepareToDecode(dstInfo, options, inputColorPtr, inputColorCount); } SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) { - return prepareToDecode(dstInfo, options); + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { + return prepareToDecode(dstInfo, options, inputColorPtr, inputColorCount); } int SkBmpCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h index cf1460582d..e956a9fc40 100644 --- a/src/codec/SkBmpCodec.h +++ b/src/codec/SkBmpCodec.h @@ -91,11 +91,20 @@ protected: * @param dstInfo Contains output information. Height specifies * the total number of rows that will be decoded. * @param options Additonal options to pass to the decoder. + * @param inputColorPtr Client-provided memory for a color table. Must + * be enough for 256 colors. This will be + * populated with colors if the encoded image uses + * a color table. + * @param inputColorCount If the encoded image uses a color table, this + * will be set to the number of colors in the + * color table. */ virtual SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) = 0; + const SkCodec::Options& options, SkPMColor inputColorPtr[], + int* inputColorCount) = 0; SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options); + const SkCodec::Options& options, SkPMColor inputColorPtr[], + int* inputColorCount); uint32_t* xformBuffer() const { return fXformBuffer.get(); } void resetXformBuffer(int count) { fXformBuffer.reset(new uint32_t[count]); } @@ -135,8 +144,8 @@ private: virtual bool skipRows(int count); - Result onStartScanlineDecode(const SkImageInfo& dstInfo, - const SkCodec::Options&) override; + Result onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options&, + SkPMColor inputColorPtr[], int* inputColorCount) override; int onGetScanlines(void* dst, int count, size_t rowBytes) override; diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp index 51060e5e99..1fc98a2909 100644 --- a/src/codec/SkBmpMaskCodec.cpp +++ b/src/codec/SkBmpMaskCodec.cpp @@ -26,6 +26,8 @@ SkBmpMaskCodec::SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts, + SkPMColor* inputColorPtr, + int* inputColorCount, int* rowsDecoded) { if (opts.fSubset) { // Subsets are not supported. @@ -36,7 +38,7 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, return kInvalidScale; } - Result result = this->prepareToDecode(dstInfo, opts); + Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { return result; } @@ -50,7 +52,7 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, } SkCodec::Result SkBmpMaskCodec::onPrepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) { + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { if (this->colorXform()) { this->resetXformBuffer(dstInfo.width()); } diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h index 8d8d64c168..2f8c060c7a 100644 --- a/src/codec/SkBmpMaskCodec.h +++ b/src/codec/SkBmpMaskCodec.h @@ -38,11 +38,12 @@ public: protected: Result onGetPixels(const SkImageInfo& dstInfo, void* dst, - size_t dstRowBytes, const Options&, - int*) override; + size_t dstRowBytes, const Options&, SkPMColor*, + int*, int*) override; SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) override; + const SkCodec::Options& options, SkPMColor inputColorPtr[], + int* inputColorCount) override; private: diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp index 0fcd290add..c6d788b800 100644 --- a/src/codec/SkBmpRLECodec.cpp +++ b/src/codec/SkBmpRLECodec.cpp @@ -34,13 +34,15 @@ SkBmpRLECodec::SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, S SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts, + SkPMColor* inputColorPtr, + int* inputColorCount, int* rowsDecoded) { if (opts.fSubset) { // Subsets are not supported. return kUnimplemented; } - Result result = this->prepareToDecode(dstInfo, opts); + Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { return result; } @@ -61,13 +63,19 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, /* * Process the color table for the bmp input */ - bool SkBmpRLECodec::createColorTable(SkColorType dstColorType) { + bool SkBmpRLECodec::createColorTable(SkColorType dstColorType, int* numColors) { // Allocate memory for color table uint32_t colorBytes = 0; SkPMColor colorTable[256]; if (this->bitsPerPixel() <= 8) { // Inform the caller of the number of colors uint32_t maxColors = 1 << this->bitsPerPixel(); + if (nullptr != numColors) { + // We set the number of colors to maxColors in order to ensure + // safe memory accesses. Otherwise, an invalid pixel could + // access memory outside of our color table array. + *numColors = maxColors; + } // Don't bother reading more than maxColors. const uint32_t numColorsToRead = fNumColors == 0 ? maxColors : SkTMin(fNumColors, maxColors); @@ -233,7 +241,7 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, } SkCodec::Result SkBmpRLECodec::onPrepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) { + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { // FIXME: Support subsets for scanline decodes. if (options.fSubset) { // Subsets are not supported. @@ -248,17 +256,20 @@ SkCodec::Result SkBmpRLECodec::onPrepareToDecode(const SkImageInfo& dstInfo, SkColorType colorTableColorType = dstInfo.colorType(); if (this->colorXform()) { // Just set a known colorType for the colorTable. No need to actually transform - // the colors in the colorTable. + // the colors in the colorTable since we do not allow decoding RLE to kIndex8. colorTableColorType = kBGRA_8888_SkColorType; } // Create the color table if necessary and prepare the stream for decode // Note that if it is non-NULL, inputColorCount will be modified - if (!this->createColorTable(colorTableColorType)) { + if (!this->createColorTable(colorTableColorType, inputColorCount)) { SkCodecPrintf("Error: could not create color table.\n"); return SkCodec::kInvalidInput; } + // Copy the color table to the client if necessary + copy_color_table(dstInfo, fColorTable.get(), inputColorPtr, inputColorCount); + // Initialize a buffer for encoded RLE data if (!this->initializeStreamBuffer()) { SkCodecPrintf("Error: cannot initialize stream buffer.\n"); diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h index d6c17c3c68..030e82731f 100644 --- a/src/codec/SkBmpRLECodec.h +++ b/src/codec/SkBmpRLECodec.h @@ -44,11 +44,12 @@ public: protected: Result onGetPixels(const SkImageInfo& dstInfo, void* dst, - size_t dstRowBytes, const Options&, - int*) override; + size_t dstRowBytes, const Options&, SkPMColor*, + int*, int*) override; SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) override; + const SkCodec::Options& options, SkPMColor inputColorPtr[], + int* inputColorCount) override; private: @@ -56,7 +57,7 @@ private: * Creates the color table * Sets colorCount to the new color count if it is non-nullptr */ - bool createColorTable(SkColorType dstColorType); + bool createColorTable(SkColorType dstColorType, int* colorCount); bool initializeStreamBuffer(); diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp index 46a5715dc9..959e75ba5b 100644 --- a/src/codec/SkBmpStandardCodec.cpp +++ b/src/codec/SkBmpStandardCodec.cpp @@ -36,6 +36,8 @@ SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInf SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts, + SkPMColor* inputColorPtr, + int* inputColorCount, int* rowsDecoded) { if (opts.fSubset) { // Subsets are not supported. @@ -46,7 +48,7 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, return kInvalidScale; } - Result result = this->prepareToDecode(dstInfo, opts); + Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { return result; } @@ -61,13 +63,20 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, /* * Process the color table for the bmp input */ - bool SkBmpStandardCodec::createColorTable(SkColorType dstColorType, SkAlphaType dstAlphaType) { + bool SkBmpStandardCodec::createColorTable(SkColorType dstColorType, SkAlphaType dstAlphaType, + int* numColors) { // Allocate memory for color table uint32_t colorBytes = 0; SkPMColor colorTable[256]; if (this->bitsPerPixel() <= 8) { // Inform the caller of the number of colors uint32_t maxColors = 1 << this->bitsPerPixel(); + if (nullptr != numColors) { + // We set the number of colors to maxColors in order to ensure + // safe memory accesses. Otherwise, an invalid pixel could + // access memory outside of our color table array. + *numColors = maxColors; + } // Don't bother reading more than maxColors. const uint32_t numColorsToRead = fNumColors == 0 ? maxColors : SkTMin(fNumColors, maxColors); @@ -182,18 +191,21 @@ void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Op } SkCodec::Result SkBmpStandardCodec::onPrepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) { + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { if (this->xformOnDecode()) { this->resetXformBuffer(dstInfo.width()); } // Create the color table if necessary and prepare the stream for decode // Note that if it is non-NULL, inputColorCount will be modified - if (!this->createColorTable(dstInfo.colorType(), dstInfo.alphaType())) { + if (!this->createColorTable(dstInfo.colorType(), dstInfo.alphaType(), inputColorCount)) { SkCodecPrintf("Error: could not create color table.\n"); return SkCodec::kInvalidInput; } + // Copy the color table to the client if necessary + copy_color_table(dstInfo, fColorTable.get(), inputColorPtr, inputColorCount); + // Initialize a swizzler this->initializeSwizzler(dstInfo, options); return SkCodec::kSuccess; @@ -279,8 +291,9 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes) { - // BMP in ICO have transparency, so this cannot be 565. The below code depends - // on the output being an SkPMColor. + // BMP in ICO have transparency, so this cannot be 565, and this mask + // prevents us from using kIndex8. The below code depends on the output + // being an SkPMColor. SkASSERT(kRGBA_8888_SkColorType == dstInfo.colorType() || kBGRA_8888_SkColorType == dstInfo.colorType() || kRGBA_F16_SkColorType == dstInfo.colorType()); diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h index f9ce5c6839..ec3d707ab8 100644 --- a/src/codec/SkBmpStandardCodec.h +++ b/src/codec/SkBmpStandardCodec.h @@ -47,15 +47,16 @@ public: protected: Result onGetPixels(const SkImageInfo& dstInfo, void* dst, - size_t dstRowBytes, const Options&, - int*) override; + size_t dstRowBytes, const Options&, SkPMColor*, + int*, int*) override; bool onInIco() const override { return fInIco; } SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) override; + const SkCodec::Options& options, SkPMColor inputColorPtr[], + int* inputColorCount) override; uint64_t onGetFillValue(const SkImageInfo&) const override; @@ -69,8 +70,9 @@ private: /* * Creates the color table + * Sets colorCount to the new color count if it is non-nullptr */ - bool createColorTable(SkColorType colorType, SkAlphaType alphaType); + bool createColorTable(SkColorType colorType, SkAlphaType alphaType, int* colorCount); void initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts); diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 4bd3917880..26b31ae11f 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -167,6 +167,19 @@ bool SkCodec::rewindIfNeeded() { return this->onRewind(); } +#define CHECK_COLOR_TABLE \ + if (kIndex_8_SkColorType == info.colorType()) { \ + if (nullptr == ctable || nullptr == ctableCount) { \ + return SkCodec::kInvalidParameters; \ + } \ + } else { \ + if (ctableCount) { \ + *ctableCount = 0; \ + } \ + ctableCount = nullptr; \ + ctable = nullptr; \ + } + static void zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, SkIRect frameRect) { if (!frameRect.intersect(dstInfo.bounds())) { @@ -192,6 +205,11 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, return kInvalidParameters; } + // index 8 is not supported beyond the first frame. + if (index < 0 || info.colorType() == kIndex_8_SkColorType) { + return kInvalidParameters; + } + if (index >= this->onGetFrameCount()) { return kIncompleteInput; } @@ -234,7 +252,8 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, Options prevFrameOptions(options); prevFrameOptions.fFrameIndex = requiredFrame; prevFrameOptions.fZeroInitialized = kNo_ZeroInitialized; - const Result result = this->getPixels(info, pixels, rowBytes, &prevFrameOptions); + const Result result = this->getPixels(info, pixels, rowBytes, &prevFrameOptions, + nullptr, nullptr); if (result == kSuccess) { const auto* prevFrame = frameHolder->getFrame(requiredFrame); const auto disposalMethod = prevFrame->getDisposalMethod(); @@ -247,7 +266,7 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, } SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, - const Options* options) { + const Options* options, SkPMColor ctable[], int* ctableCount) { if (kUnknown_SkColorType == info.colorType()) { return kInvalidConversion; } @@ -258,6 +277,8 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t return kInvalidParameters; } + CHECK_COLOR_TABLE; + if (!this->rewindIfNeeded()) { return kCouldNotRewind; } @@ -293,7 +314,14 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t // On an incomplete decode, the subclass will specify the number of scanlines that it decoded // successfully. int rowsDecoded = 0; - const Result result = this->onGetPixels(info, pixels, rowBytes, *options, &rowsDecoded); + const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ctable, ctableCount, + &rowsDecoded); + + if (ctableCount) { + if (kIncompleteInput == result || kSuccess == result || kErrorInInput == result) { + SkASSERT(*ctableCount >= 0 && *ctableCount <= 256); + } + } // A return value of kIncompleteInput indicates a truncated image stream. // In this case, we will fill any uninitialized memory with a default value. @@ -314,8 +342,12 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t return result; } +SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { + return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); +} + SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* pixels, - size_t rowBytes, const SkCodec::Options* options) { + size_t rowBytes, const SkCodec::Options* options, SkPMColor* ctable, int* ctableCount) { fStartedIncrementalDecode = false; if (kUnknown_SkColorType == info.colorType()) { @@ -325,6 +357,9 @@ SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* p return kInvalidParameters; } + // Ensure that valid color ptrs are passed in for kIndex8 color type + CHECK_COLOR_TABLE; + // FIXME: If the rows come after the rows of a previous incremental decode, // we might be able to skip the rewind, but only the implementation knows // that. (e.g. PNG will always need to rewind, since we called longjmp, but @@ -364,7 +399,8 @@ SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* p fDstInfo = info; fOptions = *options; - const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, fOptions); + const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, + fOptions, ctable, ctableCount); if (kSuccess == result) { fStartedIncrementalDecode = true; } else if (kUnimplemented == result) { @@ -382,9 +418,11 @@ SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* p SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, - const SkCodec::Options* options) { + const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { // Reset fCurrScanline in case of failure. fCurrScanline = -1; + // Ensure that valid color ptrs are passed in for kIndex8 color type + CHECK_COLOR_TABLE; if (!this->rewindIfNeeded()) { return kCouldNotRewind; @@ -412,7 +450,7 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, return kInvalidScale; } - const Result result = this->onStartScanlineDecode(info, *options); + const Result result = this->onStartScanlineDecode(info, *options, ctable, ctableCount); if (result != SkCodec::kSuccess) { return result; } @@ -423,6 +461,12 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, return kSuccess; } +#undef CHECK_COLOR_TABLE + +SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info) { + return this->startScanlineDecode(info, nullptr, nullptr, nullptr); +} + int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { if (fCurrScanline < 0) { return 0; @@ -486,7 +530,7 @@ uint64_t SkCodec::onGetFillValue(const SkImageInfo& dstInfo) const { return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ? opaqueColor : transparentColor; } default: { - // This not only handles the kN32 case, but also k565, kGray8, since + // This not only handles the kN32 case, but also k565, kGray8, kIndex8, since // the low bits are zeros. return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ? SK_ColorBLACK : SK_ColorTRANSPARENT; @@ -539,6 +583,7 @@ static inline SkColorSpaceXform::ColorFormat select_xform_format_ct(SkColorType case kBGRA_8888_SkColorType: return SkColorSpaceXform::kBGRA_8888_ColorFormat; case kRGB_565_SkColorType: + case kIndex_8_SkColorType: #ifdef SK_PMCOLOR_IS_RGBA return SkColorSpaceXform::kRGBA_8888_ColorFormat; #else diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp index 57f7fb865e..20d547ad36 100644 --- a/src/codec/SkCodecImageGenerator.cpp +++ b/src/codec/SkCodecImageGenerator.cpp @@ -44,7 +44,8 @@ bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, s const Options& opts) { SkCodec::Options codecOpts; codecOpts.fPremulBehavior = opts.fBehavior; - SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, &codecOpts); + SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, &codecOpts, nullptr, + nullptr); switch (result) { case SkCodec::kSuccess: case SkCodec::kIncompleteInput: diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h index cb7cd94979..b69e48808e 100644 --- a/src/codec/SkCodecPriv.h +++ b/src/codec/SkCodecPriv.h @@ -128,6 +128,8 @@ static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAl return colorPtr[fillIndex]; case kRGB_565_SkColorType: return SkPixel32ToPixel16(colorPtr[fillIndex]); + case kIndex_8_SkColorType: + return fillIndex; case kRGBA_F16_SkColorType: { SkASSERT(colorXform); uint64_t dstColor; @@ -146,6 +148,20 @@ static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAl } /* + * + * Copy the codec color table back to the client when kIndex8 color type is requested + */ +static inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable, + SkPMColor* inputColorPtr, int* inputColorCount) { + if (kIndex_8_SkColorType == dstInfo.colorType()) { + SkASSERT(nullptr != inputColorPtr); + SkASSERT(nullptr != inputColorCount); + SkASSERT(nullptr != colorTable); + memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor)); + } +} + +/* * Compute row bytes for an image using pixels per byte */ static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) { @@ -315,6 +331,7 @@ static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaTy * Color Type Conversions * - Always support kRGBA_8888, kBGRA_8888 * - Support kRGBA_F16 when there is a linear dst color space + * - Support kIndex8 if it matches the src * - Support k565 if kOpaque and color correction is not required * - Support k565 if it matches the src, kOpaque, and color correction is not required */ @@ -331,6 +348,8 @@ static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo return true; case kRGBA_F16_SkColorType: return dst.colorSpace() && dst.colorSpace()->gammaIsLinear(); + case kIndex_8_SkColorType: + return kIndex_8_SkColorType == src.colorType(); case kRGB_565_SkColorType: return kOpaque_SkAlphaType == src.alphaType(); case kGray_8_SkColorType: diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp index 081f237fe1..89889d2555 100644 --- a/src/codec/SkGifCodec.cpp +++ b/src/codec/SkGifCodec.cpp @@ -94,6 +94,10 @@ SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { // expanding to 8 bits and take advantage of the SkSwizzler to work from 4. const auto encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8); + // Although the encodedInfo is always kPalette_Color, it is possible that kIndex_8 is + // unsupported if the frame is subset and there is no transparent pixel. + const auto colorType = reader->firstFrameSupportsIndex8() ? kIndex_8_SkColorType + : kN32_SkColorType; // The choice of unpremul versus premul is arbitrary, since all colors are either fully // opaque or fully transparent (i.e. kBinary), but we stored the transparent colors as all // zeroes, which is arguably premultiplied. @@ -101,7 +105,7 @@ SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { : kOpaque_SkAlphaType; const auto imageInfo = SkImageInfo::Make(reader->screenWidth(), reader->screenHeight(), - kN32_SkColorType, alphaType, + colorType, alphaType, SkColorSpace::MakeSRGB()); return new SkGifCodec(encodedInfo, imageInfo, reader.release()); } @@ -185,7 +189,8 @@ void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, int frameIndex } -SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, const Options& opts) { +SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, + int* inputColorCount, const Options& opts) { if (opts.fSubset) { return gif_error("Subsets not supported.\n", kUnimplemented); } @@ -246,6 +251,11 @@ SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, const Op this->initializeSwizzler(dstInfo, frameIndex); SkASSERT(fCurrColorTable); + if (inputColorCount) { + *inputColorCount = fCurrColorTable->count(); + } + copy_color_table(dstInfo, fCurrColorTable.get(), inputColorPtr, inputColorCount); + return kSuccess; } @@ -287,8 +297,10 @@ void SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, int frameIndex) SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, void* pixels, size_t dstRowBytes, const Options& opts, + SkPMColor* inputColorPtr, + int* inputColorCount, int* rowsDecoded) { - Result result = this->prepareToDecode(dstInfo, opts); + Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts); switch (result) { case kSuccess: break; @@ -316,8 +328,10 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, SkCodec::Result SkGifCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, size_t dstRowBytes, - const SkCodec::Options& opts) { - Result result = this->prepareToDecode(dstInfo, opts); + const SkCodec::Options& opts, + SkPMColor* inputColorPtr, + int* inputColorCount) { + Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts); if (result != kSuccess) { return result; } @@ -409,8 +423,28 @@ SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts, } uint64_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const { + // Note: Using fCurrColorTable relies on having called initializeColorTable already. + // This is (currently) safe because this method is only called when filling, after + // initializeColorTable has been called. + // FIXME: Is there a way to make this less fragile? + if (dstInfo.colorType() == kIndex_8_SkColorType && fCurrColorTableIsReal) { + // We only support index 8 for the first frame, for backwards + // compatibity on Android, so we are using the color table for the first frame. + SkASSERT(this->options().fFrameIndex == 0); + // Use the transparent index for the first frame. + const int transPixel = fReader->frameContext(0)->transparentPixel(); + if (transPixel >= 0 && transPixel < fCurrColorTable->count()) { + return transPixel; + } + // Fall through to return SK_ColorTRANSPARENT (i.e. 0). This choice is arbitrary, + // but we have to pick something inside the color table, and this one is as good + // as any. + } // Using transparent as the fill value matches the behavior in Chromium, // which ignores the background color. + // If the colorType is kIndex_8, and there was no color table (i.e. + // fCurrColorTableIsReal is false), this value (zero) corresponds to the + // only entry in the dummy color table provided to the client. return SK_ColorTRANSPARENT; } diff --git a/src/codec/SkGifCodec.h b/src/codec/SkGifCodec.h index 7bb86f824b..33472d8ac1 100644 --- a/src/codec/SkGifCodec.h +++ b/src/codec/SkGifCodec.h @@ -40,7 +40,7 @@ protected: * Performs the full gif decode */ Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, - int*) override; + SkPMColor*, int*, int*) override; SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kGIF; @@ -55,7 +55,7 @@ protected: int onGetRepetitionCount() override; Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t, - const SkCodec::Options&) override; + const SkCodec::Options&, SkPMColor*, int*) override; Result onIncrementalDecode(int*) override; @@ -74,9 +74,11 @@ private: void initializeColorTable(const SkImageInfo& dstInfo, int frameIndex); /* - * Does necessary setup, including setting up the color table and swizzler. + * Does necessary setup, including setting up the color table and swizzler, + * and reports color info to the client. */ - Result prepareToDecode(const SkImageInfo& dstInfo, const Options& opts); + Result prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, + int* inputColorCount, const Options& opts); /* * Initializes the swizzler. diff --git a/src/codec/SkIcoCodec.cpp b/src/codec/SkIcoCodec.cpp index d1cbed0377..cde233a1bd 100644 --- a/src/codec/SkIcoCodec.cpp +++ b/src/codec/SkIcoCodec.cpp @@ -255,8 +255,8 @@ bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) { */ SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, - const Options& opts, - int* rowsDecoded) { + const Options& opts, SkPMColor* colorTable, + int* colorCount, int* rowsDecoded) { if (opts.fSubset) { // Subsets are not supported. return kUnimplemented; @@ -271,7 +271,7 @@ SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, } SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get(); - result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts); + result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts, colorTable, colorCount); switch (result) { case kSuccess: case kIncompleteInput: @@ -292,7 +292,7 @@ SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, } SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) { + const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount) { int index = 0; SkCodec::Result result = kInvalidScale; while (true) { @@ -302,7 +302,7 @@ SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, } SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get(); - result = embeddedCodec->startScanlineDecode(dstInfo, &options); + result = embeddedCodec->startScanlineDecode(dstInfo, &options, colorTable, colorCount); if (kSuccess == result) { fCurrScanlineCodec = embeddedCodec; fCurrIncrementalCodec = nullptr; @@ -327,7 +327,8 @@ bool SkIcoCodec::onSkipScanlines(int count) { } SkCodec::Result SkIcoCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, - void* pixels, size_t rowBytes, const SkCodec::Options& options) { + void* pixels, size_t rowBytes, const SkCodec::Options& options, + SkPMColor* colorTable, int* colorCount) { int index = 0; while (true) { index = this->chooseCodec(dstInfo.dimensions(), index); @@ -337,7 +338,7 @@ SkCodec::Result SkIcoCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get(); switch (embeddedCodec->startIncrementalDecode(dstInfo, - pixels, rowBytes, &options)) { + pixels, rowBytes, &options, colorTable, colorCount)) { case kSuccess: fCurrIncrementalCodec = embeddedCodec; fCurrScanlineCodec = nullptr; @@ -355,7 +356,8 @@ SkCodec::Result SkIcoCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, // valid for scanline decoding. // Once BMP supports incremental decoding this workaround can go // away. - if (embeddedCodec->startScanlineDecode(dstInfo) == kSuccess) { + if (embeddedCodec->startScanlineDecode(dstInfo, nullptr, + colorTable, colorCount) == kSuccess) { return kUnimplemented; } // Move on to the next embedded codec. diff --git a/src/codec/SkIcoCodec.h b/src/codec/SkIcoCodec.h index 9f2457aa0d..2a4efb50b0 100644 --- a/src/codec/SkIcoCodec.h +++ b/src/codec/SkIcoCodec.h @@ -40,7 +40,7 @@ protected: * Initiates the Ico decode */ Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, - int*) override; + SkPMColor*, int*, int*) override; SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kICO; @@ -50,15 +50,15 @@ protected: private: - Result onStartScanlineDecode(const SkImageInfo& dstInfo, - const SkCodec::Options& options) override; + Result onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, + SkPMColor inputColorPtr[], int* inputColorCount) override; int onGetScanlines(void* dst, int count, size_t rowBytes) override; bool onSkipScanlines(int count) override; Result onStartIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, - const SkCodec::Options&) override; + const SkCodec::Options&, SkPMColor*, int*) override; Result onIncrementalDecode(int* rowsDecoded) override; diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 728298917a..4d97cce124 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -556,7 +556,7 @@ static inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorTy */ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, - const Options& options, + const Options& options, SkPMColor*, int*, int* rowsDecoded) { if (options.fSubset) { // Subsets are not supported. @@ -673,7 +673,7 @@ SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { } SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, - const Options& options) { + const Options& options, SkPMColor ctable[], int* ctableCount) { // Set the jump location for libjpeg errors if (setjmp(fDecoderMgr->getJmpBuf())) { SkCodecPrintf("setjmp: Error from libjpeg\n"); diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h index 2d6822e8af..0c2f4a1257 100644 --- a/src/codec/SkJpegCodec.h +++ b/src/codec/SkJpegCodec.h @@ -45,7 +45,7 @@ protected: * Initiates the jpeg decode */ Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, - int*) override; + SkPMColor*, int*, int*) override; bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override; @@ -120,8 +120,8 @@ private: * Scanline decoding. */ SkSampler* getSampler(bool createIfNecessary) override; - Result onStartScanlineDecode(const SkImageInfo& dstInfo, - const Options& options) override; + Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, + SkPMColor ctable[], int* ctableCount) override; int onGetScanlines(void* dst, int count, size_t rowBytes) override; bool onSkipScanlines(int count) override; diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index ea832ff688..d77fe4007d 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -245,7 +245,7 @@ void SkPngCodec::processData() { static const SkColorType kXformSrcColorType = kRGBA_8888_SkColorType; // Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here. -bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) { +bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) { int numColors; png_color* palette; @@ -308,6 +308,11 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) { sk_memset32(colorTable + numColors, lastColor, maxColors - numColors); } + // Set the new color count. + if (ctableCount != nullptr) { + *ctableCount = maxColors; + } + fColorTable.reset(new SkColorTable(colorTable, maxColors)); return true; } @@ -968,7 +973,8 @@ void SkPngCodec::destroyReadStruct() { // Getting the pixels /////////////////////////////////////////////////////////////////////////////// -SkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options) { +SkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options, + SkPMColor ctable[], int* ctableCount) { if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) { SkCodecPrintf("Failed on png_read_update_info.\n"); return kInvalidInput; @@ -1005,11 +1011,14 @@ SkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const O } if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { - if (!this->createColorTable(dstInfo)) { + if (!this->createColorTable(dstInfo, ctableCount)) { return kInvalidInput; } } + // Copy the color table to the client if they request kIndex8 mode. + copy_color_table(dstInfo, fColorTable.get(), ctable, ctableCount); + this->initializeSwizzler(dstInfo, options, skipFormatConversion); return kSuccess; } @@ -1083,12 +1092,13 @@ bool SkPngCodec::onRewind() { SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, const Options& options, + SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { if (!conversion_possible(dstInfo, this->getInfo())) { return kInvalidConversion; } - Result result = this->initializeXforms(dstInfo, options); + Result result = this->initializeXforms(dstInfo, options, ctable, ctableCount); if (kSuccess != result) { return result; } @@ -1103,12 +1113,13 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, } SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, - void* dst, size_t rowBytes, const SkCodec::Options& options) { + void* dst, size_t rowBytes, const SkCodec::Options& options, + SkPMColor* ctable, int* ctableCount) { if (!conversion_possible(dstInfo, this->getInfo())) { return kInvalidConversion; } - Result result = this->initializeXforms(dstInfo, options); + Result result = this->initializeXforms(dstInfo, options, ctable, ctableCount); if (kSuccess != result) { return result; } diff --git a/src/codec/SkPngCodec.h b/src/codec/SkPngCodec.h index 25a5f07877..b329fef1b6 100644 --- a/src/codec/SkPngCodec.h +++ b/src/codec/SkPngCodec.h @@ -47,7 +47,7 @@ protected: SkPngCodec(const SkEncodedInfo&, const SkImageInfo&, SkStream*, SkPngChunkReader*, void* png_ptr, void* info_ptr, int bitDepth); - Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*) + Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*) override; SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kPNG; } bool onRewind() override; @@ -73,7 +73,8 @@ protected: void processData(); Result onStartIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, - const SkCodec::Options&) override; + const SkCodec::Options&, + SkPMColor* ctable, int* ctableCount) override; Result onIncrementalDecode(int*) override; sk_sp<SkPngChunkReader> fPngChunkReader; @@ -100,9 +101,10 @@ private: kSwizzleColor_XformMode, }; - bool createColorTable(const SkImageInfo& dstInfo); + bool createColorTable(const SkImageInfo& dstInfo, int* ctableCount); // Helper to set up swizzler, color xforms, and color table. Also calls png_read_update_info. - SkCodec::Result initializeXforms(const SkImageInfo& dstInfo, const Options&); + SkCodec::Result initializeXforms(const SkImageInfo& dstInfo, const Options&, + SkPMColor* colorPtr, int* colorCount); void initializeSwizzler(const SkImageInfo& dstInfo, const Options&, bool skipFormatConversion); void allocateStorage(const SkImageInfo& dstInfo); void destroyReadStruct(); diff --git a/src/codec/SkRawAdapterCodec.cpp b/src/codec/SkRawAdapterCodec.cpp index 49170911a4..76cbaa1a23 100644 --- a/src/codec/SkRawAdapterCodec.cpp +++ b/src/codec/SkRawAdapterCodec.cpp @@ -24,5 +24,7 @@ SkCodec::Result SkRawAdapterCodec::onGetAndroidPixels( SkCodec::Options codecOptions; codecOptions.fZeroInitialized = options.fZeroInitialized; codecOptions.fSubset = options.fSubset; - return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions); + return this->codec()->getPixels( + info, pixels, rowBytes, &codecOptions, options.fColorPtr, + options.fColorCount); } diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp index 83b7947ab6..b8bcf19163 100644 --- a/src/codec/SkRawCodec.cpp +++ b/src/codec/SkRawCodec.cpp @@ -688,6 +688,7 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, + SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { if (!conversion_possible(dstInfo, this->getInfo()) || !this->initializeColorXform(dstInfo, options.fPremulBehavior)) diff --git a/src/codec/SkRawCodec.h b/src/codec/SkRawCodec.h index d2ef921f1d..51bb234b73 100644 --- a/src/codec/SkRawCodec.h +++ b/src/codec/SkRawCodec.h @@ -35,7 +35,7 @@ public: protected: Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, - int*) override; + SkPMColor*, int*, int*) override; SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kDNG; diff --git a/src/codec/SkSampledCodec.cpp b/src/codec/SkSampledCodec.cpp index b8e2a56286..045f184f29 100644 --- a/src/codec/SkSampledCodec.cpp +++ b/src/codec/SkSampledCodec.cpp @@ -80,7 +80,8 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void SkIRect* subset = options.fSubset; if (!subset || subset->size() == this->codec()->getInfo().dimensions()) { if (this->codec()->dimensionsSupported(info.dimensions())) { - return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions); + return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions, + options.fColorPtr, options.fColorCount); } // If the native codec does not support the requested scale, scale by sampling. @@ -111,7 +112,8 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void scaledSubsetWidth, scaledSubsetHeight); codecOptions.fSubset = &incrementalSubset; const SkCodec::Result startResult = this->codec()->startIncrementalDecode( - scaledInfo, pixels, rowBytes, &codecOptions); + scaledInfo, pixels, rowBytes, &codecOptions, + options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess == startResult) { int rowsDecoded; const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); @@ -138,7 +140,7 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void codecOptions.fSubset = &scanlineSubset; SkCodec::Result result = this->codec()->startScanlineDecode(scaledInfo, - &codecOptions); + &codecOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess != result) { return result; } @@ -228,7 +230,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix incrementalOptions.fSubset = &incrementalSubset; } const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo, - pixels, rowBytes, &incrementalOptions); + pixels, rowBytes, &incrementalOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess == startResult) { SkSampler* sampler = this->codec()->getSampler(true); if (!sampler) { @@ -262,7 +264,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix // Start the scanline decode. SkCodec::Result result = this->codec()->startScanlineDecode(nativeInfo, - &sampledOptions); + &sampledOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess != result) { return result; } diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp index fe9a29133e..780ae5e5d0 100644 --- a/src/codec/SkWbmpCodec.cpp +++ b/src/codec/SkWbmpCodec.cpp @@ -21,6 +21,15 @@ static inline size_t get_src_row_bytes(int width) { return SkAlign8(width) >> 3; } +static inline void setup_color_table(SkColorType colorType, + SkPMColor* colorPtr, int* colorCount) { + if (kIndex_8_SkColorType == colorType) { + colorPtr[0] = SK_ColorBLACK; + colorPtr[1] = SK_ColorWHITE; + *colorCount = 2; + } +} + static inline bool valid_color_type(const SkImageInfo& dstInfo) { switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: @@ -88,8 +97,9 @@ bool SkWbmpCodec::onRewind() { return read_header(this->stream(), nullptr); } -SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const Options& opts) { - return SkSwizzler::CreateSwizzler(this->getEncodedInfo(), nullptr, info, opts); +SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable, + const Options& opts) { + return SkSwizzler::CreateSwizzler(this->getEncodedInfo(), ctable, info, opts); } bool SkWbmpCodec::readRow(uint8_t* row) { @@ -102,6 +112,7 @@ SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info, SkStr stream, SkColorSpace::MakeSRGB()) , fSrcRowBytes(get_src_row_bytes(this->getInfo().width())) , fSwizzler(nullptr) + , fColorTable(nullptr) {} SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const { @@ -112,6 +123,8 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, void* dst, size_t rowBytes, const Options& options, + SkPMColor ctable[], + int* ctableCount, int* rowsDecoded) { if (options.fSubset) { // Subsets are not supported. @@ -122,8 +135,11 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, return kInvalidConversion; } + // Prepare a color table if necessary + setup_color_table(info.colorType(), ctable, ctableCount); + // Initialize the swizzler - std::unique_ptr<SkSwizzler> swizzler(this->initializeSwizzler(info, options)); + std::unique_ptr<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, options)); SkASSERT(swizzler); // Perform the decode @@ -175,7 +191,7 @@ bool SkWbmpCodec::onSkipScanlines(int count) { } SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, - const Options& options) { + const Options& options, SkPMColor inputColorTable[], int* inputColorCount) { if (options.fSubset) { // Subsets are not supported. return kUnimplemented; @@ -187,8 +203,16 @@ SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kInvalidConversion; } + // Fill in the color table + setup_color_table(dstInfo.colorType(), inputColorTable, inputColorCount); + + // Copy the color table to a pointer that can be owned by the scanline decoder + if (kIndex_8_SkColorType == dstInfo.colorType()) { + fColorTable.reset(new SkColorTable(inputColorTable, 2)); + } + // Initialize the swizzler - fSwizzler.reset(this->initializeSwizzler(dstInfo, options)); + fSwizzler.reset(this->initializeSwizzler(dstInfo, get_color_ptr(fColorTable.get()), options)); SkASSERT(fSwizzler); fSrcBuffer.reset(fSrcRowBytes); diff --git a/src/codec/SkWbmpCodec.h b/src/codec/SkWbmpCodec.h index e8a6e40aba..40f507e9f3 100644 --- a/src/codec/SkWbmpCodec.h +++ b/src/codec/SkWbmpCodec.h @@ -26,13 +26,13 @@ public: protected: SkEncodedImageFormat onGetEncodedFormat() const override; Result onGetPixels(const SkImageInfo&, void*, size_t, - const Options&, int*) override; + const Options&, SkPMColor[], int*, int*) override; bool onRewind() override; private: /* * Returns a swizzler on success, nullptr on failure */ - SkSwizzler* initializeSwizzler(const SkImageInfo& info, + SkSwizzler* initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable, const Options& opts); SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fSwizzler || !createIfNecessary); @@ -50,12 +50,13 @@ private: // Used for scanline decodes: std::unique_ptr<SkSwizzler> fSwizzler; + sk_sp<SkColorTable> fColorTable; SkAutoTMalloc<uint8_t> fSrcBuffer; int onGetScanlines(void* dst, int count, size_t dstRowBytes) override; bool onSkipScanlines(int count) override; - Result onStartScanlineDecode(const SkImageInfo& dstInfo, - const Options& options) override; + Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, + SkPMColor inputColorTable[], int* inputColorCount) override; typedef SkCodec INHERITED; }; diff --git a/src/codec/SkWebpAdapterCodec.cpp b/src/codec/SkWebpAdapterCodec.cpp index 93400d0015..cf1f0e0e1f 100644 --- a/src/codec/SkWebpAdapterCodec.cpp +++ b/src/codec/SkWebpAdapterCodec.cpp @@ -41,5 +41,6 @@ SkCodec::Result SkWebpAdapterCodec::onGetAndroidPixels(const SkImageInfo& info, codecOptions.fZeroInitialized = options.fZeroInitialized; codecOptions.fSubset = options.fSubset; codecOptions.fPremulBehavior = SkTransferFunctionBehavior::kIgnore; - return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions); + return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr, + options.fColorCount); } diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp index e8e409a486..d94011a867 100644 --- a/src/codec/SkWebpCodec.cpp +++ b/src/codec/SkWebpCodec.cpp @@ -378,7 +378,8 @@ static void blend_line(SkColorType dstCT, void* dst, } SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, - const Options& options, int* rowsDecodedPtr) { + const Options& options, SkPMColor*, int*, + int* rowsDecodedPtr) { const int index = options.fFrameIndex; SkASSERT(0 == index || index < fFrameHolder.size()); diff --git a/src/codec/SkWebpCodec.h b/src/codec/SkWebpCodec.h index c911ebd585..fc9e6838a6 100644 --- a/src/codec/SkWebpCodec.h +++ b/src/codec/SkWebpCodec.h @@ -31,7 +31,8 @@ public: static SkCodec* NewFromStream(SkStream*); static bool IsWebp(const void*, size_t); protected: - Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*) override; + Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*) + override; SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kWEBP; } SkISize onGetScaledDimensions(float desiredScale) const override; |