Index: src/codec/SkWebpCodec.cpp |
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp |
index c12b1df5edf955d547aad34892d441544528f485..0c3aa402bd70bfd2659b01d8468d4cfa252be82a 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, |