OLD | NEW |
---|---|
(Empty) | |
1 /* | |
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 "SkBitmapRegionCodec.h" | |
9 #include "SkCanvas.h" | |
10 #include "SkCodec.h" | |
11 #include "SkCodecPriv.h" | |
12 #include "SkCodecTools.h" | |
13 | |
14 SkBitmapRegionCodec::SkBitmapRegionCodec(SkCodec* codec) | |
15 : INHERITED(codec->getInfo().width(), codec->getInfo().height()) | |
16 , fCodec(codec) | |
17 {} | |
18 | |
19 /* | |
20 * Three differences from the Android version: | |
21 * Returns a skia bitmap instead of an Android bitmap. | |
22 * Android version attempts to reuse a recycled bitmap. | |
23 * Removed the options object and used parameters for color type and sample size. | |
24 */ | |
25 SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWid th, int inputHeight, | |
26 int sampleSize, SkColorType dstColorType) { | |
27 | |
28 // Fix the input sampleSize if necessary. | |
29 if (sampleSize < 1) { | |
30 sampleSize = 1; | |
31 } | |
32 | |
33 // The client may not necessarily request a region that is fully within | |
34 // the image. We may need to do some calculation to determine what part | |
35 // of the image to decode. | |
36 | |
37 // The left offset of the portion of the image we want, where zero | |
38 // indicates the left edge of the image. | |
39 int imageSubsetX; | |
40 | |
41 // The size of the output bitmap is determined by the size of the | |
42 // requested region, not by the size of the intersection of the region | |
43 // and the image dimensions. If inputX is negative, we will need to | |
44 // place decoded pixels into the output bitmap starting at a left offset. | |
45 // If this is non-zero, imageSubsetX must be zero. | |
46 int outX; | |
47 | |
48 // The width of the portion of the image that we will write to the output | |
49 // bitmap. If the region is not fully contained within the image, this | |
50 // will not be the same as inputWidth. | |
51 int imageSubsetWidth; | |
52 bool imageContainsEntireSubset = set_subset_region(inputX, inputWidth, this- >width(), | |
53 &imageSubsetX, &outX, &imageSubsetWidth); | |
54 | |
55 // The top offset of the portion of the image we want, where zero | |
56 // indicates the top edge of the image. | |
57 int imageSubsetY; | |
58 | |
59 // The size of the output bitmap is determined by the size of the | |
60 // requested region, not by the size of the intersection of the region | |
61 // and the image dimensions. If inputY is negative, we will need to | |
62 // place decoded pixels into the output bitmap starting at a top offset. | |
63 // If this is non-zero, imageSubsetY must be zero. | |
64 int outY; | |
65 | |
66 // The height of the portion of the image that we will write to the output | |
67 // bitmap. If the region is not fully contained within the image, this | |
68 // will not be the same as inputHeight. | |
69 int imageSubsetHeight; | |
70 imageContainsEntireSubset &= set_subset_region(inputY, inputHeight, this->he ight(), | |
71 &imageSubsetY, &outY, &imageSubsetHeight); | |
72 | |
73 if (imageSubsetWidth <= 0 || imageSubsetHeight <= 0) { | |
74 SkCodecPrintf("Error: Region must intersect part of the image.\n"); | |
75 return nullptr; | |
76 } | |
77 | |
78 // Ask the codec for a scaled subset | |
msarett
2015/10/12 18:42:36
Up until here, this implementation is the same as
scroggo
2015/10/12 19:18:09
Would it be possible to pull out a common function
msarett
2015/10/21 19:15:09
I think this is a little cleaner. Let me know wha
| |
79 SkIRect subset = SkIRect::MakeXYWH(imageSubsetX, imageSubsetY, imageSubsetWi dth, | |
80 imageSubsetHeight); | |
81 SkISize scaledDimensions; | |
82 SkIRect scaledSubset; | |
83 SkCodec::Options options; | |
84 options.fSubset = ⊂ | |
85 options.fScaledDimensions = &scaledDimensions; | |
86 options.fScaledSubset = &scaledSubset; | |
87 if (!fCodec->getScaledSubsetDimensions(get_scale_from_sample_size(sampleSize ), options)) { | |
88 SkCodecPrintf("Error: Could not scale.\n"); | |
89 return nullptr; | |
90 } | |
91 | |
92 // Create the image info for the decode | |
93 SkAlphaType dstAlphaType = fCodec->getInfo().alphaType(); | |
94 if (kUnpremul_SkAlphaType == dstAlphaType) { | |
95 dstAlphaType = kPremul_SkAlphaType; | |
96 } | |
97 SkImageInfo decodeInfo = SkImageInfo::Make(scaledSubset.width(), scaledSubse t.height(), | |
98 dstColorType, dstAlphaType); | |
99 | |
100 // Construct a color table for the decode if necessary | |
101 SkAutoTUnref<SkColorTable> colorTable(nullptr); | |
102 SkPMColor* colorPtr = nullptr; | |
103 int* colorCountPtr = nullptr; | |
104 int maxColors = 256; | |
105 SkPMColor colors[maxColors]; | |
106 if (kIndex_8_SkColorType == dstColorType) { | |
107 // TODO (msarett): This performs a copy that is unnecessary since | |
108 // we have not yet initialized the color table. | |
109 // And then we need to use a const cast to get | |
110 // a pointer to the color table that we can | |
111 // modify during the decode. Is there a better | |
112 // way to do this? Can we allocate memory to | |
113 // decode into and then create the bitmap after | |
114 // the decode? Can we create an SkColorTable | |
115 // without copying the colors? | |
116 colorTable.reset(new SkColorTable(colors, maxColors)); | |
117 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | |
118 colorCountPtr = &maxColors; | |
119 } | |
120 | |
121 // Initialize the destination bitmap | |
122 SkAutoTDelete<SkBitmap> bitmap(new SkBitmap()); | |
123 int scaledOutX = 0; | |
124 int scaledOutY = 0; | |
125 int scaledOutWidth = scaledSubset.width(); | |
126 int scaledOutHeight = scaledSubset.height(); | |
127 if (!imageContainsEntireSubset) { | |
128 scaledOutX = outX / sampleSize; | |
129 scaledOutY = outY / sampleSize; | |
130 int scaledExtraX = (inputWidth - outX - imageSubsetWidth) / sampleSize; | |
131 int scaledExtraY = (inputHeight - outY - imageSubsetHeight) / sampleSize ; | |
132 scaledOutWidth += scaledOutX + scaledExtraX; | |
133 scaledOutHeight += scaledOutY + scaledExtraY; | |
134 } | |
135 SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight); | |
136 if (!bitmap->tryAllocPixels(outInfo, nullptr, colorTable.get())) { | |
137 SkCodecPrintf("Error: Could not allocate pixels.\n"); | |
138 return nullptr; | |
139 } | |
140 | |
141 // Zero the bitmap if the region is not completely within the image. | |
142 // TODO (msarett): Can we make this faster by implementing it to only | |
143 // zero parts of the image that we won't overwrite with | |
144 // pixels? | |
145 // TODO (msarett): This could be skipped if memory is zero initialized. | |
146 // This would matter if this code is moved to Android and | |
147 // uses Android bitmaps. | |
148 if (!imageContainsEntireSubset && SkCodec::kNo_ZeroInitialized == options.fZ eroInitialized) { | |
149 bitmap->eraseColor(0); | |
150 } | |
151 | |
152 // Decode into the destination bitmap | |
153 void* dst = bitmap->getAddr(scaledOutX, scaledOutY); | |
154 size_t rowBytes = bitmap->rowBytes(); | |
155 SkCodec::Result result = fCodec->getPixels(decodeInfo, dst, rowBytes, &optio ns, colorPtr, | |
156 colorCountPtr); | |
157 if (SkCodec::kSuccess != result && SkCodec::kIncompleteInput != result) { | |
scroggo
2015/10/12 19:18:09
Why is incomplete considered fatal?
msarett
2015/10/21 19:15:09
Success and incomplete are both non-errors. Alter
| |
158 SkCodecPrintf("Error: Could not get pixels.\n"); | |
159 return nullptr; | |
160 } | |
161 | |
162 return bitmap.detach(); | |
163 } | |
164 | |
165 bool SkBitmapRegionCodec::conversionSupported(SkColorType colorType) { | |
166 // FIXME: Call virtual function when it lands. | |
167 SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fCodec->getInfo().alph aType(), | |
168 fCodec->getInfo().profileType()); | |
169 return conversion_possible(info, fCodec->getInfo()); | |
170 } | |
OLD | NEW |