diff options
Diffstat (limited to 'src/codec')
-rw-r--r-- | src/codec/SkCodecPriv.h | 4 | ||||
-rw-r--r-- | src/codec/SkPngCodec.cpp | 16 | ||||
-rw-r--r-- | src/codec/SkWebpCodec.cpp | 74 |
3 files changed, 69 insertions, 25 deletions
diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h index 17494074b3..9a8a43e835 100644 --- a/src/codec/SkCodecPriv.h +++ b/src/codec/SkCodecPriv.h @@ -331,4 +331,8 @@ static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageIn return !isLegacy && (needsPremul || isF16 || srcDstNotEqual); } +static inline SkAlphaType select_alpha_xform(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) { + return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType; +} + #endif // SkCodecPriv_DEFINED diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index 1b8cadbf5e..ac7238d3e9 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -94,10 +94,6 @@ 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(const SkImageInfo& dstInfo, int* ctableCount) { @@ -155,8 +151,8 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) 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()); + SkAlphaType xformAlphaType = select_alpha_xform(dstInfo.alphaType(), + this->getInfo().alphaType()); fColorXform->apply(colorTable, colorTable, numColors, xformColorType, xformAlphaType); } @@ -447,8 +443,8 @@ public: return y; } - SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), - this->getInfo().alphaType()); + SkAlphaType xformAlphaType = select_alpha_xform(dstInfo.alphaType(), + this->getInfo().alphaType()); int width = fSwizzler ? fSwizzler->swizzleWidth() : dstInfo.width(); for (; y < count; y++) { @@ -533,8 +529,8 @@ public: } } - SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), - this->getInfo().alphaType()); + SkAlphaType xformAlphaType = select_alpha_xform(dstInfo.alphaType(), + this->getInfo().alphaType()); int width = fSwizzler ? fSwizzler->swizzleWidth() : dstInfo.width(); srcRow = storage.get(); for (int y = 0; y < count; y++) { diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp index c12b1df5ed..0c3aa402bd 100644 --- a/src/codec/SkWebpCodec.cpp +++ b/src/codec/SkWebpCodec.cpp @@ -6,6 +6,7 @@ */ #include "SkCodecPriv.h" +#include "SkColorSpaceXform.h" #include "SkWebpCodec.h" #include "SkStreamPriv.h" #include "SkTemplates.h" @@ -143,20 +144,20 @@ SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { streamDeleter.release(), demux.release(), std::move(data)); } -// This version is slightly different from SkCodecPriv's version of conversion_possible. It -// supports both byte orders for 8888. -static bool webp_conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { +static bool webp_conversion_possible(const SkImageInfo& dst, const SkImageInfo& src, + SkColorSpaceXform* colorXform) { if (!valid_alpha(dst.alphaType(), src.alphaType())) { return false; } switch (dst.colorType()) { - // Both byte orders are supported. + case kRGBA_F16_SkColorType: + return nullptr != colorXform; case kBGRA_8888_SkColorType: case kRGBA_8888_SkColorType: return true; case kRGB_565_SkColorType: - return src.alphaType() == kOpaque_SkAlphaType; + return nullptr == colorXform && src.alphaType() == kOpaque_SkAlphaType; default: return false; } @@ -210,8 +211,15 @@ bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const { SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, const Options& options, SkPMColor*, int*, - int* rowsDecoded) { - if (!webp_conversion_possible(dstInfo, this->getInfo())) { + int* rowsDecodedPtr) { + + std::unique_ptr<SkColorSpaceXform> colorXform = nullptr; + if (needs_color_xform(dstInfo, this->getInfo())) { + colorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpace()), + sk_ref_sp(dstInfo.colorSpace())); + } + + if (!webp_conversion_possible(dstInfo, this->getInfo(), colorXform.get())) { return kInvalidConversion; } @@ -269,13 +277,28 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, config.options.scaled_height = dstDimensions.height(); } - config.output.colorspace = webp_decode_mode(dstInfo.colorType(), - dstInfo.alphaType() == kPremul_SkAlphaType); - config.output.u.RGBA.rgba = (uint8_t*) dst; - config.output.u.RGBA.stride = (int) rowBytes; - config.output.u.RGBA.size = dstInfo.getSafeSize(rowBytes); + // FIXME (msarett): + // Lossless webp is encoded as BGRA. In that case, it would be more efficient to + // to decode BGRA and apply the color xform to a BGRA buffer. + config.output.colorspace = colorXform ? MODE_RGBA : + webp_decode_mode(dstInfo.colorType(), dstInfo.alphaType() == kPremul_SkAlphaType); config.output.is_external_memory = 1; + // We will decode the entire image and then perform the color transform. libwebp + // does not provide a row-by-row API. This is a shame particularly in the F16 case, + // where we need to allocate an extra image-sized buffer. + SkAutoTMalloc<uint32_t> pixels; + if (kRGBA_F16_SkColorType == dstInfo.colorType()) { + pixels.reset(dstDimensions.width() * dstDimensions.height()); + config.output.u.RGBA.rgba = (uint8_t*) pixels.get(); + config.output.u.RGBA.stride = (int) dstDimensions.width() * sizeof(uint32_t); + config.output.u.RGBA.size = config.output.u.RGBA.stride * dstDimensions.height(); + } else { + config.output.u.RGBA.rgba = (uint8_t*) dst; + config.output.u.RGBA.stride = (int) rowBytes; + config.output.u.RGBA.size = dstInfo.getSafeSize(rowBytes); + } + WebPIterator frame; SkAutoTCallVProc<WebPIterator, WebPDemuxReleaseIterator> autoFrame(&frame); // If this succeeded in NewFromStream(), it should succeed again here. @@ -286,15 +309,36 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, return kInvalidInput; } + int rowsDecoded; + SkCodec::Result result; switch (WebPIUpdate(idec, frame.fragment.bytes, frame.fragment.size)) { case VP8_STATUS_OK: - return kSuccess; + rowsDecoded = dstInfo.height(); + result = kSuccess; + break; case VP8_STATUS_SUSPENDED: - WebPIDecGetRGB(idec, rowsDecoded, nullptr, nullptr, nullptr); - return kIncompleteInput; + WebPIDecGetRGB(idec, rowsDecodedPtr, nullptr, nullptr, nullptr); + rowsDecoded = *rowsDecodedPtr; + result = kIncompleteInput; + break; default: return kInvalidInput; } + + if (colorXform) { + SkAlphaType xformAlphaType = select_alpha_xform(dstInfo.alphaType(), + this->getInfo().alphaType()); + + uint32_t* src = (uint32_t*) config.output.u.RGBA.rgba; + size_t srcRowBytes = config.output.u.RGBA.stride; + for (int y = 0; y < rowsDecoded; y++) { + colorXform->apply(dst, src, dstInfo.width(), dstInfo.colorType(), xformAlphaType); + dst = SkTAddOffset<void>(dst, rowBytes); + src = SkTAddOffset<uint32_t>(src, srcRowBytes); + } + } + + return result; } SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info, |