aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/android/SkBitmapRegionCanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/SkBitmapRegionCanvas.cpp')
-rw-r--r--src/android/SkBitmapRegionCanvas.cpp140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/android/SkBitmapRegionCanvas.cpp b/src/android/SkBitmapRegionCanvas.cpp
new file mode 100644
index 0000000000..bac5dc1ffc
--- /dev/null
+++ b/src/android/SkBitmapRegionCanvas.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapRegionCanvas.h"
+#include "SkBitmapRegionDecoderPriv.h"
+#include "SkCanvas.h"
+#include "SkCodecPriv.h"
+
+SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder)
+ : INHERITED(decoder->getInfo().width(), decoder->getInfo().height())
+ , fDecoder(decoder)
+{}
+
+bool SkBitmapRegionCanvas::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType,
+ bool requireUnpremul) {
+ // Reject color types not supported by this method
+ if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) {
+ SkCodecPrintf("Error: Color type not supported.\n");
+ return false;
+ }
+
+ // Reject requests for unpremultiplied alpha
+ if (requireUnpremul) {
+ SkCodecPrintf("Error: Alpha type not supported.\n");
+ return false;
+ }
+ SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType();
+ if (kUnpremul_SkAlphaType == dstAlphaType) {
+ dstAlphaType = kPremul_SkAlphaType;
+ }
+
+ // FIXME: Can we add checks and support kIndex8 or unpremultiplied alpha in special cases?
+
+ // Fix the input sampleSize if necessary.
+ if (sampleSize < 1) {
+ sampleSize = 1;
+ }
+
+ // The size of the output bitmap is determined by the size of the
+ // requested subset, not by the size of the intersection of the subset
+ // and the image dimensions.
+ // If inputX is negative, we will need to place decoded pixels into the
+ // output bitmap starting at a left offset. Call this outX.
+ // If outX is non-zero, subsetX must be zero.
+ // If inputY is negative, we will need to place decoded pixels into the
+ // output bitmap starting at a top offset. Call this outY.
+ // If outY is non-zero, subsetY must be zero.
+ int outX;
+ int outY;
+ SkIRect subset = desiredSubset;
+ SubsetType type = adjust_subset_rect(fDecoder->getInfo().dimensions(), &subset, &outX, &outY);
+ if (SubsetType::kOutside_SubsetType == type) {
+ return false;
+ }
+
+ // Create the image info for the decode
+ SkImageInfo decodeInfo = SkImageInfo::Make(this->width(), this->height(),
+ dstColorType, dstAlphaType);
+
+ // Start the scanline decoder
+ SkCodec::Result r = fDecoder->startScanlineDecode(decodeInfo);
+ if (SkCodec::kSuccess != r) {
+ SkCodecPrintf("Error: Could not start scanline decoder.\n");
+ return false;
+ }
+
+ // Allocate a bitmap for the unscaled decode
+ SkBitmap tmp;
+ SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), subset.height());
+ if (!tmp.tryAllocPixels(tmpInfo)) {
+ SkCodecPrintf("Error: Could not allocate pixels.\n");
+ return false;
+ }
+
+ // Skip the unneeded rows
+ if (!fDecoder->skipScanlines(subset.y())) {
+ SkCodecPrintf("Error: Failed to skip scanlines.\n");
+ return false;
+ }
+
+ // Decode the necessary rows
+ fDecoder->getScanlines(tmp.getAddr(0, 0), subset.height(), tmp.rowBytes());
+
+ // Calculate the size of the output
+ const int outWidth = get_scaled_dimension(desiredSubset.width(), sampleSize);
+ const int outHeight = get_scaled_dimension(desiredSubset.height(), sampleSize);
+
+ // Initialize the destination bitmap
+ SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight);
+ bitmap->setInfo(dstInfo, dstInfo.minRowBytes());
+ if (!bitmap->tryAllocPixels(allocator, nullptr)) {
+ SkCodecPrintf("Error: Could not allocate pixels.\n");
+ return false;
+ }
+
+ // Zero the bitmap if the region is not completely within the image.
+ // TODO (msarett): Can we make this faster by implementing it to only
+ // zero parts of the image that we won't overwrite with
+ // pixels?
+ if (SubsetType::kPartiallyInside_SubsetType == type) {
+ SkCodec::ZeroInitialized zeroInit = allocator ? allocator->zeroInit() :
+ SkCodec::kNo_ZeroInitialized;
+ if (SkCodec::kNo_ZeroInitialized == zeroInit) {
+ bitmap->eraseColor(0);
+ }
+ }
+
+ // Use a canvas to crop and scale to the destination bitmap
+ SkCanvas canvas(*bitmap);
+ // TODO (msarett): Maybe we can take advantage of the fact that SkRect uses floats?
+ SkRect src = SkRect::MakeXYWH((SkScalar) subset.x(), (SkScalar) 0,
+ (SkScalar) subset.width(), (SkScalar) subset.height());
+ SkRect dst = SkRect::MakeXYWH((SkScalar) (outX / sampleSize), (SkScalar) (outY / sampleSize),
+ (SkScalar) get_scaled_dimension(subset.width(), sampleSize),
+ (SkScalar) get_scaled_dimension(subset.height(), sampleSize));
+ SkPaint paint;
+ // Overwrite the dst with the src pixels
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ // TODO (msarett): Test multiple filter qualities. kNone is the default.
+ canvas.drawBitmapRect(tmp, src, dst, &paint);
+
+ return true;
+}
+
+bool SkBitmapRegionCanvas::conversionSupported(SkColorType colorType) {
+ // SkCanvas does not draw to these color types.
+ if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) {
+ return false;
+ }
+
+ // FIXME: Call virtual function when it lands.
+ SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fDecoder->getInfo().alphaType(),
+ fDecoder->getInfo().profileType());
+ return conversion_possible(info, fDecoder->getInfo());
+}