aboutsummaryrefslogtreecommitdiffhomepage
path: root/dm
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 /dm
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 'dm')
-rw-r--r--dm/DM.cpp5
-rw-r--r--dm/DMSrcSink.cpp77
-rw-r--r--dm/DMSrcSink.h1
3 files changed, 83 insertions, 0 deletions
diff --git a/dm/DM.cpp b/dm/DM.cpp
index dd072dcec6..d472be69d9 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -257,6 +257,11 @@ static void push_codec_srcs(Path path) {
CodecSrc::kGetFromCanvas_DstColorType, scale));
push_src("image", "stripe", new CodecSrc(path, CodecSrc::kStripe_Mode,
CodecSrc::kGetFromCanvas_DstColorType, scale));
+ // Note: The only codec which supports subsets natively is SkWebpCodec, which will never
+ // report kIndex_8 or kGray_8, so there is no need to test kSubset_mode with those color
+ // types specifically requested.
+ push_src("image", "codec_subset", new CodecSrc(path, CodecSrc::kSubset_Mode,
+ CodecSrc::kGetFromCanvas_DstColorType, scale));
}
}
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 38597b6946..fd1331366d 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -355,6 +355,83 @@ Error CodecSrc::draw(SkCanvas* canvas) const {
canvas->drawBitmap(bitmap, 0, 0);
break;
}
+ case kSubset_Mode: {
+ // Arbitrarily choose a divisor.
+ int divisor = 2;
+ // Total width/height of the image.
+ const int W = codec->getInfo().width();
+ const int H = codec->getInfo().height();
+ if (divisor > W || divisor > H) {
+ return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
+ "for %s with dimensions (%d x %d)", divisor,
+ fPath.c_str(), W, H));
+ }
+ // subset dimensions
+ // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
+ const int w = SkAlign2(W / divisor);
+ const int h = SkAlign2(H / divisor);
+ SkIRect subset;
+ SkCodec::Options opts;
+ opts.fSubset = &subset;
+ SkBitmap subsetBm;
+ // We will reuse pixel memory from bitmap.
+ void* pixels = bitmap.getPixels();
+ // Keep track of left and top (for drawing subsetBm into canvas). We could use
+ // fScale * x and fScale * y, but we want integers such that the next subset will start
+ // where the last one ended. So we'll add decodeInfo.width() and height().
+ int left = 0;
+ for (int x = 0; x < W; x += w) {
+ int top = 0;
+ for (int y = 0; y < H; y+= h) {
+ // Do not make the subset go off the edge of the image.
+ const int preScaleW = SkTMin(w, W - x);
+ const int preScaleH = SkTMin(h, H - y);
+ subset.setXYWH(x, y, preScaleW, preScaleH);
+ // And scale
+ // FIXME: Should we have a version of getScaledDimensions that takes a subset
+ // into account?
+ decodeInfo = decodeInfo.makeWH(SkScalarRoundToInt(preScaleW * fScale),
+ SkScalarRoundToInt(preScaleH * fScale));
+ size_t rowBytes = decodeInfo.minRowBytes();
+ if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, colorTable.get(),
+ NULL, NULL)) {
+ return SkStringPrintf("could not install pixels for %s.", fPath.c_str());
+ }
+ const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
+ &opts, colorPtr, colorCountPtr);
+ switch (result) {
+ case SkCodec::kSuccess:
+ case SkCodec::kIncompleteInput:
+ break;
+ case SkCodec::kInvalidConversion:
+ if (0 == (x|y)) {
+ // First subset is okay to return unimplemented.
+ return Error::Nonfatal("Incompatible colortype conversion");
+ }
+ // If the first subset succeeded, a later one should not fail.
+ // fall through to failure
+ case SkCodec::kUnimplemented:
+ if (0 == (x|y)) {
+ // First subset is okay to return unimplemented.
+ return Error::Nonfatal("subset codec not supported");
+ }
+ // If the first subset succeeded, why would a later one fail?
+ // fall through to failure
+ default:
+ return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
+ "from %s with dimensions (%d x %d)\t error %d",
+ x, y, decodeInfo.width(), decodeInfo.height(),
+ fPath.c_str(), W, H, result);
+ }
+ canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToScalar(top));
+ // translate by the scaled height.
+ top += decodeInfo.height();
+ }
+ // translate by the scaled width.
+ left += decodeInfo.width();
+ }
+ return "";
+ }
}
return "";
}
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index b7c28edf00..b80c7c9a4b 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -99,6 +99,7 @@ public:
kScanline_Mode,
kScanline_Subset_Mode,
kStripe_Mode, // Tests the skipping of scanlines
+ kSubset_Mode, // For codecs that support subsets directly.
};
enum DstColorType {
kGetFromCanvas_DstColorType,