aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/codec
diff options
context:
space:
mode:
authorGravatar Leon Scroggins III <scroggo@google.com>2018-01-16 15:01:17 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-16 21:23:08 +0000
commit07a722cdcf064fca22213dc06a433dd82f080c23 (patch)
tree8d8e7de91637af359b9ff8649c8bed317019cbf7 /src/codec
parent539c6f5c92c2a4f04816d562c3d23556a35a2e98 (diff)
Add SkAndroidCodec::computeSampledSize
Bug: b/63909536 Android's ImageDecoder API takes as input an arbitrary width and height to scale the image to. Internally, this uses SkAndroidCodec to sample, and then (if not a perfect match) scales to the desired size with drawing. computeSampledSize is a modified version of what ImageDecoder currently does to convert from arbitrary dimensions to a sampleSize. Moving it here allows it to be shared by SkAnimatedImage. The modified version also corrects two bugs: - a client using the dimensions returned by getSampledDimensions previously may have resulted in ImageDecoder decoding to a larger size and then scaling it. (example found in tests: dog.jpg is 180 x 180. getSampledDimensions(8) returns 23 x 23, but the old method resulted in using sampleSize of 7 and downscaling the resulting 25 x 25 image.) - recompute the sampleSize based on the size returned by getSampledDimensions. Change-Id: I022040e8bac31c20988903a0452257f7ae902bc7 Reviewed-on: https://skia-review.googlesource.com/94620 Reviewed-by: Derek Sollenberger <djsollen@google.com> Commit-Queue: Leon Scroggins <scroggo@google.com>
Diffstat (limited to 'src/codec')
-rw-r--r--src/codec/SkAndroidCodec.cpp94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/codec/SkAndroidCodec.cpp b/src/codec/SkAndroidCodec.cpp
index a7ffa4e93b..486257f9a3 100644
--- a/src/codec/SkAndroidCodec.cpp
+++ b/src/codec/SkAndroidCodec.cpp
@@ -186,6 +186,100 @@ sk_sp<SkColorSpace> SkAndroidCodec::computeOutputColorSpace(SkColorType outputCo
}
}
+static bool supports_any_down_scale(const SkCodec* codec) {
+ return codec->getEncodedFormat() == SkEncodedImageFormat::kWEBP;
+}
+
+// There are a variety of ways two SkISizes could be compared. This method
+// returns true if either dimensions of a is < that of b.
+// computeSampleSize also uses the opposite, which means that both
+// dimensions of a >= b.
+static inline bool smaller_than(const SkISize& a, const SkISize& b) {
+ return a.width() < b.width() || a.height() < b.height();
+}
+
+// Both dimensions of a > that of b.
+static inline bool strictly_bigger_than(const SkISize& a, const SkISize& b) {
+ return a.width() > b.width() && a.height() > b.height();
+}
+
+int SkAndroidCodec::computeSampleSize(SkISize* desiredSize) const {
+ SkASSERT(desiredSize);
+
+ if (!desiredSize || *desiredSize == fInfo.dimensions()) {
+ return 1;
+ }
+
+ if (smaller_than(fInfo.dimensions(), *desiredSize)) {
+ *desiredSize = fInfo.dimensions();
+ return 1;
+ }
+
+ // Handle bad input:
+ if (desiredSize->width() < 1 || desiredSize->height() < 1) {
+ *desiredSize = SkISize::Make(std::max(1, desiredSize->width()),
+ std::max(1, desiredSize->height()));
+ }
+
+ if (supports_any_down_scale(fCodec.get())) {
+ return 1;
+ }
+
+ int sampleX = fInfo.width() / desiredSize->width();
+ int sampleY = fInfo.height() / desiredSize->height();
+ int sampleSize = std::min(sampleX, sampleY);
+ auto computedSize = this->getSampledDimensions(sampleSize);
+ if (computedSize == *desiredSize) {
+ return sampleSize;
+ }
+
+ if (computedSize == fInfo.dimensions() || sampleSize == 1) {
+ // Cannot downscale
+ *desiredSize = computedSize;
+ return 1;
+ }
+
+ if (strictly_bigger_than(computedSize, *desiredSize)) {
+ // See if there is a tighter fit.
+ while (true) {
+ auto smaller = this->getSampledDimensions(sampleSize + 1);
+ if (smaller == *desiredSize) {
+ return sampleSize + 1;
+ }
+ if (smaller == computedSize || smaller_than(smaller, *desiredSize)) {
+ // Cannot get any smaller without being smaller than desired.
+ *desiredSize = computedSize;
+ return sampleSize;
+ }
+
+ sampleSize++;
+ computedSize = smaller;
+ }
+
+ SkASSERT(false);
+ }
+
+ if (!smaller_than(computedSize, *desiredSize)) {
+ // This means one of the computed dimensions is equal to desired, and
+ // the other is bigger. This is as close as we can get.
+ *desiredSize = computedSize;
+ return sampleSize;
+ }
+
+ // computedSize is too small. Make it larger.
+ while (sampleSize > 2) {
+ auto bigger = this->getSampledDimensions(sampleSize - 1);
+ if (bigger == *desiredSize || !smaller_than(bigger, *desiredSize)) {
+ *desiredSize = bigger;
+ return sampleSize - 1;
+ }
+ sampleSize--;
+ }
+
+ *desiredSize = fInfo.dimensions();
+ return 1;
+}
+
SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
if (!is_valid_sample_size(sampleSize)) {
return {0, 0};