Index: dm/DMSrcSink.cpp |
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp |
index 38597b6946994c06d8cc24971dc018163ff41b14..fd1331366dd34b07761e57e5c5e91e13dc4cea9f 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 = ⊂ |
+ 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 ""; |
} |