Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: tests/ImageDecodingTest.cpp

Issue 1692053002: Delete SkDecodingImageGenerator (Closed) Base URL: https://skia.googlesource.com/skia.git@noble
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 "Resources.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkColor.h"
12 #include "SkColorPriv.h"
13 #include "SkData.h"
14 #include "SkDecodingImageGenerator.h"
15 #include "SkDiscardableMemoryPool.h"
16 #include "SkForceLinking.h"
17 #include "SkGradientShader.h"
18 #include "SkImageDecoder.h"
19 #include "SkImageEncoder.h"
20 #include "SkImageGeneratorPriv.h"
21 #include "SkImagePriv.h"
22 #include "SkOSFile.h"
23 #include "SkPoint.h"
24 #include "SkShader.h"
25 #include "SkStream.h"
26 #include "SkString.h"
27 #include "Test.h"
28
29 __SK_FORCE_IMAGE_DECODER_LINKING;
30
31 /**
32 * Interprets c as an unpremultiplied color, and returns the
33 * premultiplied equivalent.
34 */
35 static SkPMColor premultiply_unpmcolor(SkPMColor c) {
36 U8CPU a = SkGetPackedA32(c);
37 U8CPU r = SkGetPackedR32(c);
38 U8CPU g = SkGetPackedG32(c);
39 U8CPU b = SkGetPackedB32(c);
40 return SkPreMultiplyARGB(a, r, g, b);
41 }
42
43 /**
44 * Return true if this stream format should be skipped, due
45 * to do being an opaque format or not a valid format.
46 */
47 static bool skip_image_format(SkImageDecoder::Format format) {
48 switch (format) {
49 case SkImageDecoder::kPNG_Format:
50 case SkImageDecoder::kWEBP_Format:
51 return false;
52 // Skip unknown since it will not be decoded anyway.
53 case SkImageDecoder::kUnknown_Format:
54 // Technically ICO and BMP supports alpha channels, but our image
55 // decoders do not, so skip them as well.
56 case SkImageDecoder::kICO_Format:
57 case SkImageDecoder::kBMP_Format:
58 // KTX and ASTC are texture formats so it's not particularly clear how t o
59 // decode the alpha from them.
60 case SkImageDecoder::kKTX_Format:
61 case SkImageDecoder::kASTC_Format:
62 // The rest of these are opaque.
63 case SkImageDecoder::kPKM_Format:
64 case SkImageDecoder::kWBMP_Format:
65 case SkImageDecoder::kGIF_Format:
66 case SkImageDecoder::kJPEG_Format:
67 return true;
68 }
69 SkASSERT(false);
70 return true;
71 }
72
73 /**
74 * Test decoding an image in premultiplied mode and unpremultiplied mode and co mpare
75 * them.
76 */
77 static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filen ame) {
78 // Decode a resource:
79 SkBitmap bm8888;
80 SkBitmap bm8888Unpremul;
81
82 SkFILEStream stream(filename.c_str());
83
84 SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream);
85 if (skip_image_format(format)) {
86 return;
87 }
88
89 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
90 if (nullptr == decoder.get()) {
91 SkDebugf("couldn't decode %s\n", filename.c_str());
92 return;
93 }
94
95 bool success = decoder->decode(&stream, &bm8888, kN32_SkColorType,
96 SkImageDecoder::kDecodePixels_Mode) != SkImag eDecoder::kFailure;
97 if (!success) {
98 return;
99 }
100
101 success = stream.rewind();
102 REPORTER_ASSERT(reporter, success);
103 if (!success) {
104 return;
105 }
106
107 decoder->setRequireUnpremultipliedColors(true);
108 success = decoder->decode(&stream, &bm8888Unpremul, kN32_SkColorType,
109 SkImageDecoder::kDecodePixels_Mode) != SkImageDeco der::kFailure;
110 if (!success) {
111 return;
112 }
113
114 bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width()
115 && bm8888.height() == bm8888Unpremul.height();
116 REPORTER_ASSERT(reporter, dimensionsMatch);
117 if (!dimensionsMatch) {
118 return;
119 }
120
121 // Only do the comparison if the two bitmaps are both 8888.
122 if (bm8888.colorType() != kN32_SkColorType || bm8888Unpremul.colorType() != kN32_SkColorType) {
123 return;
124 }
125
126 // Now compare the two bitmaps.
127 for (int i = 0; i < bm8888.width(); ++i) {
128 for (int j = 0; j < bm8888.height(); ++j) {
129 // "c0" is the color of the premultiplied bitmap at (i, j).
130 const SkPMColor c0 = *bm8888.getAddr32(i, j);
131 // "c1" is the result of premultiplying the color of the unpremultip lied
132 // bitmap at (i, j).
133 const SkPMColor c1 = premultiply_unpmcolor(*bm8888Unpremul.getAddr32 (i, j));
134 // Compute the difference for each component.
135 int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
136 int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
137 int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
138 int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
139
140 // Alpha component must be exactly the same.
141 REPORTER_ASSERT(reporter, 0 == da);
142
143 // Color components may not match exactly due to rounding error.
144 REPORTER_ASSERT(reporter, dr <= 1);
145 REPORTER_ASSERT(reporter, dg <= 1);
146 REPORTER_ASSERT(reporter, db <= 1);
147 }
148 }
149 }
150
151 static void test_unpremul(skiatest::Reporter* reporter) {
152 // This test cannot run if there is no resource path.
153 SkString resourcePath = GetResourcePath();
154 if (resourcePath.isEmpty()) {
155 SkDebugf("Could not run unpremul test because resourcePath not specified .");
156 return;
157 }
158 SkOSFile::Iter iter(resourcePath.c_str());
159 SkString basename;
160 if (iter.next(&basename)) {
161 do {
162 SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_ str());
163 // SkDebugf("about to decode \"%s\"\n", filename.c_str());
164 compare_unpremul(reporter, filename);
165 } while (iter.next(&basename));
166 } else {
167 SkDebugf("Failed to find any files :(\n");
168 }
169 }
170
171 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
172 // Test that the alpha type is what we expect.
173 static void test_alphaType(skiatest::Reporter* reporter, const SkString& filenam e,
174 bool requireUnpremul) {
175 SkBitmap bm;
176 SkFILEStream stream(filename.c_str());
177
178 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
179 if (nullptr == decoder.get()) {
180 return;
181 }
182
183 decoder->setRequireUnpremultipliedColors(requireUnpremul);
184
185 // Decode just the bounds. This should always succeed.
186 bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
187 SkImageDecoder::kDecodeBounds_Mode);
188 REPORTER_ASSERT(reporter, success);
189 if (!success) {
190 return;
191 }
192
193 // Keep track of the alpha type for testing later. If the full decode
194 // succeeds, the alpha type should be the same, unless the full decode
195 // determined that the alpha type should actually be opaque, which may
196 // not be known when only decoding the bounds.
197 const SkAlphaType boundsAlphaType = bm.alphaType();
198
199 // rewind should always succeed on SkFILEStream.
200 success = stream.rewind();
201 REPORTER_ASSERT(reporter, success);
202 if (!success) {
203 return;
204 }
205
206 success = decoder->decode(&stream, &bm, kN32_SkColorType, SkImageDecoder::kD ecodePixels_Mode);
207
208 if (!success) {
209 // When the decoder is set to require unpremul, if it does not support
210 // unpremul it will fail. This is the only reason the decode should
211 // fail (since we know the files we are using to test can be decoded).
212 REPORTER_ASSERT(reporter, requireUnpremul);
213 return;
214 }
215
216 // The bounds decode should return with either the requested
217 // premul/unpremul or opaque, if that value could be determined when only
218 // decoding the bounds.
219 if (requireUnpremul) {
220 REPORTER_ASSERT(reporter, kUnpremul_SkAlphaType == boundsAlphaType
221 || kOpaque_SkAlphaType == boundsAlphaType
222 || filename.endsWith(".ico"));
223 // TODO(halcanary): Find out why color_wheel.ico fails this test.
224 } else {
225 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == boundsAlphaType
226 || kOpaque_SkAlphaType == boundsAlphaType);
227 }
228
229 // When decoding the full image, the alpha type should match the one
230 // returned by the bounds decode, unless the full decode determined that
231 // the alpha type is actually opaque.
232 REPORTER_ASSERT(reporter, bm.alphaType() == boundsAlphaType
233 || bm.alphaType() == kOpaque_SkAlphaType);
234 }
235
236 DEF_TEST(ImageDecoding_alphaType, reporter) {
237 SkString resourcePath = GetResourcePath();
238 if (resourcePath.isEmpty()) {
239 SkDebugf("Could not run alphaType test because resourcePath not specifie d.");
240 return;
241 }
242
243 SkOSFile::Iter iter(resourcePath.c_str());
244 SkString basename;
245 if (iter.next(&basename)) {
246 do {
247 SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_ str());
248 for (int truth = 0; truth <= 1; ++truth) {
249 test_alphaType(reporter, filename, SkToBool(truth));
250 }
251 } while (iter.next(&basename));
252 } else {
253 SkDebugf("Failed to find any files :(\n");
254 }
255
256 }
257
258 // Using known images, test that decoding into unpremul and premul behave as exp ected.
259 DEF_TEST(ImageDecoding_unpremul, reporter) {
260 SkString resourcePath = GetResourcePath();
261 if (resourcePath.isEmpty()) {
262 SkDebugf("Could not run unpremul test because resourcePath not specified .");
263 return;
264 }
265 const char* root = "half-transparent-white-pixel";
266 const char* suffixes[] = { ".png", ".webp" };
267
268 for (size_t i = 0; i < SK_ARRAY_COUNT(suffixes); ++i) {
269 SkString basename = SkStringPrintf("%s%s", root, suffixes[i]);
270 SkString fullName = SkOSPath::Join(resourcePath.c_str(), basename.c_str( ));
271
272 SkBitmap bm;
273 SkFILEStream stream(fullName.c_str());
274
275 if (!stream.isValid()) {
276 SkDebugf("file %s missing from resource directoy %s\n",
277 basename.c_str(), resourcePath.c_str());
278 continue;
279 }
280
281 // This should never fail since we know the images we're decoding.
282 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
283 REPORTER_ASSERT(reporter, decoder.get());
284 if (nullptr == decoder.get()) {
285 continue;
286 }
287
288 // Test unpremultiplied. We know what color this should result in.
289 decoder->setRequireUnpremultipliedColors(true);
290 bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
291 SkImageDecoder::kDecodePixels_Mode);
292 REPORTER_ASSERT(reporter, success);
293 if (!success) {
294 continue;
295 }
296
297 REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
298 {
299 SkAutoLockPixels alp(bm);
300 REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7fffffff);
301 }
302
303 success = stream.rewind();
304 REPORTER_ASSERT(reporter, success);
305 if (!success) {
306 continue;
307 }
308
309 // Test premultiplied. Once again, we know which color this should
310 // result in.
311 decoder->setRequireUnpremultipliedColors(false);
312 success = decoder->decode(&stream, &bm, kN32_SkColorType,
313 SkImageDecoder::kDecodePixels_Mode);
314 REPORTER_ASSERT(reporter, success);
315 if (!success) {
316 continue;
317 }
318
319 REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
320 {
321 SkAutoLockPixels alp(bm);
322 REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7f7f7f7f);
323 }
324 }
325 }
326 #endif // SK_BUILD_FOR_UNIX/ANDROID https://bug.skia.org/2388
327
328 #ifdef SK_DEBUG
329 // Test inside SkScaledBitmapSampler.cpp
330 extern void test_row_proc_choice();
331 #endif // SK_DEBUG
332
333 DEF_TEST(ImageDecoding, reporter) {
334 test_unpremul(reporter);
335 #ifdef SK_DEBUG
336 test_row_proc_choice();
337 #endif
338 }
339
340 // expected output for 8x8 bitmap
341 static const int kExpectedWidth = 8;
342 static const int kExpectedHeight = 8;
343 static const SkColor kExpectedPixels[] = {
344 0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
345 0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
346 0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
347 0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
348 0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
349 0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
350 0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
351 0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
352 0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
353 0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
354 0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
355 0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
356 0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
357 0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
358 0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
359 0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
360 };
361 static_assert((kExpectedWidth * kExpectedHeight) == SK_ARRAY_COUNT(kExpectedPixe ls),
362 "array_size_mismatch");
363
364 static bool decode_into_bitmap(skiatest::Reporter* r, SkBitmap* bm, SkData* enco ded) {
365 SkAutoTDelete<SkImageGenerator> gen(SkImageGenerator::NewFromEncoded(encoded ));
366 if (!gen) {
367 REPORTER_ASSERT(r, false);
368 return false;
369 }
370 if (!gen->tryGenerateBitmap(bm)) {
371 REPORTER_ASSERT(r, false);
372 return false;
373 }
374 return true;
375 }
376
377 DEF_TEST(WebP, reporter) {
378 const unsigned char encodedWebP[] = {
379 0x52, 0x49, 0x46, 0x46, 0x2c, 0x01, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
380 0x56, 0x50, 0x38, 0x4c, 0x20, 0x01, 0x00, 0x00, 0x2f, 0x07, 0xc0, 0x01,
381 0x00, 0xff, 0x01, 0x45, 0x03, 0x00, 0xe2, 0xd5, 0xae, 0x60, 0x2b, 0xad,
382 0xd9, 0x68, 0x76, 0xb6, 0x8d, 0x6a, 0x1d, 0xc0, 0xe6, 0x19, 0xd6, 0x16,
383 0xb7, 0xb4, 0xef, 0xcf, 0xc3, 0x15, 0x6c, 0xb3, 0xbd, 0x77, 0x0d, 0x85,
384 0x6d, 0x1b, 0xa9, 0xb1, 0x2b, 0xdc, 0x3d, 0x83, 0xdb, 0x00, 0x00, 0xc8,
385 0x26, 0xe5, 0x01, 0x99, 0x8a, 0xd5, 0xdd, 0xfc, 0x82, 0xcd, 0xcd, 0x9a,
386 0x8c, 0x13, 0xcc, 0x1b, 0xba, 0xf5, 0x05, 0xdb, 0xee, 0x6a, 0xdb, 0x38,
387 0x60, 0xfe, 0x43, 0x2c, 0xd4, 0x6a, 0x99, 0x4d, 0xc6, 0xc0, 0xd3, 0x28,
388 0x1b, 0xc1, 0xb1, 0x17, 0x4e, 0x43, 0x0e, 0x3d, 0x27, 0xe9, 0xe4, 0x84,
389 0x4f, 0x24, 0x62, 0x69, 0x85, 0x43, 0x8d, 0xc2, 0x04, 0x00, 0x07, 0x59,
390 0x60, 0xfd, 0x8b, 0x4d, 0x60, 0x32, 0x72, 0xcf, 0x88, 0x0c, 0x2f, 0x2f,
391 0xad, 0x62, 0xbd, 0x27, 0x09, 0x16, 0x70, 0x78, 0x6c, 0xd9, 0x82, 0xef,
392 0x1a, 0xa2, 0xcc, 0xf0, 0xf1, 0x6f, 0xd8, 0x78, 0x2e, 0x39, 0xa1, 0xcf,
393 0x14, 0x4b, 0x89, 0xb4, 0x1b, 0x48, 0x15, 0x7c, 0x48, 0x6f, 0x8c, 0x20,
394 0xb7, 0x00, 0xcf, 0xfc, 0xdb, 0xd0, 0xe9, 0xe7, 0x42, 0x09, 0xa4, 0x03,
395 0x40, 0xac, 0xda, 0x40, 0x01, 0x00, 0x5f, 0xa1, 0x3d, 0x64, 0xe1, 0xf4,
396 0x03, 0x45, 0x29, 0xe0, 0xe2, 0x4a, 0xc3, 0xa2, 0xe8, 0xe0, 0x25, 0x12,
397 0x74, 0xc6, 0xe8, 0xfb, 0x93, 0x4f, 0x9f, 0x5e, 0xc0, 0xa6, 0x91, 0x1b,
398 0xa4, 0x24, 0x82, 0xc3, 0x61, 0x07, 0x4c, 0x49, 0x4f, 0x53, 0xae, 0x5f,
399 0x5d, 0x39, 0x36, 0xc0, 0x5b, 0x57, 0x54, 0x60, 0x10, 0x00, 0x00, 0xd1,
400 0x68, 0xb6, 0x6d, 0xdb, 0x36, 0x22, 0xfa, 0x1f, 0x35, 0x75, 0x22, 0xec,
401 0x31, 0xbc, 0x5d, 0x8f, 0x87, 0x53, 0xa2, 0x05, 0x8c, 0x2f, 0xcd, 0xa8,
402 0xa7, 0xf3, 0xa3, 0xbd, 0x83, 0x8b, 0x2a, 0xc8, 0x58, 0xf5, 0xac, 0x80,
403 0xe3, 0xfe, 0x66, 0xa4, 0x7c, 0x1b, 0x6c, 0xd1, 0xa9, 0xd8, 0x14, 0xd0,
404 0xc5, 0xb5, 0x39, 0x71, 0x97, 0x19, 0x19, 0x1b
405 };
406
407 SkBitmap bm;
408 SkAutoDataUnref encoded(SkData::NewWithoutCopy(encodedWebP, sizeof(encodedWe bP)));
409 if (!decode_into_bitmap(reporter, &bm, encoded)) {
410 return;
411 }
412 if (kExpectedWidth != bm.width() || kExpectedHeight != bm.height()) {
413 REPORTER_ASSERT(reporter, false);
414 return;
415 }
416
417 bool error = false;
418 const SkColor* correctPixel = kExpectedPixels;
419 for (int y = 0; y < bm.height(); ++y) {
420 for (int x = 0; x < bm.width(); ++x) {
421 error |= (*correctPixel != bm.getColor(x, y));
422 ++correctPixel;
423 }
424 }
425 REPORTER_ASSERT(reporter, !error);
426 }
427
428 ////////////////////////////////////////////////////////////////////////////////
429
430 /**
431 * A test for the SkDecodingImageGenerator::Create
432 */
433 DEF_TEST(ImprovedBitmapFactory, reporter) {
434 SkString pngFilename = GetResourcePath("randPixels.png");
435 SkAutoTDelete<SkStreamRewindable> stream(SkStream::NewFromFile(pngFilename.c _str()));
436 if (sk_exists(pngFilename.c_str())) {
437 // example of how Android will do this inside their BitmapFactory
438 SkDecodingImageGenerator::Options opts(1, true, kN32_SkColorType);
439 SkBitmap bm;
440 SkAutoTDelete<SkImageGenerator> gen(SkDecodingImageGenerator::Create(str eam.detach(),
441 opt s));
442 REPORTER_ASSERT(reporter, gen->tryGenerateBitmap(&bm));
443 }
444 }
445
446 ////////////////////////////////////////////////////////////////////////////////
447
448 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
449 static inline bool check_rounding(int value, int dividend, int divisor) {
450 // returns true if the value is greater than floor(dividend/divisor)
451 // and less than SkNextPow2(ceil(dividend - divisor))
452 return (((divisor * value) > (dividend - divisor))
453 && value <= SkNextPow2(((dividend - 1) / divisor) + 1));
454 }
455 #endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
456
457
458 #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
459 #define kBackwards_SkColorType kRGBA_8888_SkColorType
460 #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
461 #define kBackwards_SkColorType kBGRA_8888_SkColorType
462 #else
463 #error "SK_*32_SHFIT values must correspond to BGRA or RGBA byte order"
464 #endif
465
466 static inline const char* SkColorType_to_string(SkColorType colorType) {
467 switch(colorType) {
468 case kAlpha_8_SkColorType: return "Alpha_8";
469 case kRGB_565_SkColorType: return "RGB_565";
470 case kARGB_4444_SkColorType: return "ARGB_4444";
471 case kN32_SkColorType: return "N32";
472 case kBackwards_SkColorType: return "Backwards";
473 case kIndex_8_SkColorType: return "Index_8";
474 default: return "ERROR";
475 }
476 }
477
478 static inline const char* options_colorType(
479 const SkDecodingImageGenerator::Options& opts) {
480 if (opts.fUseRequestedColorType) {
481 return SkColorType_to_string(opts.fRequestedColorType);
482 } else {
483 return "(none)";
484 }
485 }
486
487 static inline const char* yn(bool value) {
488 if (value) {
489 return "yes";
490 } else {
491 return "no";
492 }
493 }
494
495 /**
496 * Given either a SkStream or a SkData, try to decode the encoded
497 * image using the specified options and report errors.
498 */
499 static void test_options(skiatest::Reporter* reporter,
500 const SkDecodingImageGenerator::Options& opts,
501 SkStreamRewindable* encodedStream,
502 SkData* encodedData,
503 bool useData,
504 const SkString& path) {
505 SkBitmap bm;
506 SkAutoTDelete<SkImageGenerator> gen;
507
508 if (useData) {
509 if (nullptr == encodedData) {
510 return;
511 }
512 gen.reset(SkDecodingImageGenerator::Create(encodedData, opts));
513 } else {
514 if (nullptr == encodedStream) {
515 return;
516 }
517 gen.reset(SkDecodingImageGenerator::Create(encodedStream->duplicate(), o pts));
518 }
519 if (!gen) {
520 if (opts.fUseRequestedColorType && (kARGB_4444_SkColorType == opts.fRequ estedColorType)) {
521 return; // Ignore known conversion inabilities.
522 }
523 // If we get here, it's a failure and we will need more
524 // information about why it failed.
525 ERRORF(reporter, "Bounds decode failed [sampleSize=%d dither=%s "
526 "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
527 options_colorType(opts), path.c_str());
528 return;
529 }
530 if (!gen->tryGenerateBitmap(&bm)) {
531 return;
532 }
533
534 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
535 // Android is the only system that use Skia's image decoders in
536 // production. For now, we'll only verify that samplesize works
537 // on systems where it already is known to work.
538 REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight, opts. fSampleSize));
539 REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth, opts.fS ampleSize));
540 // The ImageDecoder API doesn't guarantee that SampleSize does
541 // anything at all, but the decoders that this test excercises all
542 // produce an output size in the following range:
543 // (((sample_size * out_size) > (in_size - sample_size))
544 // && out_size <= SkNextPow2(((in_size - 1) / sample_size) + 1));
545 #endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
546
547 SkColorType requestedColorType = opts.fRequestedColorType;
548 REPORTER_ASSERT(reporter,
549 (!opts.fUseRequestedColorType)
550 || (bm.colorType() == requestedColorType));
551
552 // Condition under which we should check the decoding results:
553 if ((kN32_SkColorType == bm.colorType())
554 && (!path.endsWith(".jpg")) // lossy
555 && (opts.fSampleSize == 1)) { // scaled
556 const SkColor* correctPixels = kExpectedPixels;
557 SkASSERT(bm.height() == kExpectedHeight);
558 SkASSERT(bm.width() == kExpectedWidth);
559 int pixelErrors = 0;
560 for (int y = 0; y < bm.height(); ++y) {
561 for (int x = 0; x < bm.width(); ++x) {
562 if (*correctPixels != bm.getColor(x, y)) {
563 ++pixelErrors;
564 }
565 ++correctPixels;
566 }
567 }
568 if (pixelErrors != 0) {
569 ERRORF(reporter, "Pixel-level mismatch (%d of %d) "
570 "[sampleSize=%d dither=%s colorType=%s %s]",
571 pixelErrors, kExpectedHeight * kExpectedWidth,
572 opts.fSampleSize, yn(opts.fDitherImage),
573 options_colorType(opts), path.c_str());
574 }
575 }
576 }
577
578 /**
579 * SkDecodingImageGenerator has an Options struct which lets the
580 * client of the generator set sample size, dithering, and bitmap
581 * config. This test loops through many possible options and tries
582 * them on a set of 5 small encoded images (each in a different
583 * format). We test both SkData and SkStreamRewindable decoding.
584 */
585 DEF_TEST(ImageDecoderOptions, reporter) {
586 const char* files[] = {
587 "randPixels.bmp",
588 "randPixels.jpg",
589 "randPixels.png",
590 "randPixels.webp",
591 #if !defined(SK_BUILD_FOR_WIN)
592 // TODO(halcanary): Find out why this fails sometimes.
593 "randPixels.gif",
594 #endif
595 };
596
597 SkString resourceDir = GetResourcePath();
598 if (!sk_exists(resourceDir.c_str())) {
599 return;
600 }
601
602 int scaleList[] = {1, 2, 3, 4};
603 bool ditherList[] = {true, false};
604 SkColorType colorList[] = {
605 kAlpha_8_SkColorType,
606 kRGB_565_SkColorType,
607 kARGB_4444_SkColorType, // Most decoders will fail on 4444.
608 kN32_SkColorType
609 // Note that indexed color is left out of the list. Lazy
610 // decoding doesn't do indexed color.
611 };
612 const bool useDataList[] = {true, false};
613
614 for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
615 SkString path = SkOSPath::Join(resourceDir.c_str(), files[fidx]);
616 if (!sk_exists(path.c_str())) {
617 continue;
618 }
619
620 SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
621 REPORTER_ASSERT(reporter, encodedData.get() != nullptr);
622 SkAutoTDelete<SkStreamRewindable> encodedStream(
623 SkStream::NewFromFile(path.c_str()));
624 REPORTER_ASSERT(reporter, encodedStream.get() != nullptr);
625
626 for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
627 for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
628 for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
629 for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) {
630 SkDecodingImageGenerator::Options opts(scaleList[i],
631 ditherList[j],
632 colorList[k]);
633 test_options(reporter, opts, encodedStream, encodedData,
634 useDataList[m], path);
635
636 }
637 SkDecodingImageGenerator::Options options(scaleList[i],
638 ditherList[j]);
639 test_options(reporter, options, encodedStream, encodedData,
640 useDataList[m], path);
641 }
642 }
643 }
644 }
645 }
646
647 DEF_TEST(DecodingImageGenerator_ColorTableCheck, r) {
648 SkString resourceDir = GetResourcePath();
649 SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.gif");
650 if (!sk_exists(path.c_str())) {
651 return;
652 }
653 SkAutoDataUnref encoded(SkData::NewFromFileName(path.c_str()));
654 SkBitmap bitmap;
655 SkAutoTDelete<SkImageGenerator> gen(SkDecodingImageGenerator::Create(encoded ,
656 SkDecodingImageGene rator::Options()));
657 if (!gen) {
658 REPORTER_ASSERT(r, false);
659 return;
660 }
661 if (!gen->tryGenerateBitmap(&bitmap)) {
662 REPORTER_ASSERT(r, false);
663 return;
664 }
665 if (kIndex_8_SkColorType != bitmap.colorType()) {
666 return;
667 }
668 REPORTER_ASSERT(r, bitmap.getColorTable());
669 }
670
671
672 ////////////////////////////////////////////////////////////////////////////////
673 namespace {
674 class SingleAllocator : public SkBitmap::Allocator {
675 public:
676 SingleAllocator(void* p, size_t s) : fPixels(p), fSize(s) { }
677 ~SingleAllocator() {}
678 // If the pixels in fPixels are big enough, use them.
679 bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) override {
680 SkASSERT(bm);
681 if (bm->info().getSafeSize(bm->rowBytes()) <= fSize) {
682 bm->setPixels(fPixels, ct);
683 fPixels = nullptr;
684 fSize = 0;
685 return true;
686 }
687 return bm->tryAllocPixels(nullptr, ct);
688 }
689 bool ready() { return fPixels != nullptr; }
690 private:
691 void* fPixels;
692 size_t fSize;
693 };
694 } // namespace
695
696 /* This tests for a bug in libjpeg where INT32 is typedefed to long
697 and memory can be written to outside of the array. */
698 DEF_TEST(ImageDecoding_JpegOverwrite, r) {
699 SkString resourceDir = GetResourcePath();
700 SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.jpg");
701 SkAutoTDelete<SkStreamAsset> stream(
702 SkStream::NewFromFile(path.c_str()));
703 if (!stream.get()) {
704 SkDebugf("\nPath '%s' missing.\n", path.c_str());
705 return;
706 }
707 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
708 if (nullptr == decoder.get()) {
709 ERRORF(r, "\nSkImageDecoder::Factory failed.\n");
710 return;
711 }
712 SkAssertResult(stream->rewind());
713
714 static const uint16_t sentinal = 0xBEEF;
715 static const int pixelCount = 16;
716 SkAutoTMalloc<uint16_t> pixels(pixelCount + 1);
717 // pixels.get() should be 4-byte aligned.
718 // This is necessary to reproduce the bug.
719
720 pixels[pixelCount] = sentinal; // This value should not be changed.
721
722 SkAutoTUnref<SingleAllocator> allocator(
723 new SingleAllocator((void*)pixels.get(), sizeof(uint16_t) * pixelCou nt));
724 decoder->setAllocator(allocator);
725 decoder->setSampleSize(2);
726 SkBitmap bitmap;
727 bool success = decoder->decode(stream, &bitmap, kRGB_565_SkColorType,
728 SkImageDecoder::kDecodePixels_Mode) != SkImag eDecoder::kFailure;
729 REPORTER_ASSERT(r, success);
730 REPORTER_ASSERT(r, !allocator->ready()); // Decoder used correct memory
731 REPORTER_ASSERT(r, sentinal == pixels[pixelCount]);
732 }
OLDNEW
« no previous file with comments | « src/images/SkDecodingImageGenerator.cpp ('k') | tests/JpegTest.cpp » ('j') | tests/YUVTest.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698