aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Matt Sarett <msarett@google.com>2016-11-04 13:19:48 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-11-04 20:55:16 +0000
commit61eedebe4ce61215a56ced832e0df73c2cb19447 (patch)
tree869f208f74b8966e8f0153edd6fe323d37adfbf6
parent125b2aac5a38121b3c82545acd27e74366ca83aa (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/VERSION2
-rw-r--r--infra/bots/tasks.json6
-rw-r--r--src/codec/SkCodec.cpp3
-rw-r--r--src/codec/SkCodecPriv.h14
-rw-r--r--src/codec/SkGifCodec.cpp92
-rw-r--r--src/codec/SkGifCodec.h7
-rw-r--r--src/codec/SkPngCodec.cpp2
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.