OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2013 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 "SkData.h" | |
9 #include "SkDecodingImageGenerator.h" | |
10 #include "SkImageDecoder.h" | |
11 #include "SkImageInfo.h" | |
12 #include "SkImageGenerator.h" | |
13 #include "SkImagePriv.h" | |
14 #include "SkStream.h" | |
15 #include "SkUtils.h" | |
16 | |
17 namespace { | |
18 bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) { | |
19 return a.width() == b.width() && a.height() == b.height() && | |
20 a.colorType() == b.colorType(); | |
21 } | |
22 | |
23 class DecodingImageGenerator : public SkImageGenerator { | |
24 public: | |
25 virtual ~DecodingImageGenerator(); | |
26 | |
27 SkData* fData; | |
28 SkAutoTDelete<SkStreamRewindable> fStream; | |
29 const SkImageInfo fInfo; | |
30 const int fSampleSize; | |
31 const bool fDitherImage; | |
32 | |
33 DecodingImageGenerator(SkData* data, | |
34 SkStreamRewindable* stream, | |
35 const SkImageInfo& info, | |
36 int sampleSize, | |
37 bool ditherImage); | |
38 | |
39 protected: | |
40 SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override; | |
41 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, | |
42 SkPMColor ctable[], int* ctableCount) override; | |
43 bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], | |
44 SkYUVColorSpace* colorSpace) override; | |
45 | |
46 private: | |
47 typedef SkImageGenerator INHERITED; | |
48 }; | |
49 | |
50 /** | |
51 * Special allocator used by getPixels(). Uses preallocated memory | |
52 * provided if possible, else fall-back on the default allocator | |
53 */ | |
54 class TargetAllocator : public SkBitmap::Allocator { | |
55 public: | |
56 TargetAllocator(const SkImageInfo& info, | |
57 void* target, | |
58 size_t rowBytes) | |
59 : fInfo(info) | |
60 , fTarget(target) | |
61 , fRowBytes(rowBytes) | |
62 {} | |
63 | |
64 bool isReady() { return (fTarget != nullptr); } | |
65 | |
66 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) { | |
67 if (nullptr == fTarget || !equal_modulo_alpha(fInfo, bm->info())) { | |
68 // Call default allocator. | |
69 return bm->tryAllocPixels(nullptr, ct); | |
70 } | |
71 | |
72 // TODO(halcanary): verify that all callers of this function | |
73 // will respect new RowBytes. Will be moot once rowbytes belongs | |
74 // to PixelRef. | |
75 bm->installPixels(fInfo, fTarget, fRowBytes, ct, nullptr, nullptr); | |
76 | |
77 fTarget = nullptr; // never alloc same pixels twice! | |
78 return true; | |
79 } | |
80 | |
81 private: | |
82 const SkImageInfo fInfo; | |
83 void* fTarget; // Block of memory to be supplied as pixel memory | |
84 // in allocPixelRef. Must be large enough to hold | |
85 // a bitmap described by fInfo and fRowBytes | |
86 const size_t fRowBytes; // rowbytes for the destination bitmap | |
87 | |
88 typedef SkBitmap::Allocator INHERITED; | |
89 }; | |
90 | |
91 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h | |
92 #ifdef SK_DEBUG | |
93 #define SkCheckResult(expr, value) SkASSERT((value) == (expr)) | |
94 #else | |
95 #define SkCheckResult(expr, value) (void)(expr) | |
96 #endif | |
97 | |
98 #ifdef SK_DEBUG | |
99 inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) { | |
100 return ((reported == actual) | |
101 || ((reported == kPremul_SkAlphaType) | |
102 && (actual == kOpaque_SkAlphaType))); | |
103 } | |
104 #endif // SK_DEBUG | |
105 | |
106 //////////////////////////////////////////////////////////////////////////////// | |
107 | |
108 DecodingImageGenerator::DecodingImageGenerator( | |
109 SkData* data, | |
110 SkStreamRewindable* stream, | |
111 const SkImageInfo& info, | |
112 int sampleSize, | |
113 bool ditherImage) | |
114 : INHERITED(info) | |
115 , fData(data) | |
116 , fStream(stream) | |
117 , fInfo(info) | |
118 , fSampleSize(sampleSize) | |
119 , fDitherImage(ditherImage) | |
120 { | |
121 SkASSERT(stream != nullptr); | |
122 SkSafeRef(fData); // may be nullptr. | |
123 } | |
124 | |
125 DecodingImageGenerator::~DecodingImageGenerator() { | |
126 SkSafeUnref(fData); | |
127 } | |
128 | |
129 SkData* DecodingImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { | |
130 // This functionality is used in `gm --serialize` | |
131 // Does not encode options. | |
132 if (nullptr == fData) { | |
133 // TODO(halcanary): SkStreamRewindable needs a refData() function | |
134 // which returns a cheap copy of the underlying data. | |
135 if (!fStream->rewind()) { | |
136 return nullptr; | |
137 } | |
138 size_t length = fStream->getLength(); | |
139 if (length) { | |
140 fData = SkData::NewFromStream(fStream, length); | |
141 } | |
142 } | |
143 return SkSafeRef(fData); | |
144 } | |
145 | |
146 bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels,
size_t rowBytes, | |
147 SkPMColor ctableEntries[], int* ctableC
ount) { | |
148 if (fInfo != info) { | |
149 // The caller has specified a different info. This is an | |
150 // error for this kind of SkImageGenerator. Use the Options | |
151 // to change the settings. | |
152 return false; | |
153 } | |
154 | |
155 SkAssertResult(fStream->rewind()); | |
156 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); | |
157 if (nullptr == decoder.get()) { | |
158 return false; | |
159 } | |
160 decoder->setDitherImage(fDitherImage); | |
161 decoder->setSampleSize(fSampleSize); | |
162 decoder->setRequireUnpremultipliedColors(info.alphaType() == kUnpremul_SkAlp
haType); | |
163 | |
164 SkBitmap bitmap; | |
165 TargetAllocator allocator(fInfo, pixels, rowBytes); | |
166 decoder->setAllocator(&allocator); | |
167 const SkImageDecoder::Result decodeResult = decoder->decode(fStream, &bitmap
, info.colorType(), | |
168 SkImageDecoder::
kDecodePixels_Mode); | |
169 decoder->setAllocator(nullptr); | |
170 if (SkImageDecoder::kFailure == decodeResult) { | |
171 return false; | |
172 } | |
173 if (allocator.isReady()) { // Did not use pixels! | |
174 SkBitmap bm; | |
175 SkASSERT(bitmap.canCopyTo(info.colorType())); | |
176 bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator); | |
177 if (!copySuccess || allocator.isReady()) { | |
178 SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed."); | |
179 // Earlier we checked canCopyto(); we expect consistency. | |
180 return false; | |
181 } | |
182 SkASSERT(check_alpha(info.alphaType(), bm.alphaType())); | |
183 } else { | |
184 SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType())); | |
185 } | |
186 | |
187 if (kIndex_8_SkColorType == info.colorType()) { | |
188 if (kIndex_8_SkColorType != bitmap.colorType()) { | |
189 // they asked for Index8, but we didn't receive that from decoder | |
190 return false; | |
191 } | |
192 SkColorTable* ctable = bitmap.getColorTable(); | |
193 if (nullptr == ctable) { | |
194 return false; | |
195 } | |
196 const int count = ctable->count(); | |
197 memcpy(ctableEntries, ctable->readColors(), count * sizeof(SkPMColor)); | |
198 *ctableCount = count; | |
199 } | |
200 return true; | |
201 } | |
202 | |
203 bool DecodingImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], | |
204 size_t rowBytes[3], SkYUVColorSpace
* colorSpace) { | |
205 if (!fStream->rewind()) { | |
206 return false; | |
207 } | |
208 | |
209 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); | |
210 if (nullptr == decoder.get()) { | |
211 return false; | |
212 } | |
213 | |
214 return decoder->decodeYUV8Planes(fStream, sizes, planes, rowBytes, colorSpac
e); | |
215 } | |
216 | |
217 // A contructor-type function that returns nullptr on failure. This | |
218 // prevents the returned SkImageGenerator from ever being in a bad | |
219 // state. Called by both Create() functions | |
220 SkImageGenerator* CreateDecodingImageGenerator( | |
221 SkData* data, | |
222 SkStreamRewindable* stream, | |
223 const SkDecodingImageGenerator::Options& opts) { | |
224 SkASSERT(stream); | |
225 SkAutoTDelete<SkStreamRewindable> autoStream(stream); // always delete this | |
226 SkAssertResult(autoStream->rewind()); | |
227 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream)); | |
228 if (nullptr == decoder.get()) { | |
229 return nullptr; | |
230 } | |
231 SkBitmap bitmap; | |
232 decoder->setSampleSize(opts.fSampleSize); | |
233 decoder->setRequireUnpremultipliedColors(opts.fRequireUnpremul); | |
234 if (!decoder->decode(stream, &bitmap, SkImageDecoder::kDecodeBounds_Mode)) { | |
235 return nullptr; | |
236 } | |
237 if (kUnknown_SkColorType == bitmap.colorType()) { | |
238 return nullptr; | |
239 } | |
240 | |
241 SkImageInfo info = bitmap.info(); | |
242 | |
243 if (opts.fUseRequestedColorType && (opts.fRequestedColorType != info.colorTy
pe())) { | |
244 if (!bitmap.canCopyTo(opts.fRequestedColorType)) { | |
245 SkASSERT(bitmap.colorType() != opts.fRequestedColorType); | |
246 return nullptr; // Can not translate to needed config. | |
247 } | |
248 info = info.makeColorType(opts.fRequestedColorType); | |
249 } | |
250 | |
251 if (opts.fRequireUnpremul && info.alphaType() != kOpaque_SkAlphaType) { | |
252 info = info.makeAlphaType(kUnpremul_SkAlphaType); | |
253 } | |
254 | |
255 SkAlphaType newAlphaType = info.alphaType(); | |
256 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAl
phaType)) { | |
257 return nullptr; | |
258 } | |
259 | |
260 return new DecodingImageGenerator(data, autoStream.detach(), info.makeAlphaT
ype(newAlphaType), | |
261 opts.fSampleSize, opts.fDitherImage); | |
262 } | |
263 | |
264 } // namespace | |
265 | |
266 //////////////////////////////////////////////////////////////////////////////// | |
267 | |
268 SkImageGenerator* SkDecodingImageGenerator::Create( | |
269 SkData* data, | |
270 const SkDecodingImageGenerator::Options& opts) { | |
271 SkASSERT(data != nullptr); | |
272 if (nullptr == data) { | |
273 return nullptr; | |
274 } | |
275 SkStreamRewindable* stream = new SkMemoryStream(data); | |
276 SkASSERT(stream != nullptr); | |
277 return CreateDecodingImageGenerator(data, stream, opts); | |
278 } | |
279 | |
280 SkImageGenerator* SkDecodingImageGenerator::Create( | |
281 SkStreamRewindable* stream, | |
282 const SkDecodingImageGenerator::Options& opts) { | |
283 SkASSERT(stream != nullptr); | |
284 if (stream == nullptr) { | |
285 return nullptr; | |
286 } | |
287 return CreateDecodingImageGenerator(nullptr, stream, opts); | |
288 } | |
OLD | NEW |