diff options
author | 2016-11-04 13:19:48 -0400 | |
---|---|---|
committer | 2016-11-04 20:55:16 +0000 | |
commit | 61eedebe4ce61215a56ced832e0df73c2cb19447 (patch) | |
tree | 869f208f74b8966e8f0153edd6fe323d37adfbf6 | |
parent | 125b2aac5a38121b3c82545acd27e74366ca83aa (diff) |
Add F16, SkColorSpaceXform support to SkGifCodec
BUG=skia:4895
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4396
Change-Id: I7c521760891852daf4f3933ecf02dc08acec64c0
Reviewed-on: https://skia-review.googlesource.com/4396
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
-rw-r--r-- | infra/bots/assets/skimage/VERSION | 2 | ||||
-rw-r--r-- | infra/bots/tasks.json | 6 | ||||
-rw-r--r-- | src/codec/SkCodec.cpp | 3 | ||||
-rw-r--r-- | src/codec/SkCodecPriv.h | 14 | ||||
-rw-r--r-- | src/codec/SkGifCodec.cpp | 92 | ||||
-rw-r--r-- | src/codec/SkGifCodec.h | 7 | ||||
-rw-r--r-- | src/codec/SkPngCodec.cpp | 2 |
7 files changed, 80 insertions, 46 deletions
diff --git a/infra/bots/assets/skimage/VERSION b/infra/bots/assets/skimage/VERSION index 9a037142aa..b4de394767 100644 --- a/infra/bots/assets/skimage/VERSION +++ b/infra/bots/assets/skimage/VERSION @@ -1 +1 @@ -10
\ No newline at end of file +11 diff --git a/infra/bots/tasks.json b/infra/bots/tasks.json index 0f4f3162cb..06600aa6f4 100644 --- a/infra/bots/tasks.json +++ b/infra/bots/tasks.json @@ -172,7 +172,7 @@ { "name": "skia/bots/skimage", "path": "skimage", - "version": "version:10" + "version": "version:11" }, { "name": "skia/bots/skp", @@ -219,7 +219,7 @@ { "name": "skia/bots/skimage", "path": "skimage", - "version": "version:10" + "version": "version:11" }, { "name": "skia/bots/skp", @@ -265,7 +265,7 @@ { "name": "skia/bots/skimage", "path": "skimage", - "version": "version:10" + "version": "version:11" }, { "name": "skia/bots/skp", diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 2673d2ea9f..739c9cd673 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -472,7 +472,8 @@ void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo) { fColorXform = nullptr; - if (needs_color_xform(dstInfo, fSrcInfo)) { + bool needsPremul = needs_premul(dstInfo, fEncodedInfo); + if (needs_color_xform(dstInfo, fSrcInfo, needsPremul)) { fColorXform = SkColorSpaceXform::New(fSrcInfo.colorSpace(), dstInfo.colorSpace()); if (!fColorXform) { return false; diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h index a13cdbba92..bf3ab291e2 100644 --- a/src/codec/SkCodecPriv.h +++ b/src/codec/SkCodecPriv.h @@ -344,15 +344,13 @@ static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType co } } -static inline bool needs_premul(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { +static inline bool needs_premul(const SkImageInfo& dstInfo, const SkEncodedInfo& encodedInfo) { return kPremul_SkAlphaType == dstInfo.alphaType() && - kUnpremul_SkAlphaType == srcInfo.alphaType(); + SkEncodedInfo::kUnpremul_Alpha == encodedInfo.alpha(); } -static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { - // Color xform is necessary in order to correctly perform premultiply in linear space. - bool needsPremul = needs_premul(dstInfo, srcInfo); - +static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, + bool needsPremul) { // F16 is by definition a linear space, so we always must perform a color xform. bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType(); @@ -402,10 +400,10 @@ static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo case kIndex_8_SkColorType: return kIndex_8_SkColorType == src.colorType(); case kRGB_565_SkColorType: - return kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src); + return kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src, false); case kGray_8_SkColorType: return kGray_8_SkColorType == src.colorType() && - kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src); + kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src, false); default: return false; } diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp index 277da03191..e773ed71e9 100644 --- a/src/codec/SkGifCodec.cpp +++ b/src/codec/SkGifCodec.cpp @@ -145,12 +145,29 @@ int SkGifCodec::onGetRepetitionCount() { } void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, size_t frameIndex) { - fCurrColorTable = fReader->getColorTable(dstInfo.colorType(), frameIndex); - fCurrColorTableIsReal = fCurrColorTable; - if (!fCurrColorTable) { + SkColorType colorTableColorType = dstInfo.colorType(); + if (this->colorXform()) { + colorTableColorType = kRGBA_8888_SkColorType; + } + + sk_sp<SkColorTable> currColorTable = fReader->getColorTable(colorTableColorType, frameIndex); + fCurrColorTableIsReal = currColorTable; + if (!fCurrColorTableIsReal) { // This is possible for an empty frame. Create a dummy with one value (transparent). SkPMColor color = SK_ColorTRANSPARENT; fCurrColorTable.reset(new SkColorTable(&color, 1)); + } else if (this->colorXform() && !fXformOnDecode) { + SkPMColor dstColors[256]; + SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); + SkColorSpaceXform::ColorFormat srcFormat = SkColorSpaceXform::kRGBA_8888_ColorFormat; + SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + SkAssertResult(this->colorXform()->apply(dstFormat, dstColors, srcFormat, + currColorTable->readColors(), + currColorTable->count(), xformAlphaType)); + fCurrColorTable.reset(new SkColorTable(dstColors, currColorTable->count())); + } else { + fCurrColorTable = std::move(currColorTable); } } @@ -158,13 +175,17 @@ void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, size_t frameIn SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, int* inputColorCount, const Options& opts) { // Check for valid input parameters - if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { + if (!conversion_possible(dstInfo, this->getInfo()) || !this->initializeColorXform(dstInfo)) { return gif_error("Cannot convert input type to output type.\n", kInvalidConversion); } - if (dstInfo.colorType() == kRGBA_F16_SkColorType) { - // FIXME: This should be supported. - return gif_error("GIF does not yet support F16.\n", kInvalidConversion); + fXformOnDecode = false; + if (this->colorXform()) { + fXformOnDecode = apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color()); + if (fXformOnDecode) { + fXformBuffer.reset(new uint32_t[dstInfo.width()]); + sk_bzero(fXformBuffer.get(), dstInfo.width() * sizeof(uint32_t)); + } } if (opts.fSubset) { @@ -238,6 +259,14 @@ void SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, size_t frameInde // frameRect, since it might extend beyond the edge of the frame. SkIRect swizzleRect = SkIRect::MakeLTRB(xBegin, 0, xEnd, 0); + SkImageInfo swizzlerInfo = dstInfo; + if (this->colorXform()) { + swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType); + if (kPremul_SkAlphaType == dstInfo.alphaType()) { + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); + } + } + // The default Options should be fine: // - we'll ignore if the memory is zero initialized - unless we're the first frame, this won't // matter anyway. @@ -246,7 +275,7 @@ void SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, size_t frameInde // We may not be able to use the real Options anyway, since getPixels does not store it (due to // a bug). fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), - fCurrColorTable->readColors(), dstInfo, Options(), &swizzleRect)); + fCurrColorTable->readColors(), swizzlerInfo, Options(), &swizzleRect)); SkASSERT(fSwizzler.get()); } @@ -436,6 +465,22 @@ uint64_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const { return SK_ColorTRANSPARENT; } +void SkGifCodec::applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint8_t* src) const { + if (this->colorXform() && fXformOnDecode) { + fSwizzler->swizzle(fXformBuffer.get(), src); + + const SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); + const SkColorSpaceXform::ColorFormat srcFormat = SkColorSpaceXform::kRGBA_8888_ColorFormat; + const SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + const int xformWidth = get_scaled_dimension(dstInfo.width(), fSwizzler->sampleX()); + SkAssertResult(this->colorXform()->apply(dstFormat, dst, srcFormat, fXformBuffer.get(), + xformWidth, xformAlphaType)); + } else { + fSwizzler->swizzle(dst, src); + } +} + bool SkGifCodec::haveDecodedRow(size_t frameIndex, const unsigned char* rowBegin, size_t rowNumber, unsigned repeatCount, bool writeTransparentPixels) { @@ -524,27 +569,10 @@ bool SkGifCodec::haveDecodedRow(size_t frameIndex, const unsigned char* rowBegin // will "show through" the later ones. const auto dstInfo = this->dstInfo(); if (writeTransparentPixels) { - fSwizzler->swizzle(dstLine, rowBegin); + this->applyXformRow(dstInfo, dstLine, rowBegin); } else { - // We cannot swizzle directly into the dst, since that will write the transparent pixels. - // Instead, swizzle into a temporary buffer, and copy that into the dst. - { - void* const memsetDst = fTmpBuffer.get(); - // Although onGetFillValue returns a uint64_t, we only use the low eight bits. The - // return value is either an 8 bit index (for index8) or SK_ColorTRANSPARENT, which is - // all zeroes. - const int fillValue = (uint8_t) this->onGetFillValue(dstInfo); - const size_t rb = dstInfo.minRowBytes(); - if (fillValue == 0) { - // FIXME: This special case should be unnecessary, and in fact sk_bzero just calls - // memset. But without it, the compiler thinks this is trying to pass a zero length - // to memset, causing an error. - sk_bzero(memsetDst, rb); - } else { - memset(memsetDst, fillValue, rb); - } - } - fSwizzler->swizzle(fTmpBuffer.get(), rowBegin); + sk_bzero(fTmpBuffer.get(), dstInfo.minRowBytes()); + this->applyXformRow(dstInfo, fTmpBuffer.get(), rowBegin); const size_t offsetBytes = fSwizzler->swizzleOffsetBytes(); switch (dstInfo.colorType()) { @@ -564,11 +592,11 @@ bool SkGifCodec::haveDecodedRow(size_t frameIndex, const unsigned char* rowBegin } break; } - case kIndex_8_SkColorType: { - uint8_t* dstPixel = SkTAddOffset<uint8_t>(dstLine, offsetBytes); - uint8_t* srcPixel = SkTAddOffset<uint8_t>(fTmpBuffer.get(), offsetBytes); + case kRGBA_F16_SkColorType: { + uint64_t* dstPixel = SkTAddOffset<uint64_t>(dstLine, offsetBytes); + uint64_t* srcPixel = SkTAddOffset<uint64_t>(fTmpBuffer.get(), offsetBytes); for (int i = 0; i < fSwizzler->swizzleWidth(); i++) { - if (*srcPixel != frameContext->transparentPixel()) { + if (*srcPixel != 0) { *dstPixel = *srcPixel; } dstPixel++; diff --git a/src/codec/SkGifCodec.h b/src/codec/SkGifCodec.h index 5793766204..8e93730bcd 100644 --- a/src/codec/SkGifCodec.h +++ b/src/codec/SkGifCodec.h @@ -115,6 +115,11 @@ private: Result decodeFrame(bool firstAttempt, const Options& opts, int* rowsDecoded); /* + * Swizzles and color xforms (if necessary) into dst. + */ + void applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint8_t* src) const; + + /* * Creates an instance of the decoder * Called only by NewFromStream * Takes ownership of the SkGifImageReader @@ -142,6 +147,8 @@ private: // Updated inside haveDecodedRow when rows are decoded, unless we filled // the background, in which case it is set once and left alone. int fRowsDecoded; + std::unique_ptr<uint32_t[]> fXformBuffer; + bool fXformOnDecode; typedef SkCodec INHERITED; }; diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index a7359ee848..8297dd49be 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -231,7 +231,7 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) { // If we are performing a color xform, it will handle the premultiply. Otherwise, // we'll do it here. - bool premultiply = !this->colorXform() && needs_premul(dstInfo, this->getInfo()); + bool premultiply = !this->colorXform() && needs_premul(dstInfo, this->getEncodedInfo()); // Choose which function to use to create the color table. If the final destination's // colortype is unpremultiplied, the color table will store unpremultiplied colors. |