diff options
author | 2017-03-27 15:07:35 -0400 | |
---|---|---|
committer | 2017-03-28 16:07:04 +0000 | |
commit | d2adc66efec8a172b71bf5572fbedde064025825 (patch) | |
tree | 12a61a477bfc82b769912951e920eb787a42eb60 | |
parent | 20ece3a966708bf2886034cda15aea7f4946f4b1 (diff) |
Use SkTransferFunctionBehavior for raster pixel conversions
Fixes some gbr-8888 behaviors.
BUG=skia:
Change-Id: I1351b043129f7ed0e125bfdb626a0ecaf64c15cc
Reviewed-on: https://skia-review.googlesource.com/10169
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Matt Sarett <msarett@google.com>
-rw-r--r-- | include/core/SkBitmap.h | 7 | ||||
-rw-r--r-- | src/core/SkBitmap.cpp | 8 | ||||
-rw-r--r-- | src/core/SkConvertPixels.cpp | 79 | ||||
-rw-r--r-- | src/core/SkConvertPixels.h | 2 | ||||
-rw-r--r-- | src/core/SkPixmap.cpp | 2 | ||||
-rw-r--r-- | src/image/SkImage_Raster.cpp | 4 |
6 files changed, 70 insertions, 32 deletions
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 700dbc2cb4..fd25a23cdd 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -657,7 +657,9 @@ public: * This is logically the same as creating a bitmap around src, and calling readPixels on it * with this bitmap as the dst. */ - bool writePixels(const SkPixmap& src, int dstX, int dstY); + bool writePixels(const SkPixmap& src, int dstX, int dstY) { + return this->writePixels(src, dstX, dstY, SkTransferFunctionBehavior::kRespect); + } bool writePixels(const SkPixmap& src) { return this->writePixels(src, 0, 0); } @@ -777,6 +779,8 @@ private: uint32_t fRowBytes; uint8_t fFlags; + bool writePixels(const SkPixmap& src, int x, int y, SkTransferFunctionBehavior behavior); + /* Unreference any pixelrefs or colortables */ void freePixels(); @@ -785,6 +789,7 @@ private: static void WriteRawPixels(SkWriteBuffer*, const SkBitmap&); static bool ReadRawPixels(SkReadBuffer*, SkBitmap*); + friend class SkImage_Raster; friend class SkReadBuffer; // unflatten, rawpixels friend class SkBinaryWriteBuffer; // rawpixels friend struct SkBitmapProcState; diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 4a55e1a7f3..0a999cee42 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -709,7 +709,8 @@ bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const { return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY); } -bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) { +bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY, + SkTransferFunctionBehavior behavior) { SkAutoPixmapUnlock dst; if (!this->requestLock(&dst)) { return false; @@ -727,7 +728,7 @@ bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) { void* dstPixels = this->getAddr(rec.fX, rec.fY); const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes, - src.ctable()); + src.ctable(), behavior); return true; } @@ -848,7 +849,8 @@ static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int } const SkPixmap& pmap = apl.pixmap(); SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes, - pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable()); + pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(), + SkTransferFunctionBehavior::kRespect); return true; } diff --git a/src/core/SkConvertPixels.cpp b/src/core/SkConvertPixels.cpp index 787acb97f2..b919f5dbe8 100644 --- a/src/core/SkConvertPixels.cpp +++ b/src/core/SkConvertPixels.cpp @@ -5,7 +5,7 @@ * found in the LICENSE file. */ -#include "SkColorSpaceXform.h" +#include "SkColorSpaceXform_Base.h" #include "SkColorSpaceXformPriv.h" #include "SkColorTable.h" #include "SkConvertPixels.h" @@ -87,9 +87,13 @@ void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t ds } // Fast Path 3: Color space xform. -static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { - if (kUnpremul_SkAlphaType == dstInfo.alphaType() && kPremul_SkAlphaType == srcInfo.alphaType()) - { +static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, + SkTransferFunctionBehavior behavior) { + // Unpremultiplication is unsupported by SkColorSpaceXform. Note that if |src| is non-linearly + // premultiplied, we're always going to have to unpremultiply before doing anything. + if (kPremul_SkAlphaType == srcInfo.alphaType() && + (kUnpremul_SkAlphaType == dstInfo.alphaType() || + SkTransferFunctionBehavior::kIgnore == behavior)) { return false; } @@ -115,7 +119,7 @@ static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkIma static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, const SkImageInfo& srcInfo, const void* srcPixels, - size_t srcRB) { + size_t srcRB, SkTransferFunctionBehavior behavior) { SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType()); SkAlphaType xformAlpha; @@ -142,8 +146,8 @@ static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels break; } - std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcInfo.colorSpace(), - dstInfo.colorSpace()); + std::unique_ptr<SkColorSpaceXform> xform = + SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior); SkASSERT(xform); for (int y = 0; y < dstInfo.height(); y++) { @@ -158,14 +162,14 @@ static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels template <typename T> void do_index8(const SkImageInfo& dstInfo, T* dstPixels, size_t dstRB, const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB, - SkColorTable* ctable) { + SkColorTable* ctable, SkTransferFunctionBehavior behavior) { T dstCTable[256]; int count = ctable->count(); SkImageInfo srcInfo8888 = srcInfo.makeColorType(kN32_SkColorType).makeWH(count, 1); SkImageInfo dstInfoCT = dstInfo.makeWH(count, 1); size_t rowBytes = count * sizeof(T); SkConvertPixels(dstInfoCT, dstCTable, rowBytes, srcInfo8888, ctable->readColors(), rowBytes, - nullptr); + nullptr, behavior); for (int y = 0; y < dstInfo.height(); y++) { for (int x = 0; x < dstInfo.width(); x++) { @@ -178,21 +182,25 @@ void do_index8(const SkImageInfo& dstInfo, T* dstPixels, size_t dstRB, void convert_from_index8(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB, - SkColorTable* ctable) { + SkColorTable* ctable, SkTransferFunctionBehavior behavior) { switch (dstInfo.colorType()) { case kAlpha_8_SkColorType: - do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable); + do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); break; case kRGB_565_SkColorType: case kARGB_4444_SkColorType: - do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable); + do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); break; case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: - do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable); + do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); break; case kRGBA_F16_SkColorType: - do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable); + do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, + behavior); break; default: SkASSERT(false); @@ -267,7 +275,7 @@ static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& src // Default: Use the pipeline. static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB, const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB, - bool isColorAware) { + bool isColorAware, SkTransferFunctionBehavior behavior) { SkRasterPipeline pipeline; switch (srcInfo.colorType()) { case kRGBA_8888_SkColorType: @@ -294,6 +302,12 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size break; } + SkAlphaType premulState = srcInfo.alphaType(); + if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) { + pipeline.append(SkRasterPipeline::unpremul); + premulState = kUnpremul_SkAlphaType; + } + if (isColorAware && srcInfo.gammaCloseToSRGB()) { pipeline.append_from_srgb(srcInfo.alphaType()); } @@ -304,18 +318,32 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size dstInfo.colorSpace())); } - SkAlphaType sat = srcInfo.alphaType(); SkAlphaType dat = dstInfo.alphaType(); - if (sat == kPremul_SkAlphaType && dat == kUnpremul_SkAlphaType) { - pipeline.append(SkRasterPipeline::unpremul); - } else if (sat == kUnpremul_SkAlphaType && dat == kPremul_SkAlphaType) { - pipeline.append(SkRasterPipeline::premul); + if (SkTransferFunctionBehavior::kRespect == behavior) { + if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) { + pipeline.append(SkRasterPipeline::unpremul); + premulState = kUnpremul_SkAlphaType; + } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) { + pipeline.append(SkRasterPipeline::premul); + premulState = kPremul_SkAlphaType; + } } if (isColorAware && dstInfo.gammaCloseToSRGB()) { pipeline.append(SkRasterPipeline::to_srgb); } + if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat && + SkTransferFunctionBehavior::kIgnore == behavior) + { + pipeline.append(SkRasterPipeline::premul); + premulState = kPremul_SkAlphaType; + } + + // The final premul state must equal the dst alpha type. Note that if we are "converting" + // opaque to another alpha type, there's no need to worry about multiplication. + SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType()); + switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: pipeline.append(SkRasterPipeline::store_8888, &dstRow); @@ -349,7 +377,7 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, - SkColorTable* ctable) { + SkColorTable* ctable, SkTransferFunctionBehavior behavior) { SkASSERT(dstInfo.dimensions() == srcInfo.dimensions()); SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo)); @@ -369,8 +397,8 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, } // Fast Path 3: Color space xform. - if (isColorAware && optimized_color_xform(dstInfo, srcInfo)) { - apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB); + if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) { + apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior); return; } @@ -378,7 +406,7 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, if (kIndex_8_SkColorType == srcInfo.colorType()) { SkASSERT(ctable); convert_from_index8(dstInfo, dstPixels, dstRB, srcInfo, (const uint8_t*) srcPixels, srcRB, - ctable); + ctable, behavior); return; } @@ -389,5 +417,6 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, } // Default: Use the pipeline. - convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware); + convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware, + behavior); } diff --git a/src/core/SkConvertPixels.h b/src/core/SkConvertPixels.h index aa641e552d..c825d84aa1 100644 --- a/src/core/SkConvertPixels.h +++ b/src/core/SkConvertPixels.h @@ -15,7 +15,7 @@ class SkColorTable; void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes, - SkColorTable* srcCTable = nullptr); + SkColorTable* srcCTable, SkTransferFunctionBehavior behavior); static inline void SkRectMemcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow, int rowCount) { diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp index 62dda1696c..7eac6c4ed5 100644 --- a/src/core/SkPixmap.cpp +++ b/src/core/SkPixmap.cpp @@ -98,7 +98,7 @@ const { const void* srcPixels = this->addr(rec.fX, rec.fY); const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(), - this->ctable()); + this->ctable(), SkTransferFunctionBehavior::kRespect); return true; } diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index 30262ddbc3..547bdbf5ad 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -374,7 +374,9 @@ sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target) cons src.setColorSpace(SkColorSpace::MakeSRGB()); } - SkAssertResult(dst.writePixels(src)); + // Use kIgnore for transfer function behavior. This is used by the SkColorSpaceXformCanvas, + // which wants to pre-xform the inputs but ignore the transfer function on blends. + SkAssertResult(dst.writePixels(src, 0, 0, SkTransferFunctionBehavior::kIgnore)); dst.setImmutable(); return SkImage::MakeFromBitmap(dst); } |