Chromium Code Reviews| Index: src/codec/SkWebpCodec.cpp |
| diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp |
| index c12b1df5edf955d547aad34892d441544528f485..aae57a3ff0df2df176b2fa9ac18ca612a20def73 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,27 @@ 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. |
|
scroggo
2016/09/07 20:32:58
Why don't we today?
msarett
2016/09/07 22:27:41
I haven't implemented BGRA as an input yet :)
|
| + config.output.colorspace = colorXform ? MODE_RGBA : |
| + webp_decode_mode(dstInfo.colorType(), dstInfo.alphaType() == kPremul_SkAlphaType); |
| config.output.is_external_memory = 1; |
| + SkAutoTMalloc<uint32_t> pixels; |
| + if (kRGBA_F16_SkColorType == dstInfo.colorType()) { |
| + // The best we can do is to decode into an 8888 buffer and then transform the entire |
| + // buffer to F16. libwebp does not support a row-by-row decode. |
|
scroggo
2016/09/07 20:32:58
It seems like this comment mostly applies to the b
msarett
2016/09/07 22:27:41
Yeah, I'll move it up. It's just that it's awful
|
| + 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 +308,38 @@ 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; |
| - case VP8_STATUS_SUSPENDED: |
| - WebPIDecGetRGB(idec, rowsDecoded, nullptr, nullptr, nullptr); |
| - return kIncompleteInput; |
| + rowsDecoded = dstInfo.height(); |
| + result = kSuccess; |
| + break; |
| + case VP8_STATUS_SUSPENDED: { |
|
scroggo
2016/09/07 20:32:58
Nit: do you need the braces?
msarett
2016/09/07 22:27:41
No, removed.
|
| + WebPIDecGetRGB(idec, rowsDecodedPtr, nullptr, nullptr, nullptr); |
| + |
| + rowsDecoded = *rowsDecodedPtr; |
| + result = kIncompleteInput; |
| + break; |
| + } |
| default: |
| return kInvalidInput; |
| } |
| + |
| + if (colorXform) { |
| + SkAlphaType xformAlphaType = color_xform_alpha_type(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, |