blob: c7c42bd9a25c0bfa759178e9c3b04e6dad0bfff8 [file] [log] [blame]
msaretta5783ae2015-09-08 15:35:32 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkBitmapRegionCanvas.h"
msarett84a80652015-11-10 15:49:46 -08009#include "SkBitmapRegionDecoderPriv.h"
msaretta5783ae2015-09-08 15:35:32 -070010#include "SkCanvas.h"
msarett04965c62015-10-12 10:24:38 -070011#include "SkCodecPriv.h"
msaretta5783ae2015-09-08 15:35:32 -070012
scroggo46c57472015-09-30 08:57:13 -070013SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder)
msaretta5783ae2015-09-08 15:35:32 -070014 : INHERITED(decoder->getInfo().width(), decoder->getInfo().height())
15 , fDecoder(decoder)
16{}
17
msarettcb8d7192015-11-11 13:30:43 -080018bool SkBitmapRegionCanvas::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator,
msarett35e5d1b2015-10-27 12:50:25 -070019 const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType,
20 bool requireUnpremul) {
msarett9a0e3462015-12-11 07:38:50 -080021
msaretta5783ae2015-09-08 15:35:32 -070022 // Reject color types not supported by this method
23 if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) {
msarett04965c62015-10-12 10:24:38 -070024 SkCodecPrintf("Error: Color type not supported.\n");
msarett35e5d1b2015-10-27 12:50:25 -070025 return false;
msaretta5783ae2015-09-08 15:35:32 -070026 }
27
msarett35e5d1b2015-10-27 12:50:25 -070028 // Reject requests for unpremultiplied alpha
29 if (requireUnpremul) {
30 SkCodecPrintf("Error: Alpha type not supported.\n");
31 return false;
32 }
33 SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType();
34 if (kUnpremul_SkAlphaType == dstAlphaType) {
35 dstAlphaType = kPremul_SkAlphaType;
36 }
37
msarett26ad17b2015-10-22 07:29:19 -070038 // Fix the input sampleSize if necessary.
39 if (sampleSize < 1) {
40 sampleSize = 1;
41 }
msaretta5783ae2015-09-08 15:35:32 -070042
43 // The size of the output bitmap is determined by the size of the
msarett26ad17b2015-10-22 07:29:19 -070044 // requested subset, not by the size of the intersection of the subset
45 // and the image dimensions.
46 // If inputX is negative, we will need to place decoded pixels into the
47 // output bitmap starting at a left offset. Call this outX.
48 // If outX is non-zero, subsetX must be zero.
49 // If inputY is negative, we will need to place decoded pixels into the
50 // output bitmap starting at a top offset. Call this outY.
51 // If outY is non-zero, subsetY must be zero.
msaretta5783ae2015-09-08 15:35:32 -070052 int outX;
msaretta5783ae2015-09-08 15:35:32 -070053 int outY;
msarett35e5d1b2015-10-27 12:50:25 -070054 SkIRect subset = desiredSubset;
msarett26ad17b2015-10-22 07:29:19 -070055 SubsetType type = adjust_subset_rect(fDecoder->getInfo().dimensions(), &subset, &outX, &outY);
56 if (SubsetType::kOutside_SubsetType == type) {
msarett35e5d1b2015-10-27 12:50:25 -070057 return false;
msaretta5783ae2015-09-08 15:35:32 -070058 }
59
60 // Create the image info for the decode
msaretta5783ae2015-09-08 15:35:32 -070061 SkImageInfo decodeInfo = SkImageInfo::Make(this->width(), this->height(),
62 dstColorType, dstAlphaType);
msarett26ad17b2015-10-22 07:29:19 -070063
msaretta5783ae2015-09-08 15:35:32 -070064 // Start the scanline decoder
scroggo46c57472015-09-30 08:57:13 -070065 SkCodec::Result r = fDecoder->startScanlineDecode(decodeInfo);
msaretta5783ae2015-09-08 15:35:32 -070066 if (SkCodec::kSuccess != r) {
msarett04965c62015-10-12 10:24:38 -070067 SkCodecPrintf("Error: Could not start scanline decoder.\n");
msarett35e5d1b2015-10-27 12:50:25 -070068 return false;
msaretta5783ae2015-09-08 15:35:32 -070069 }
70
71 // Allocate a bitmap for the unscaled decode
72 SkBitmap tmp;
msarett26ad17b2015-10-22 07:29:19 -070073 SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), subset.height());
msaretta5783ae2015-09-08 15:35:32 -070074 if (!tmp.tryAllocPixels(tmpInfo)) {
msarett04965c62015-10-12 10:24:38 -070075 SkCodecPrintf("Error: Could not allocate pixels.\n");
msarett35e5d1b2015-10-27 12:50:25 -070076 return false;
msaretta5783ae2015-09-08 15:35:32 -070077 }
78
79 // Skip the unneeded rows
msarett26ad17b2015-10-22 07:29:19 -070080 if (!fDecoder->skipScanlines(subset.y())) {
msarett04965c62015-10-12 10:24:38 -070081 SkCodecPrintf("Error: Failed to skip scanlines.\n");
msarett35e5d1b2015-10-27 12:50:25 -070082 return false;
msaretta5783ae2015-09-08 15:35:32 -070083 }
84
85 // Decode the necessary rows
msarett26ad17b2015-10-22 07:29:19 -070086 fDecoder->getScanlines(tmp.getAddr(0, 0), subset.height(), tmp.rowBytes());
msaretta5783ae2015-09-08 15:35:32 -070087
88 // Calculate the size of the output
msarett35e5d1b2015-10-27 12:50:25 -070089 const int outWidth = get_scaled_dimension(desiredSubset.width(), sampleSize);
90 const int outHeight = get_scaled_dimension(desiredSubset.height(), sampleSize);
msaretta5783ae2015-09-08 15:35:32 -070091
92 // Initialize the destination bitmap
msaretta5783ae2015-09-08 15:35:32 -070093 SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight);
msarett35e5d1b2015-10-27 12:50:25 -070094 bitmap->setInfo(dstInfo, dstInfo.minRowBytes());
95 if (!bitmap->tryAllocPixels(allocator, nullptr)) {
msarett04965c62015-10-12 10:24:38 -070096 SkCodecPrintf("Error: Could not allocate pixels.\n");
msarett35e5d1b2015-10-27 12:50:25 -070097 return false;
msaretta5783ae2015-09-08 15:35:32 -070098 }
99
100 // Zero the bitmap if the region is not completely within the image.
101 // TODO (msarett): Can we make this faster by implementing it to only
102 // zero parts of the image that we won't overwrite with
103 // pixels?
msarett26ad17b2015-10-22 07:29:19 -0700104 if (SubsetType::kPartiallyInside_SubsetType == type) {
msarettcb8d7192015-11-11 13:30:43 -0800105 SkCodec::ZeroInitialized zeroInit = allocator ? allocator->zeroInit() :
106 SkCodec::kNo_ZeroInitialized;
107 if (SkCodec::kNo_ZeroInitialized == zeroInit) {
108 bitmap->eraseColor(0);
109 }
msaretta5783ae2015-09-08 15:35:32 -0700110 }
111
112 // Use a canvas to crop and scale to the destination bitmap
113 SkCanvas canvas(*bitmap);
114 // TODO (msarett): Maybe we can take advantage of the fact that SkRect uses floats?
msarett26ad17b2015-10-22 07:29:19 -0700115 SkRect src = SkRect::MakeXYWH((SkScalar) subset.x(), (SkScalar) 0,
116 (SkScalar) subset.width(), (SkScalar) subset.height());
msaretta5783ae2015-09-08 15:35:32 -0700117 SkRect dst = SkRect::MakeXYWH((SkScalar) (outX / sampleSize), (SkScalar) (outY / sampleSize),
msarett26ad17b2015-10-22 07:29:19 -0700118 (SkScalar) get_scaled_dimension(subset.width(), sampleSize),
119 (SkScalar) get_scaled_dimension(subset.height(), sampleSize));
msaretta5783ae2015-09-08 15:35:32 -0700120 SkPaint paint;
121 // Overwrite the dst with the src pixels
122 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
123 // TODO (msarett): Test multiple filter qualities. kNone is the default.
124 canvas.drawBitmapRect(tmp, src, dst, &paint);
125
msarett35e5d1b2015-10-27 12:50:25 -0700126 return true;
msaretta5783ae2015-09-08 15:35:32 -0700127}
msarett04965c62015-10-12 10:24:38 -0700128
129bool SkBitmapRegionCanvas::conversionSupported(SkColorType colorType) {
130 // SkCanvas does not draw to these color types.
131 if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) {
132 return false;
133 }
134
135 // FIXME: Call virtual function when it lands.
136 SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fDecoder->getInfo().alphaType(),
137 fDecoder->getInfo().profileType());
138 return conversion_possible(info, fDecoder->getInfo());
139}