From d851795e7992565c1eb2b9474ee5ad01d1a01fad Mon Sep 17 00:00:00 2001 From: Matt Sarett Date: Wed, 2 Nov 2016 16:18:01 -0400 Subject: Add F16, SkColorSpaceXform support to SkBmpCodec BUG=skia:4895 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4300 Change-Id: I2f2b8d3854ea3a8c5904dd3c5bea0342e2be9789 Reviewed-on: https://skia-review.googlesource.com/4300 Reviewed-by: Leon Scroggins Commit-Queue: Matt Sarett --- src/codec/SkBmpCodec.cpp | 23 +++++++++-- src/codec/SkBmpCodec.h | 16 ++++++-- src/codec/SkBmpMaskCodec.cpp | 30 +++++++++++---- src/codec/SkBmpMaskCodec.h | 2 +- src/codec/SkBmpRLECodec.cpp | 82 ++++++++++++++++++++++++++++------------ src/codec/SkBmpRLECodec.h | 3 +- src/codec/SkBmpStandardCodec.cpp | 43 +++++++++++++++------ src/codec/SkBmpStandardCodec.h | 2 +- src/codec/SkMaskSwizzler.h | 7 ++++ 9 files changed, 153 insertions(+), 55 deletions(-) (limited to 'src/codec') diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index b0ef8ad1d8..d99ba3ae43 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -587,6 +587,7 @@ SkBmpCodec::SkBmpCodec(int width, int height, const SkEncodedInfo& info, SkStrea , fBitsPerPixel(bitsPerPixel) , fRowOrder(rowOrder) , fSrcRowBytes(SkAlign4(compute_row_bytes(width, fBitsPerPixel))) + , fXformBuffer(nullptr) {} bool SkBmpCodec::onRewind() { @@ -601,13 +602,17 @@ int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const { return height - y - 1; } -SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); + if (!conversion_possible(dstInfo, this->getInfo()) || !this->initializeColorXform(dstInfo)) { return kInvalidConversion; } + return this->onPrepareToDecode(dstInfo, options, inputColorPtr, inputColorCount); +} + +SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { return prepareToDecode(dstInfo, options, inputColorPtr, inputColorCount); } @@ -627,3 +632,15 @@ bool SkBmpCodec::skipRows(int count) { bool SkBmpCodec::onSkipScanlines(int count) { return this->skipRows(count); } + +void SkBmpCodec::applyColorXform(const SkImageInfo& dstInfo, void* dst, void* src) const { + SkColorSpaceXform* xform = this->colorXform(); + if (xform) { + SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); + SkColorSpaceXform::ColorFormat srcFormat = SkColorSpaceXform::kBGRA_8888_ColorFormat; + SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + SkAssertResult(xform->apply(dstFormat, dst, srcFormat, src, dstInfo.width(), + alphaType)); + } +} diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h index 0ece7ad6ce..a51bbcecc3 100644 --- a/src/codec/SkBmpCodec.h +++ b/src/codec/SkBmpCodec.h @@ -99,9 +99,16 @@ protected: * will be set to the number of colors in the * color table. */ - virtual SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + virtual SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) = 0; + SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + const SkCodec::Options& options, SkPMColor inputColorPtr[], + int* inputColorCount); + + void applyColorXform(const SkImageInfo& dstInfo, void* dst, void* src) const; + uint32_t* xformBuffer() const { return fXformBuffer.get(); } + void resetXformBuffer(int count) { fXformBuffer.reset(new uint32_t[count]); } private: @@ -138,9 +145,10 @@ private: bool onSkipScanlines(int count) override; - const uint16_t fBitsPerPixel; - const SkScanlineOrder fRowOrder; - const size_t fSrcRowBytes; + const uint16_t fBitsPerPixel; + const SkScanlineOrder fRowOrder; + const size_t fSrcRowBytes; + std::unique_ptr fXformBuffer; typedef SkCodec INHERITED; }; diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp index 5b28252f7c..68f31b29e1 100644 --- a/src/codec/SkBmpMaskCodec.cpp +++ b/src/codec/SkBmpMaskCodec.cpp @@ -39,11 +39,6 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, return kInvalidScale; } - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); - return kInvalidConversion; - } - Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { return result; @@ -57,10 +52,22 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, return kSuccess; } -SkCodec::Result SkBmpMaskCodec::prepareToDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpMaskCodec::onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { + if (this->colorXform()) { + this->resetXformBuffer(dstInfo.width()); + } + + SkImageInfo swizzlerInfo = dstInfo; + if (this->colorXform()) { + swizzlerInfo = swizzlerInfo.makeColorType(kBGRA_8888_SkColorType); + if (kPremul_SkAlphaType == dstInfo.alphaType()) { + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); + } + } + // Initialize the mask swizzler - fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(dstInfo, this->getInfo(), fMasks, + fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(swizzlerInfo, this->getInfo(), fMasks, this->bitsPerPixel(), options)); SkASSERT(fMaskSwizzler); @@ -86,7 +93,14 @@ int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo, // Decode the row in destination format uint32_t row = this->getDstRow(y, height); void* dstRow = SkTAddOffset(dst, row * dstRowBytes); - fMaskSwizzler->swizzle(dstRow, srcRow); + + if (this->colorXform()) { + SkImageInfo xformInfo = dstInfo.makeWH(fMaskSwizzler->swizzleWidth(), dstInfo.height()); + fMaskSwizzler->swizzle(this->xformBuffer(), srcRow); + this->applyColorXform(xformInfo, dstRow, this->xformBuffer()); + } else { + fMaskSwizzler->swizzle(dstRow, srcRow); + } } // Finished decoding the entire image diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h index 4cfd4d2531..21c8db05ec 100644 --- a/src/codec/SkBmpMaskCodec.h +++ b/src/codec/SkBmpMaskCodec.h @@ -38,7 +38,7 @@ protected: size_t dstRowBytes, const Options&, SkPMColor*, int*, int*) override; - SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) override; diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp index 33ba851ec6..e502fe879f 100644 --- a/src/codec/SkBmpRLECodec.cpp +++ b/src/codec/SkBmpRLECodec.cpp @@ -44,10 +44,6 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, // Subsets are not supported. return kUnimplemented; } - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); - return kInvalidConversion; - } Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { @@ -267,7 +263,7 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, } } -SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpRLECodec::onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { // FIXME: Support subsets for scanline decodes. if (options.fSubset) { @@ -306,39 +302,75 @@ SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, */ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowBytes, const Options& opts) { - // Set RLE flags - static const uint8_t RLE_ESCAPE = 0; - static const uint8_t RLE_EOL = 0; - static const uint8_t RLE_EOF = 1; - static const uint8_t RLE_DELTA = 2; - const int width = this->getInfo().width(); int height = info.height(); - // Account for sampling. - SkImageInfo dstInfo = info.makeWH(get_scaled_dimension(width, fSampleX), height); - - // Set the background as transparent. Then, if the RLE code skips pixels, - // the skipped pixels will be transparent. - // Because of the need for transparent pixels, kN32 is the only color - // type that makes sense for the destination format. - SkASSERT(kRGBA_8888_SkColorType == dstInfo.colorType() || - kBGRA_8888_SkColorType == dstInfo.colorType()); - if (dst) { - SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroInitialized); - } - // Adjust the height and the dst if the previous call to decodeRows() left us // with lines that need to be skipped. if (height > fLinesToSkip) { height -= fLinesToSkip; - dst = SkTAddOffset(dst, fLinesToSkip * dstRowBytes); + if (dst) { + dst = SkTAddOffset(dst, fLinesToSkip * dstRowBytes); + } fLinesToSkip = 0; } else { fLinesToSkip -= height; return height; } + // Account for sampling. + SkImageInfo dstInfo = info.makeWH(get_scaled_dimension(width, fSampleX), height); + + void* decodeDst = dst; + size_t decodeRowBytes = dstRowBytes; + SkImageInfo decodeInfo = dstInfo; + if (decodeDst) { + SkCodec::ZeroInitialized zeroInit = opts.fZeroInitialized; + if (this->colorXform()) { + decodeInfo = decodeInfo.makeColorType(kBGRA_8888_SkColorType); + if (kRGBA_F16_SkColorType == dstInfo.colorType()) { + int count = height * dstInfo.width(); + this->resetXformBuffer(count); + decodeDst = this->xformBuffer(); + decodeRowBytes = dstInfo.width() * sizeof(uint32_t); + zeroInit = SkCodec::kNo_ZeroInitialized; + } + } + + // Set the background as transparent. Then, if the RLE code skips pixels, + // the skipped pixels will be transparent. + // Because of the need for transparent pixels, kN32 is the only color + // type that makes sense for the destination format. + SkASSERT(kRGBA_8888_SkColorType == decodeInfo.colorType() || + kBGRA_8888_SkColorType == decodeInfo.colorType()); + SkSampler::Fill(decodeInfo, decodeDst, decodeRowBytes, SK_ColorTRANSPARENT, zeroInit); + } + + int decodedHeight = this->decodeRLE(decodeInfo, decodeDst, decodeRowBytes); + if (this->colorXform() && decodeDst) { + for (int y = 0; y < decodedHeight; y++) { + this->applyColorXform(dstInfo, dst, decodeDst); + decodeDst = SkTAddOffset(decodeDst, decodeRowBytes); + dst = SkTAddOffset(dst, dstRowBytes); + } + } + + return decodedHeight; +} + +int SkBmpRLECodec::decodeRLE(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes) { + // Use the original width to count the number of pixels in each row. + const int width = this->getInfo().width(); + + // This tells us the number of rows that we are meant to decode. + const int height = dstInfo.height(); + + // Set RLE flags + static const uint8_t RLE_ESCAPE = 0; + static const uint8_t RLE_EOL = 0; + static const uint8_t RLE_EOF = 1; + static const uint8_t RLE_DELTA = 2; + // Destination parameters int x = 0; int y = 0; diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h index 1291e9f617..c2459c0b22 100644 --- a/src/codec/SkBmpRLECodec.h +++ b/src/codec/SkBmpRLECodec.h @@ -48,7 +48,7 @@ protected: size_t dstRowBytes, const Options&, SkPMColor*, int*, int*) override; - SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) override; @@ -89,6 +89,7 @@ private: */ int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) override; + int decodeRLE(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes); bool skipRows(int count) override; diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp index 2dbb338a07..2a703fdff9 100644 --- a/src/codec/SkBmpStandardCodec.cpp +++ b/src/codec/SkBmpStandardCodec.cpp @@ -48,10 +48,6 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, SkCodecPrintf("Error: scaling not supported.\n"); return kInvalidScale; } - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { - SkCodecPrintf("Error: cannot convert input type to output type.\n"); - return kInvalidConversion; - } Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { @@ -153,13 +149,13 @@ void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Op // In the case of bmp-in-icos, we will report BGRA to the client, // since we may be required to apply an alpha mask after the decode. // However, the swizzler needs to know the actual format of the bmp. - SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); + SkEncodedInfo encodedInfo = this->getEncodedInfo(); if (fInIco) { if (this->bitsPerPixel() <= 8) { - swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, - swizzlerInfo.alpha(), this->bitsPerPixel()); + encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, + encodedInfo.alpha(), this->bitsPerPixel()); } else if (this->bitsPerPixel() == 24) { - swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kBGR_Color, + encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kBGR_Color, SkEncodedInfo::kOpaque_Alpha, 8); } } @@ -167,13 +163,29 @@ void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Op // Get a pointer to the color table if it exists const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); - // Create swizzler - fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, colorPtr, dstInfo, opts)); + SkImageInfo swizzlerInfo = dstInfo; + SkCodec::Options swizzlerOptions = opts; + if (this->colorXform()) { + swizzlerInfo = swizzlerInfo.makeColorType(kBGRA_8888_SkColorType); + if (kPremul_SkAlphaType == dstInfo.alphaType()) { + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); + } + + swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized; + } + + + fSwizzler.reset(SkSwizzler::CreateSwizzler(encodedInfo, colorPtr, swizzlerInfo, + swizzlerOptions)); SkASSERT(fSwizzler); } -SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkBmpStandardCodec::onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { + if (this->colorXform()) { + 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(), inputColorCount)) { @@ -207,7 +219,14 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t uint32_t row = this->getDstRow(y, dstInfo.height()); void* dstRow = SkTAddOffset(dst, row * dstRowBytes); - fSwizzler->swizzle(dstRow, fSrcBuffer.get()); + + if (this->colorXform()) { + SkImageInfo xformInfo = dstInfo.makeWH(fSwizzler->swizzleWidth(), dstInfo.height()); + fSwizzler->swizzle(this->xformBuffer(), fSrcBuffer.get()); + this->applyColorXform(xformInfo, dstRow, this->xformBuffer()); + } else { + fSwizzler->swizzle(dstRow, fSrcBuffer.get()); + } } if (fInIco && fIsOpaque) { diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h index edb88acd0c..06730a6b6a 100644 --- a/src/codec/SkBmpStandardCodec.h +++ b/src/codec/SkBmpStandardCodec.h @@ -52,7 +52,7 @@ protected: return fInIco; } - SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo, + SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) override; diff --git a/src/codec/SkMaskSwizzler.h b/src/codec/SkMaskSwizzler.h index 3bf8d1758f..5d2955caab 100644 --- a/src/codec/SkMaskSwizzler.h +++ b/src/codec/SkMaskSwizzler.h @@ -45,6 +45,13 @@ public: SkSampler::Fill(fillInfo, dst, rowBytes, colorOrIndex, zeroInit); } + /** + * Returns the byte offset at which we write to destination memory, taking + * scaling, subsetting, and partial frames into account. + * A similar function exists on SkSwizzler. + */ + int swizzleWidth() const { return fDstWidth; } + private: /* -- cgit v1.2.3