aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar scroggo <scroggo@chromium.org>2015-07-22 07:16:20 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-07-22 07:16:20 -0700
commitb636b45971bc5e64e3b103169577cbc874bc064d (patch)
tree17579347d627ede9bdc4e675b22202f4191190f9 /src
parent8c0144ccb17220db9d5140ef5ee85d5bc7837513 (diff)
Add the ability to decode a subset to SkCodec
This allows codecs that support subsets natively (i.e. WEBP) to do so. Add a field on SkCodec::Options representing the subset. Add a method on SkCodec to find a valid subset which approximately matches a desired subset. Implement subset decodes in SkWebpCodec. Add a test in DM for decoding subsets. Notice that we only start on even boundaries. This is due to the way libwebp's API works. SkWEBPImageDecoder does not take this into account, which results in visual artifacts. FIXME: Subsets with scaling are not pixel identical, but close. (This may be fine, though - they are not perceptually different. We'll just need to mark another set of images in gold as valid, once https://skbug.com/4038 is fixed, so we can tests scaled webp without generating new images on each run.) Review URL: https://codereview.chromium.org/1240143002
Diffstat (limited to 'src')
-rw-r--r--src/codec/SkCodec_libbmp.cpp4
-rw-r--r--src/codec/SkCodec_libgif.cpp4
-rw-r--r--src/codec/SkCodec_libico.cpp4
-rw-r--r--src/codec/SkCodec_libpng.cpp4
-rw-r--r--src/codec/SkCodec_wbmp.cpp6
-rw-r--r--src/codec/SkJpegCodec.cpp5
-rw-r--r--src/codec/SkWebpCodec.cpp64
-rw-r--r--src/codec/SkWebpCodec.h2
8 files changed, 87 insertions, 6 deletions
diff --git a/src/codec/SkCodec_libbmp.cpp b/src/codec/SkCodec_libbmp.cpp
index 3ac4b0b8ab..bd5d2ca7c5 100644
--- a/src/codec/SkCodec_libbmp.cpp
+++ b/src/codec/SkCodec_libbmp.cpp
@@ -585,6 +585,10 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
return kCouldNotRewind;
}
}
+ if (opts.fSubset) {
+ // Subsets are not supported.
+ return kUnimplemented;
+ }
if (dstInfo.dimensions() != this->getInfo().dimensions()) {
SkCodecPrintf("Error: scaling not supported.\n");
return kInvalidScale;
diff --git a/src/codec/SkCodec_libgif.cpp b/src/codec/SkCodec_libgif.cpp
index fb578f2bea..9b15151f10 100644
--- a/src/codec/SkCodec_libgif.cpp
+++ b/src/codec/SkCodec_libgif.cpp
@@ -257,6 +257,10 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
}
// Check for valid input parameters
+ if (opts.fSubset) {
+ // Subsets are not supported.
+ return kUnimplemented;
+ }
if (dstInfo.dimensions() != this->getInfo().dimensions()) {
return gif_error("Scaling not supported.\n", kInvalidScale);
}
diff --git a/src/codec/SkCodec_libico.cpp b/src/codec/SkCodec_libico.cpp
index 97404afed0..7df4879442 100644
--- a/src/codec/SkCodec_libico.cpp
+++ b/src/codec/SkCodec_libico.cpp
@@ -229,6 +229,10 @@ SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo,
void* dst, size_t dstRowBytes,
const Options& opts, SkPMColor* ct,
int* ptr) {
+ if (opts.fSubset) {
+ // Subsets are not supported.
+ return kUnimplemented;
+ }
// We return invalid scale if there is no candidate image with matching
// dimensions.
Result result = kInvalidScale;
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index 7f9aeaa091..553233de12 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -517,6 +517,10 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
if (!conversion_possible(requestedInfo, this->getInfo())) {
return kInvalidConversion;
}
+ if (options.fSubset) {
+ // Subsets are not supported.
+ return kUnimplemented;
+ }
if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
return kInvalidScale;
}
diff --git a/src/codec/SkCodec_wbmp.cpp b/src/codec/SkCodec_wbmp.cpp
index 9709a689b1..35ac808219 100644
--- a/src/codec/SkCodec_wbmp.cpp
+++ b/src/codec/SkCodec_wbmp.cpp
@@ -103,7 +103,7 @@ SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const {
SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
void* pixels,
size_t rowBytes,
- const Options&,
+ const Options& options,
SkPMColor ctable[],
int* ctableCount) {
SkCodec::RewindState rewindState = this->rewindIfNeeded();
@@ -112,6 +112,10 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
} else if (rewindState == kRewound_RewindState) {
(void)read_header(this->stream(), NULL);
}
+ if (options.fSubset) {
+ // Subsets are not supported.
+ return kUnimplemented;
+ }
if (info.dimensions() != this->getInfo().dimensions()) {
return kInvalidScale;
}
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index 28e1e12bfc..5acc0b396c 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -308,6 +308,11 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
return fDecoderMgr->returnFailure("could not rewind stream", kCouldNotRewind);
}
+ if (options.fSubset) {
+ // Subsets are not supported.
+ return kUnimplemented;
+ }
+
// Get a pointer to the decompress info since we will use it quite frequently
jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index 32a8b78b14..fea557d21e 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -125,8 +125,26 @@ static WEBP_CSP_MODE webp_decode_mode(SkColorType ct, bool premultiply) {
// is arbitrary.
static const size_t BUFFER_SIZE = 4096;
+bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const {
+ if (!desiredSubset) {
+ return false;
+ }
+
+ SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions());
+ if (!desiredSubset->intersect(bounds)) {
+ return false;
+ }
+
+ // As stated below, libwebp snaps to even left and top. Make sure top and left are even, so we
+ // decode this exact subset.
+ // Leave right and bottom unmodified, so we suggest a slightly larger subset than requested.
+ desiredSubset->fLeft = (desiredSubset->fLeft >> 1) << 1;
+ desiredSubset->fTop = (desiredSubset->fTop >> 1) << 1;
+ return true;
+}
+
SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
- const Options&, SkPMColor*, int*) {
+ const Options& options, SkPMColor*, int*) {
switch (this->rewindIfNeeded()) {
case kCouldNotRewind_RewindState:
return kCouldNotRewind;
@@ -153,12 +171,48 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
// Free any memory associated with the buffer. Must be called last, so we declare it first.
SkAutoTCallVProc<WebPDecBuffer, WebPFreeDecBuffer> autoFree(&(config.output));
- SkISize dimensions = dstInfo.dimensions();
- if (this->getInfo().dimensions() != dimensions) {
+ SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions());
+ if (options.fSubset) {
+ // Caller is requesting a subset.
+ if (!bounds.contains(*options.fSubset)) {
+ // The subset is out of bounds.
+ return kInvalidParameters;
+ }
+
+ bounds = *options.fSubset;
+
+ // This is tricky. libwebp snaps the top and left to even values. We could let libwebp
+ // do the snap, and return a subset which is a different one than requested. The problem
+ // with that approach is that the caller may try to stitch subsets together, and if we
+ // returned different subsets than requested, there would be artifacts at the boundaries.
+ // Instead, we report that we cannot support odd values for top and left..
+ if (!SkIsAlign2(bounds.fLeft) || !SkIsAlign2(bounds.fTop)) {
+ return kInvalidParameters;
+ }
+
+#ifdef SK_DEBUG
+ {
+ // Make a copy, since getValidSubset can change its input.
+ SkIRect subset(bounds);
+ // That said, getValidSubset should *not* change its input, in this case; otherwise
+ // getValidSubset does not match the actual subsets we can do.
+ SkASSERT(this->getValidSubset(&subset) && subset == bounds);
+ }
+#endif
+
+ config.options.use_cropping = 1;
+ config.options.crop_left = bounds.fLeft;
+ config.options.crop_top = bounds.fTop;
+ config.options.crop_width = bounds.width();
+ config.options.crop_height = bounds.height();
+ }
+
+ SkISize dstDimensions = dstInfo.dimensions();
+ if (bounds.size() != dstDimensions) {
// Caller is requesting scaling.
config.options.use_scaling = 1;
- config.options.scaled_width = dimensions.width();
- config.options.scaled_height = dimensions.height();
+ config.options.scaled_width = dstDimensions.width();
+ config.options.scaled_height = dstDimensions.height();
}
config.output.colorspace = webp_decode_mode(dstInfo.colorType(),
diff --git a/src/codec/SkWebpCodec.h b/src/codec/SkWebpCodec.h
index 9ea6a94ecb..1fd3acbd16 100644
--- a/src/codec/SkWebpCodec.h
+++ b/src/codec/SkWebpCodec.h
@@ -30,6 +30,8 @@ protected:
}
SkISize onGetScaledDimensions(float desiredScale) const override;
+
+ bool onGetValidSubset(SkIRect* /* desiredSubset */) const override;
private:
SkWebpCodec(const SkImageInfo&, SkStream*);