aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-08-22 08:48:40 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-22 08:48:40 -0700
commitdcd5e65340f9ef239d769bf20bafd2fa819eab31 (patch)
tree5597db8cdd3183f6ea8e9acb090887a90ba0f174
parentc0c6e1c5d133c51cc75ed9d5770fdc5448d8c324 (diff)
Support color xforms for kIndex8 pngs
This change started as: "Always use color xforms to premultiply". We need to be in a linear space to premultiply correctly. It became clear that we also need to support kIndex8 color xforms in order to make this change. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2246143002 Review-Url: https://codereview.chromium.org/2246143002
-rw-r--r--src/codec/SkCodecImageGenerator.cpp7
-rw-r--r--src/codec/SkCodecPriv.h21
-rw-r--r--src/codec/SkPngCodec.cpp84
-rw-r--r--src/codec/SkPngCodec.h2
4 files changed, 81 insertions, 33 deletions
diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp
index e579da92f6..1bae1df856 100644
--- a/src/codec/SkCodecImageGenerator.cpp
+++ b/src/codec/SkCodecImageGenerator.cpp
@@ -37,7 +37,12 @@ SkData* SkCodecImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) {
bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
SkPMColor ctable[], int* ctableCount) {
- SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, nullptr, ctable,
+ // FIXME (msarett):
+ // We don't give the client the chance to request an SkColorSpace. Until we improve
+ // the API, let's assume that they want legacy mode.
+ SkImageInfo decodeInfo = info.makeColorSpace(nullptr);
+
+ SkCodec::Result result = fCodec->getPixels(decodeInfo, pixels, rowBytes, nullptr, ctable,
ctableCount);
switch (result) {
case SkCodec::kSuccess:
diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h
index b768b23a8a..17494074b3 100644
--- a/src/codec/SkCodecPriv.h
+++ b/src/codec/SkCodecPriv.h
@@ -310,10 +310,25 @@ static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType co
}
}
+static inline bool needs_premul(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
+ return kPremul_SkAlphaType == dstInfo.alphaType() &&
+ kUnpremul_SkAlphaType == srcInfo.alphaType();
+}
+
static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
- return (kRGBA_F16_SkColorType == dstInfo.colorType()) ||
- (dstInfo.colorSpace() && !SkColorSpace::Equals(srcInfo.colorSpace(),
- dstInfo.colorSpace()));
+ // Color xform is necessary in order to correctly perform premultiply in linear space.
+ bool needsPremul = needs_premul(dstInfo, srcInfo);
+
+ // F16 is by definition a linear space, so we always must perform a color xform.
+ bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType();
+
+ // Need a color xform when dst space does not match the src.
+ bool srcDstNotEqual = !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
+
+ // We never perform a color xform in legacy mode.
+ bool isLegacy = nullptr == dstInfo.colorSpace();
+
+ return !isLegacy && (needsPremul || isF16 || srcDstNotEqual);
}
#endif // SkCodecPriv_DEFINED
diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
index 2b52ab72d7..8f7ab79bf1 100644
--- a/src/codec/SkPngCodec.cpp
+++ b/src/codec/SkPngCodec.cpp
@@ -92,8 +92,12 @@ private:
};
#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
+static inline SkAlphaType xform_alpha_type(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) {
+ return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType;
+}
+
// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
-bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, int* ctableCount) {
+bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) {
int numColors;
png_color* palette;
@@ -101,21 +105,27 @@ bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, in
return false;
}
- // Note: These are not necessarily SkPMColors.
- SkPMColor colorPtr[256];
+ // Contents depend on tableColorType and our choice of if/when to premultiply:
+ // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA }
+ SkPMColor colorTable[256];
+ SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo.colorType();
png_bytep alphas;
int numColorsWithAlpha = 0;
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 = !fColorXform && needs_premul(dstInfo, this->getInfo());
+
// 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.
- PackColorProc proc = choose_pack_color_proc(premultiply, dstColorType);
+ PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType);
for (int i = 0; i < numColorsWithAlpha; i++) {
// We don't have a function in SkOpts that combines a set of alphas with a set
// of RGBs. We could write one, but it's hardly worth it, given that this
// is such a small fraction of the total decode time.
- colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
+ colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
palette++;
}
}
@@ -129,21 +139,31 @@ bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, in
SkASSERT(&palette->green < &palette->blue);
#endif
- if (is_rgba(dstColorType)) {
- SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette,
+ if (is_rgba(tableColorType)) {
+ SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette,
numColors - numColorsWithAlpha);
} else {
- SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette,
+ SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette,
numColors - numColorsWithAlpha);
}
}
+ // If we are not decoding to F16, we can color xform now and store the results
+ // in the color table.
+ if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) {
+ SkColorType xformColorType = is_rgba(dstInfo.colorType()) ?
+ kRGBA_8888_SkColorType : kBGRA_8888_SkColorType;
+ SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
+ this->getInfo().alphaType());
+ fColorXform->apply(colorTable, colorTable, numColors, xformColorType, xformAlphaType);
+ }
+
// Pad the color table with the last color in the table (or black) in the case that
// invalid pixel indices exceed the number of colors in the table.
const int maxColors = 1 << fBitDepth;
if (numColors < maxColors) {
- SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_ColorBLACK;
- sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors);
+ SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK;
+ sk_memset32(colorTable + numColors, lastColor, maxColors - numColors);
}
// Set the new color count.
@@ -151,7 +171,7 @@ bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, in
*ctableCount = maxColors;
}
- fColorTable.reset(new SkColorTable(colorPtr, maxColors));
+ fColorTable.reset(new SkColorTable(colorTable, maxColors));
return true;
}
@@ -367,6 +387,11 @@ void SkPngCodec::allocateStorage() {
fColorXform ? SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcRowBytes)) : 0;
}
+static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) {
+ // We will apply the color xform when reading the color table, unless F16 is requested.
+ return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
+}
+
class SkPngNormalCodec : public SkPngCodec {
public:
SkPngNormalCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
@@ -400,18 +425,21 @@ public:
void* swizzlerDstRow = dst;
size_t swizzlerDstRowBytes = rowBytes;
- if (fColorXform) {
+
+ bool colorXform = fColorXform &&
+ apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color());
+ if (colorXform) {
swizzlerDstRow = fColorXformSrcRow;
swizzlerDstRowBytes = 0;
}
- SkAlphaType xformAlphaType = (kOpaque_SkAlphaType == this->getInfo().alphaType()) ?
- kOpaque_SkAlphaType : dstInfo.alphaType();
+ SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
+ this->getInfo().alphaType());
for (; y < count; y++) {
png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow);
- if (fColorXform) {
+ if (colorXform) {
fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizzler->swizzleWidth(),
dstInfo.colorType(), xformAlphaType);
dst = SkTAddOffset<void>(dst, rowBytes);
@@ -442,7 +470,6 @@ public:
typedef SkPngCodec INHERITED;
};
-
class SkPngInterlacedCodec : public SkPngCodec {
public:
SkPngInterlacedCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
@@ -500,25 +527,25 @@ public:
// Swizzle and xform the rows we care about
void* swizzlerDstRow = dst;
size_t swizzlerDstRowBytes = rowBytes;
- if (fColorXform) {
+
+ bool colorXform = fColorXform &&
+ apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color());
+ if (colorXform) {
swizzlerDstRow = fColorXformSrcRow;
swizzlerDstRowBytes = 0;
}
- SkAlphaType xformAlphaType = (kOpaque_SkAlphaType == this->getInfo().alphaType()) ?
- kOpaque_SkAlphaType : dstInfo.alphaType();
+ SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
+ this->getInfo().alphaType());
srcRow = storage.get();
for (int y = 0; y < count; y++) {
fSwizzler->swizzle(swizzlerDstRow, srcRow);
srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes);
- if (fColorXform) {
- if (fColorXform) {
- fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow,
- fSwizzler->swizzleWidth(), dstInfo.colorType(),
- xformAlphaType);
- dst = SkTAddOffset<void>(dst, rowBytes);
- }
+ if (colorXform) {
+ fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizzler->swizzleWidth(),
+ dstInfo.colorType(), xformAlphaType);
+ dst = SkTAddOffset<void>(dst, rowBytes);
}
swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBytes);
@@ -802,6 +829,8 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt
swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
}
break;
+ case kIndex_8_SkColorType:
+ break;
default:
return false;
}
@@ -815,8 +844,7 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt
}
if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
- if (!this->createColorTable(swizzlerInfo.colorType(),
- kPremul_SkAlphaType == swizzlerInfo.alphaType(), ctableCount)) {
+ if (!this->createColorTable(dstInfo, ctableCount)) {
return false;
}
}
diff --git a/src/codec/SkPngCodec.h b/src/codec/SkPngCodec.h
index 9d97c719da..aace7b1c4c 100644
--- a/src/codec/SkPngCodec.h
+++ b/src/codec/SkPngCodec.h
@@ -66,7 +66,7 @@ protected:
int fBitDepth;
private:
- bool createColorTable(SkColorType dstColorType, bool premultiply, int* ctableCount);
+ bool createColorTable(const SkImageInfo& dstInfo, int* ctableCount);
void destroyReadStruct();
typedef SkCodec INHERITED;