aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/encode-platform.cpp3
-rw-r--r--gm/encode-srgb.cpp141
-rw-r--r--gn/gm.gni1
-rw-r--r--src/image/SkImage.cpp6
-rw-r--r--src/images/SkImageEncoder.cpp12
-rw-r--r--src/images/SkImageEncoderPriv.h14
-rw-r--r--src/images/SkPNGImageEncoder.cpp159
-rw-r--r--src/images/transform_scanline.h45
8 files changed, 298 insertions, 83 deletions
diff --git a/gm/encode-platform.cpp b/gm/encode-platform.cpp
index e8f420fb15..ca3cda1d73 100644
--- a/gm/encode-platform.cpp
+++ b/gm/encode-platform.cpp
@@ -70,7 +70,8 @@ static sk_sp<SkData> encode_data(SkEncodedImageFormat type, const SkBitmap& bitm
#else
switch (type) {
case SkEncodedImageFormat::kPNG:
- return SkEncodeImageAsPNG(&buf, src) ? buf.detachAsData() : nullptr;
+ return SkEncodeImageAsPNG(&buf, src, SkEncodeOptions()) ? buf.detachAsData()
+ : nullptr;
case SkEncodedImageFormat::kJPEG:
return SkEncodeImageAsJPEG(&buf, src, 100) ? buf.detachAsData() : nullptr;
case SkEncodedImageFormat::kWEBP:
diff --git a/gm/encode-srgb.cpp b/gm/encode-srgb.cpp
new file mode 100644
index 0000000000..b9fe65bf6a
--- /dev/null
+++ b/gm/encode-srgb.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+
+#include "Resources.h"
+#include "SkCanvas.h"
+#include "SkCodec.h"
+#include "SkData.h"
+#include "SkImageEncoderPriv.h"
+#include "SkPM4f.h"
+#include "SkSRGB.h"
+
+namespace skiagm {
+
+static const int imageWidth = 128;
+static const int imageHeight = 128;
+
+static inline int div_round_up(int a, int b) {
+ return (a + b - 1) / b;
+}
+
+static void make_index8(SkBitmap* bitmap, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
+ const SkColor colors[] = {
+ 0x800000FF, 0x8000FF00, 0x80FF0000, 0x80FFFF00,
+ };
+
+ auto toPMColor = [alphaType, colorSpace](SkColor color) {
+ // In the unpremul case, just convert to SkPMColor ordering.
+ if (kUnpremul_SkAlphaType == alphaType) {
+ return SkSwizzle_BGRA_to_PMColor(color);
+ }
+
+ // Linear premultiply.
+ if (colorSpace) {
+ uint32_t result;
+ Sk4f pmFloat = SkColor4f::FromColor(color).premul().to4f_pmorder();
+ SkNx_cast<uint8_t>(sk_linear_to_srgb_needs_trunc(pmFloat)).store(&result);
+ result = (result & 0x00FFFFFF) | (color & 0xFF000000);
+ return result;
+ }
+
+ // Legacy premultiply.
+ return SkPreMultiplyColor(color);
+ };
+
+ // Note that these are not necessarily premultiplied, but they are platform byte ordering.
+ SkPMColor pmColors[SK_ARRAY_COUNT(colors)];
+ for (int i = 0; i < (int) SK_ARRAY_COUNT(colors); i++) {
+ pmColors[i] = toPMColor(colors[i]);
+ }
+
+ sk_sp<SkColorTable> colorTable(new SkColorTable(pmColors, SK_ARRAY_COUNT(pmColors)));
+ SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kIndex_8_SkColorType,
+ alphaType, colorSpace);
+ bitmap->allocPixels(info, nullptr, colorTable.get());
+ for (int y = 0; y < imageHeight; y++) {
+ for (int x = 0; x < imageWidth; x++) {
+ *bitmap->getAddr8(x, y) = (x / div_round_up(imageWidth, 2)) +
+ (y / div_round_up(imageHeight, 3));
+ }
+ }
+}
+
+static void make(SkBitmap* bitmap, SkColorType colorType, SkAlphaType alphaType,
+ sk_sp<SkColorSpace> colorSpace) {
+ if (kIndex_8_SkColorType == colorType) {
+ make_index8(bitmap, alphaType, colorSpace);
+ return;
+ }
+
+ sk_sp<SkData> data = GetResourceAsData("color_wheel.png");
+ std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
+ SkImageInfo dstInfo = codec->getInfo().makeColorType(colorType)
+ .makeAlphaType(alphaType)
+ .makeColorSpace(colorSpace);
+ bitmap->allocPixels(dstInfo);
+ codec->getPixels(dstInfo, bitmap->getPixels(), bitmap->rowBytes());
+}
+
+static sk_sp<SkData> encode_data(const SkBitmap& bitmap) {
+ SkAutoLockPixels autoLockPixels(bitmap);
+ SkPixmap src;
+ if (!bitmap.peekPixels(&src)) {
+ return nullptr;
+ }
+ SkDynamicMemoryWStream buf;
+ SkEncodeOptions options;
+ if (bitmap.colorSpace()) {
+ options.fPremulBehavior = SkEncodeOptions::PremulBehavior::kGammaCorrect;
+ }
+ SkAssertResult(SkEncodeImageAsPNG(&buf, src, options));
+ return buf.detachAsData();
+}
+
+class EncodeSRGBGM : public GM {
+public:
+ EncodeSRGBGM() {}
+
+protected:
+ SkString onShortName() override {
+ return SkString("encode-srgb");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(imageWidth * 2, imageHeight * 4);
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ const SkColorType colorTypes[] = { kN32_SkColorType, kIndex_8_SkColorType, };
+ const SkAlphaType alphaTypes[] = { kUnpremul_SkAlphaType, kPremul_SkAlphaType, };
+ const sk_sp<SkColorSpace> colorSpaces[] = {
+ nullptr, SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named),
+ };
+
+ SkBitmap bitmap;
+ for (SkColorType colorType : colorTypes) {
+ for (SkAlphaType alphaType : alphaTypes) {
+ canvas->save();
+ for (sk_sp<SkColorSpace> colorSpace : colorSpaces) {
+ make(&bitmap, colorType, alphaType, colorSpace);
+ auto image = SkImage::MakeFromEncoded(encode_data(bitmap));
+ canvas->drawImage(image.get(), 0.0f, 0.0f);
+ canvas->translate((float) imageWidth, 0.0f);
+ }
+ canvas->restore();
+ canvas->translate(0.0f, (float) imageHeight);
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+DEF_GM( return new EncodeSRGBGM; )
+}
diff --git a/gn/gm.gni b/gn/gm.gni
index 327416c611..2a90b14ec5 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -113,6 +113,7 @@ gm_sources = [
"$_gm/emptypath.cpp",
"$_gm/encode.cpp",
"$_gm/encode-platform.cpp",
+ "$_gm/encode-srgb.cpp",
"$_gm/extractbitmap.cpp",
"$_gm/fadefilter.cpp",
"$_gm/fatpathfill.cpp",
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 417a29a1ed..d2fc8456f3 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -92,9 +92,6 @@ sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode
SkData* SkImage::encode(SkEncodedImageFormat type, int quality) const {
SkBitmap bm;
- // TODO: Right now, the encoders don't handle F16 or linearly premultiplied data. Once they do,
- // we should decode in "color space aware" mode, then re-encode that. For now, work around this
- // by asking for a legacy decode (which gives us the raw data in N32).
SkColorSpace* legacyColorSpace = nullptr;
if (as_IB(this)->getROPixels(&bm, legacyColorSpace)) {
SkDynamicMemoryWStream buf;
@@ -112,9 +109,6 @@ SkData* SkImage::encode(SkPixelSerializer* serializer) const {
SkBitmap bm;
SkAutoPixmapUnlock apu;
- // TODO: Right now, the encoders don't handle F16 or linearly premultiplied data. Once they do,
- // we should decode in "color space aware" mode, then re-encode that. For now, work around this
- // by asking for a legacy decode (which gives us the raw data in N32).
SkColorSpace* legacyColorSpace = nullptr;
if (as_IB(this)->getROPixels(&bm, legacyColorSpace) &&
bm.requestLock(&apu)) {
diff --git a/src/images/SkImageEncoder.cpp b/src/images/SkImageEncoder.cpp
index f135a02063..fecadbf82a 100644
--- a/src/images/SkImageEncoder.cpp
+++ b/src/images/SkImageEncoder.cpp
@@ -16,10 +16,14 @@ bool SkEncodeImage(SkWStream* dst, const SkPixmap& src,
return SkEncodeImageWithWIC(dst, src, format, quality);
#else
switch(format) {
- case SkEncodedImageFormat::kJPEG: return SkEncodeImageAsJPEG(dst, src, quality);
- case SkEncodedImageFormat::kPNG: return SkEncodeImageAsPNG(dst, src);
- case SkEncodedImageFormat::kWEBP: return SkEncodeImageAsWEBP(dst, src, quality);
- default: return false;
+ case SkEncodedImageFormat::kJPEG:
+ return SkEncodeImageAsJPEG(dst, src, quality);
+ case SkEncodedImageFormat::kPNG:
+ return SkEncodeImageAsPNG(dst, src, SkEncodeOptions());
+ case SkEncodedImageFormat::kWEBP:
+ return SkEncodeImageAsWEBP(dst, src, quality);
+ default:
+ return false;
}
#endif
}
diff --git a/src/images/SkImageEncoderPriv.h b/src/images/SkImageEncoderPriv.h
index 22f8f4b0ef..7748204fed 100644
--- a/src/images/SkImageEncoderPriv.h
+++ b/src/images/SkImageEncoderPriv.h
@@ -10,6 +10,18 @@
#include "SkImageEncoder.h"
+struct SkEncodeOptions {
+ enum class PremulBehavior {
+ // Convert to a linear space before premultiplying or unpremultiplying.
+ kGammaCorrect,
+
+ // Ignore the transfer function when premultiplying or unpremultiplying.
+ kLegacy,
+ };
+
+ PremulBehavior fPremulBehavior = PremulBehavior::kLegacy;
+};
+
#ifdef SK_HAS_JPEG_LIBRARY
bool SkEncodeImageAsJPEG(SkWStream*, const SkPixmap&, int quality);
#else
@@ -17,7 +29,7 @@
#endif
#ifdef SK_HAS_PNG_LIBRARY
- bool SkEncodeImageAsPNG(SkWStream*, const SkPixmap&);
+ bool SkEncodeImageAsPNG(SkWStream*, const SkPixmap&, const SkEncodeOptions&);
#else
#define SkEncodeImageAsPNG(...) false
#endif
diff --git a/src/images/SkPNGImageEncoder.cpp b/src/images/SkPNGImageEncoder.cpp
index d752bf86ba..55aead2c04 100644
--- a/src/images/SkPNGImageEncoder.cpp
+++ b/src/images/SkPNGImageEncoder.cpp
@@ -38,34 +38,55 @@ static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
}
}
-static transform_scanline_proc choose_proc(SkColorType ct, SkAlphaType alphaType) {
- static const struct {
- SkColorType fColorType;
- SkAlphaType fAlphaType;
- transform_scanline_proc fProc;
- } gMap[] = {
- { kRGB_565_SkColorType, kOpaque_SkAlphaType, transform_scanline_565 },
- { kRGBA_8888_SkColorType, kOpaque_SkAlphaType, transform_scanline_RGBX },
- { kBGRA_8888_SkColorType, kOpaque_SkAlphaType, transform_scanline_BGRX },
- { kRGBA_8888_SkColorType, kPremul_SkAlphaType, transform_scanline_rgbA },
- { kBGRA_8888_SkColorType, kPremul_SkAlphaType, transform_scanline_bgrA },
- { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_memcpy },
- { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_BGRA },
- { kARGB_4444_SkColorType, kOpaque_SkAlphaType, transform_scanline_444 },
- { kARGB_4444_SkColorType, kPremul_SkAlphaType, transform_scanline_4444 },
- { kIndex_8_SkColorType, kOpaque_SkAlphaType, transform_scanline_memcpy },
- { kIndex_8_SkColorType, kPremul_SkAlphaType, transform_scanline_memcpy },
- { kIndex_8_SkColorType, kUnpremul_SkAlphaType, transform_scanline_memcpy },
- { kGray_8_SkColorType, kOpaque_SkAlphaType, transform_scanline_memcpy },
- };
-
- for (auto entry : gMap) {
- if (entry.fColorType == ct && entry.fAlphaType == alphaType) {
- return entry.fProc;
- }
+static transform_scanline_proc choose_proc(const SkImageInfo& info) {
+ const bool isGammaEncoded = info.gammaCloseToSRGB();
+ switch (info.colorType()) {
+ case kRGBA_8888_SkColorType:
+ switch (info.alphaType()) {
+ case kOpaque_SkAlphaType:
+ return transform_scanline_RGBX;
+ case kUnpremul_SkAlphaType:
+ return transform_scanline_memcpy;
+ case kPremul_SkAlphaType:
+ return isGammaEncoded ? transform_scanline_srgbA :
+ transform_scanline_rgbA;
+ default:
+ SkASSERT(false);
+ return nullptr;
+ }
+ case kBGRA_8888_SkColorType:
+ switch (info.alphaType()) {
+ case kOpaque_SkAlphaType:
+ return transform_scanline_BGRX;
+ case kUnpremul_SkAlphaType:
+ return transform_scanline_BGRA;
+ case kPremul_SkAlphaType:
+ return isGammaEncoded ? transform_scanline_sbgrA :
+ transform_scanline_bgrA;
+ default:
+ SkASSERT(false);
+ return nullptr;
+ }
+ case kRGB_565_SkColorType:
+ return transform_scanline_565;
+ case kARGB_4444_SkColorType:
+ switch (info.alphaType()) {
+ case kOpaque_SkAlphaType:
+ return transform_scanline_444;
+ case kPremul_SkAlphaType:
+ // 4444 is assumed to be legacy premul.
+ return transform_scanline_4444;
+ default:
+ SkASSERT(false);
+ return nullptr;
+ }
+ case kIndex_8_SkColorType:
+ case kGray_8_SkColorType:
+ return transform_scanline_memcpy;
+ default:
+ SkASSERT(false);
+ return nullptr;
}
- sk_throw();
- return nullptr;
}
/* Pack palette[] with the corresponding colors, and if the image has alpha, also
@@ -73,29 +94,28 @@ static transform_scanline_proc choose_proc(SkColorType ct, SkAlphaType alphaType
opaque, the return value will always be 0.
*/
static inline int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT palette,
- png_byte* SK_RESTRICT alphas, SkAlphaType alphaType) {
- const SkPMColor* SK_RESTRICT colors = ctable->readColors();
+ png_byte* SK_RESTRICT alphas, const SkImageInfo& info) {
+ const SkPMColor* colors = ctable->readColors();
const int count = ctable->count();
- int numWithAlpha = 0;
- if (kOpaque_SkAlphaType != alphaType) {
- auto getUnpremulColor = [alphaType](uint8_t color, uint8_t alpha) {
- if (kPremul_SkAlphaType == alphaType) {
- const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
- const SkUnPreMultiply::Scale scale = table[alpha];
- return (uint8_t) SkUnPreMultiply::ApplyScale(scale, color);
- } else {
- return color;
- }
- };
+ SkPMColor storage[256];
+ if (kPremul_SkAlphaType == info.alphaType()) {
+ // Unpremultiply the colors.
+ const SkImageInfo rgbaInfo = info.makeColorType(kRGBA_8888_SkColorType);
+ transform_scanline_proc proc = choose_proc(rgbaInfo);
+ proc((char*) storage, (const char*) colors, ctable->count(), 4);
+ colors = storage;
+ }
+ int numWithAlpha = 0;
+ if (kOpaque_SkAlphaType != info.alphaType()) {
// PNG requires that all non-opaque colors come first in the palette. Write these first.
for (int i = 0; i < count; i++) {
uint8_t alpha = SkGetPackedA32(colors[i]);
if (0xFF != alpha) {
alphas[numWithAlpha] = alpha;
- palette[numWithAlpha].red = getUnpremulColor(SkGetPackedR32(colors[i]), alpha);
- palette[numWithAlpha].green = getUnpremulColor(SkGetPackedG32(colors[i]), alpha);
- palette[numWithAlpha].blue = getUnpremulColor(SkGetPackedB32(colors[i]), alpha);
+ palette[numWithAlpha].red = SkGetPackedR32(colors[i]);
+ palette[numWithAlpha].green = SkGetPackedG32(colors[i]);
+ palette[numWithAlpha].blue = SkGetPackedB32(colors[i]);
numWithAlpha++;
}
}
@@ -132,12 +152,24 @@ static inline int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT pale
static bool do_encode(SkWStream*, const SkPixmap&, int, int, png_color_8&);
-bool SkEncodeImageAsPNG(SkWStream* stream, const SkPixmap& pixmap) {
+bool SkEncodeImageAsPNG(SkWStream* stream, const SkPixmap& src, const SkEncodeOptions& opts) {
+ SkASSERT(!src.colorSpace() || src.colorSpace()->gammaCloseToSRGB() ||
+ src.colorSpace()->gammaIsLinear());
+
+ SkPixmap pixmap = src;
+ if (SkEncodeOptions::PremulBehavior::kLegacy == opts.fPremulBehavior) {
+ pixmap.setColorSpace(nullptr);
+ } else {
+ if (!pixmap.colorSpace()) {
+ return false;
+ }
+ }
+
if (!pixmap.addr() || pixmap.info().isEmpty()) {
return false;
}
- const SkColorType ct = pixmap.colorType();
- switch (ct) {
+ const SkColorType colorType = pixmap.colorType();
+ switch (colorType) {
case kIndex_8_SkColorType:
case kGray_8_SkColorType:
case kRGBA_8888_SkColorType:
@@ -152,7 +184,7 @@ bool SkEncodeImageAsPNG(SkWStream* stream, const SkPixmap& pixmap) {
const SkAlphaType alphaType = pixmap.alphaType();
switch (alphaType) {
case kUnpremul_SkAlphaType:
- if (kARGB_4444_SkColorType == ct) {
+ if (kARGB_4444_SkColorType == colorType) {
return false;
}
@@ -169,18 +201,18 @@ bool SkEncodeImageAsPNG(SkWStream* stream, const SkPixmap& pixmap) {
png_color_8 sig_bit;
sk_bzero(&sig_bit, sizeof(png_color_8));
- int colorType;
- switch (ct) {
+ int pngColorType;
+ switch (colorType) {
case kIndex_8_SkColorType:
sig_bit.red = 8;
sig_bit.green = 8;
sig_bit.blue = 8;
sig_bit.alpha = 8;
- colorType = PNG_COLOR_TYPE_PALETTE;
+ pngColorType = PNG_COLOR_TYPE_PALETTE;
break;
case kGray_8_SkColorType:
sig_bit.gray = 8;
- colorType = PNG_COLOR_TYPE_GRAY;
+ pngColorType = PNG_COLOR_TYPE_GRAY;
SkASSERT(isOpaque);
break;
case kRGBA_8888_SkColorType:
@@ -189,26 +221,26 @@ bool SkEncodeImageAsPNG(SkWStream* stream, const SkPixmap& pixmap) {
sig_bit.green = 8;
sig_bit.blue = 8;
sig_bit.alpha = 8;
- colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
+ pngColorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
break;
case kARGB_4444_SkColorType:
sig_bit.red = 4;
sig_bit.green = 4;
sig_bit.blue = 4;
sig_bit.alpha = 4;
- colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
+ pngColorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
break;
case kRGB_565_SkColorType:
sig_bit.red = 5;
sig_bit.green = 6;
sig_bit.blue = 5;
- colorType = PNG_COLOR_TYPE_RGB;
+ pngColorType = PNG_COLOR_TYPE_RGB;
SkASSERT(isOpaque);
break;
default:
return false;
}
- if (kIndex_8_SkColorType == ct) {
+ if (kIndex_8_SkColorType == colorType) {
SkColorTable* ctable = pixmap.ctable();
if (!ctable || ctable->count() == 0) {
return false;
@@ -218,14 +250,11 @@ bool SkEncodeImageAsPNG(SkWStream* stream, const SkPixmap& pixmap) {
// When ctable->count() <= 16, we could potentially use 1, 2,
// or 4 bit indices.
}
- return do_encode(stream, pixmap, colorType, bitDepth, sig_bit);
+ return do_encode(stream, pixmap, pngColorType, bitDepth, sig_bit);
}
static bool do_encode(SkWStream* stream, const SkPixmap& pixmap,
- int colorType, int bitDepth, png_color_8& sig_bit) {
- SkAlphaType alphaType = pixmap.alphaType();
- SkColorType ct = pixmap.colorType();
-
+ int pngColorType, int bitDepth, png_color_8& sig_bit) {
png_structp png_ptr;
png_infop info_ptr;
@@ -260,17 +289,17 @@ static bool do_encode(SkWStream* stream, const SkPixmap& pixmap,
*/
png_set_IHDR(png_ptr, info_ptr, pixmap.width(), pixmap.height(),
- bitDepth, colorType,
+ bitDepth, pngColorType,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
// set our colortable/trans arrays if needed
png_color paletteColors[256];
png_byte trans[256];
- if (kIndex_8_SkColorType == ct) {
+ if (kIndex_8_SkColorType == pixmap.colorType()) {
SkColorTable* colorTable = pixmap.ctable();
SkASSERT(colorTable);
- int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType);
+ int numTrans = pack_palette(colorTable, paletteColors, trans, pixmap.info());
png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count());
if (numTrans > 0) {
png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr);
@@ -283,11 +312,11 @@ static bool do_encode(SkWStream* stream, const SkPixmap& pixmap,
const char* srcImage = (const char*)pixmap.addr();
SkAutoSTMalloc<1024, char> rowStorage(pixmap.width() << 2);
char* storage = rowStorage.get();
- transform_scanline_proc proc = choose_proc(ct, alphaType);
+ transform_scanline_proc proc = choose_proc(pixmap.info());
for (int y = 0; y < pixmap.height(); y++) {
png_bytep row_ptr = (png_bytep)storage;
- proc(storage, srcImage, pixmap.width(), SkColorTypeBytesPerPixel(ct));
+ proc(storage, srcImage, pixmap.width(), SkColorTypeBytesPerPixel(pixmap.colorType()));
png_write_rows(png_ptr, &row_ptr, 1);
srcImage += pixmap.rowBytes();
}
diff --git a/src/images/transform_scanline.h b/src/images/transform_scanline.h
index a02e98ab07..1ce67cd3a2 100644
--- a/src/images/transform_scanline.h
+++ b/src/images/transform_scanline.h
@@ -13,6 +13,7 @@
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkPreConfig.h"
+#include "SkRasterPipeline.h"
#include "SkUnPreMultiply.h"
/**
@@ -128,21 +129,53 @@ static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst,
}
/**
- * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
+ * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
*/
-static void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
- int width, int bpp) {
+static void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, int width,
+ int bpp) {
transform_scanline_unpremultiply<true>(dst, src, width, bpp);
}
/**
- * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
+ * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
*/
-static void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
- int width, int bpp) {
+static void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, int width,
+ int bpp) {
transform_scanline_unpremultiply<false>(dst, src, width, bpp);
}
+template <bool kIsRGBA>
+static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width, int)
+{
+ SkRasterPipeline p;
+ p.append(SkRasterPipeline::load_8888, &src);
+ if (!kIsRGBA) {
+ p.append(SkRasterPipeline::swap_rb);
+ }
+
+ p.append_from_srgb(kPremul_SkAlphaType);
+ p.append(SkRasterPipeline::unpremul);
+ p.append(SkRasterPipeline::to_srgb);
+ p.append(SkRasterPipeline::store_8888, &dst);
+ p.run(0, 0, width);
+}
+
+/**
+ * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
+ */
+static void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+ int width, int bpp) {
+ transform_scanline_unpremultiply_sRGB<true>(dst, src, width, bpp);
+}
+
+/**
+ * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
+ */
+static void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+ int width, int bpp) {
+ transform_scanline_unpremultiply_sRGB<false>(dst, src, width, bpp);
+}
+
/**
* Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
*/