diff options
author | Leon Scroggins III <scroggo@google.com> | 2018-01-26 15:48:26 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-26 22:13:34 +0000 |
commit | da3e9ad894379713cbb66779136ca6877ccac7dd (patch) | |
tree | 6b2be2cf902fed8f4a311783e98c0d8e19fbea89 /src/codec/SkAndroidCodec.cpp | |
parent | 323df5720ce076f94709d20215e92e150ce60f6c (diff) |
Make SkAndroidCodec (optionally) respect origin
Bug: b/63909536
ImageDecoder will respect the origin, but BitmapFactory will maintain
its current behavior of not respecting it. Add an option to respect it.
In addition, add support for reading the EXIF data from a WEBP. This
seems to be an uncommon use case, but is occasionally used when
converting from a JPEG. Add 8 WEBPs, all converted (with cwebp) from
their analogous JPEG files already checked in.
Change-Id: I38afca58c86fa99ee9ab7d1dc83aaa4f23132c11
Reviewed-on: https://skia-review.googlesource.com/95300
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
Diffstat (limited to 'src/codec/SkAndroidCodec.cpp')
-rw-r--r-- | src/codec/SkAndroidCodec.cpp | 84 |
1 files changed, 70 insertions, 14 deletions
diff --git a/src/codec/SkAndroidCodec.cpp b/src/codec/SkAndroidCodec.cpp index 486257f9a3..536e3441de 100644 --- a/src/codec/SkAndroidCodec.cpp +++ b/src/codec/SkAndroidCodec.cpp @@ -9,6 +9,8 @@ #include "SkCodec.h" #include "SkCodecPriv.h" #include "SkMakeUnique.h" +#include "SkPixmap.h" +#include "SkPixmapPriv.h" #include "SkRawAdapterCodec.h" #include "SkSampledCodec.h" #include "SkWebpAdapterCodec.h" @@ -57,19 +59,32 @@ static bool is_wide_gamut(const SkColorSpace* colorSpace) { return false; } -SkAndroidCodec::SkAndroidCodec(SkCodec* codec) - : fInfo(codec->getInfo()) +static inline SkImageInfo adjust_info(SkCodec* codec, + SkAndroidCodec::ExifOrientationBehavior orientationBehavior) { + auto info = codec->getInfo(); + if (orientationBehavior == SkAndroidCodec::ExifOrientationBehavior::kIgnore + || !SkPixmapPriv::ShouldSwapWidthHeight(codec->getOrigin())) { + return info; + } + return SkPixmapPriv::SwapWidthHeight(info); +} + +SkAndroidCodec::SkAndroidCodec(SkCodec* codec, ExifOrientationBehavior orientationBehavior) + : fInfo(adjust_info(codec, orientationBehavior)) + , fOrientationBehavior(orientationBehavior) , fCodec(codec) {} SkAndroidCodec::~SkAndroidCodec() {} -std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromStream(std::unique_ptr<SkStream> stream, SkPngChunkReader* chunkReader) { +std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromStream(std::unique_ptr<SkStream> stream, + SkPngChunkReader* chunkReader) { auto codec = SkCodec::MakeFromStream(std::move(stream), nullptr, chunkReader); return MakeFromCodec(std::move(codec)); } -std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromCodec(std::unique_ptr<SkCodec> codec) { +std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromCodec(std::unique_ptr<SkCodec> codec, + ExifOrientationBehavior orientationBehavior) { if (nullptr == codec) { return nullptr; } @@ -88,14 +103,16 @@ std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromCodec(std::unique_ptr<Sk #ifdef SK_HAS_HEIF_LIBRARY case SkEncodedImageFormat::kHEIF: #endif - return skstd::make_unique<SkSampledCodec>(codec.release()); + return skstd::make_unique<SkSampledCodec>(codec.release(), orientationBehavior); #ifdef SK_HAS_WEBP_LIBRARY case SkEncodedImageFormat::kWEBP: - return skstd::make_unique<SkWebpAdapterCodec>((SkWebpCodec*) codec.release()); + return skstd::make_unique<SkWebpAdapterCodec>((SkWebpCodec*) codec.release(), + orientationBehavior); #endif #ifdef SK_CODEC_DECODES_RAW case SkEncodedImageFormat::kDNG: - return skstd::make_unique<SkRawAdapterCodec>((SkRawCodec*)codec.release()); + return skstd::make_unique<SkRawAdapterCodec>((SkRawCodec*)codec.release(), + orientationBehavior); #endif default: return nullptr; @@ -325,24 +342,43 @@ SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect get_scaled_dimension(subset.height(), sampleSize)}; } -SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels, - size_t rowBytes, const AndroidOptions* options) { - if (!pixels) { +static bool acceptable_result(SkCodec::Result result) { + switch (result) { + // These results mean a partial or complete image. They should be considered + // a success by SkPixmapPriv. + case SkCodec::kSuccess: + case SkCodec::kIncompleteInput: + case SkCodec::kErrorInInput: + return true; + default: + return false; + } +} + +SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& requestInfo, + void* requestPixels, size_t requestRowBytes, const AndroidOptions* options) { + if (!requestPixels) { return SkCodec::kInvalidParameters; } - if (rowBytes < info.minRowBytes()) { + if (requestRowBytes < requestInfo.minRowBytes()) { return SkCodec::kInvalidParameters; } + SkImageInfo adjustedInfo = fInfo; + if (ExifOrientationBehavior::kRespect == fOrientationBehavior + && SkPixmapPriv::ShouldSwapWidthHeight(fCodec->getOrigin())) { + adjustedInfo = SkPixmapPriv::SwapWidthHeight(adjustedInfo); + } + AndroidOptions defaultOptions; if (!options) { options = &defaultOptions; } else if (options->fSubset) { - if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) { + if (!is_valid_subset(*options->fSubset, adjustedInfo.dimensions())) { return SkCodec::kInvalidParameters; } - if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) { + if (SkIRect::MakeSize(adjustedInfo.dimensions()) == *options->fSubset) { // The caller wants the whole thing, rather than a subset. Modify // the AndroidOptions passed to onGetAndroidPixels to not specify // a subset. @@ -352,7 +388,27 @@ SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* } } - return this->onGetAndroidPixels(info, pixels, rowBytes, *options); + if (ExifOrientationBehavior::kIgnore == fOrientationBehavior) { + return this->onGetAndroidPixels(requestInfo, requestPixels, requestRowBytes, *options); + } + + SkCodec::Result result; + auto decode = [this, options, &result](const SkPixmap& pm) { + result = this->onGetAndroidPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), *options); + return acceptable_result(result); + }; + + SkPixmap dst(requestInfo, requestPixels, requestRowBytes); + if (SkPixmapPriv::Orient(dst, fCodec->getOrigin(), decode)) { + return result; + } + + // Orient returned false. If onGetAndroidPixels succeeded, then Orient failed internally. + if (acceptable_result(result)) { + return SkCodec::kInternalError; + } + + return result; } SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels, |