2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
12 #include "SkColorPriv.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"
29 __SK_FORCE_IMAGE_DECODER_LINKING;
32 * Interprets c as an unpremultiplied color, and returns the
33 * premultiplied equivalent.
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);
44 * Return true if this stream format should be skipped, due
45 * to do being an opaque format or not a valid format.
47 static bool skip_image_format(SkImageDecoder::Format format) {
49 case SkImageDecoder::kPNG_Format:
50 case SkImageDecoder::kWEBP_Format:
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 to
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:
74 * Test decoding an image in premultiplied mode and unpremultiplied mode and compare
77 static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filename) {
80 SkBitmap bm8888Unpremul;
82 SkFILEStream stream(filename.c_str());
84 SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream);
85 if (skip_image_format(format)) {
89 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
90 if (NULL == decoder.get()) {
91 SkDebugf("couldn't decode %s\n", filename.c_str());
95 bool success = decoder->decode(&stream, &bm8888, kN32_SkColorType,
96 SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
101 success = stream.rewind();
102 REPORTER_ASSERT(reporter, success);
107 decoder->setRequireUnpremultipliedColors(true);
108 success = decoder->decode(&stream, &bm8888Unpremul, kN32_SkColorType,
109 SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
114 bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width()
115 && bm8888.height() == bm8888Unpremul.height();
116 REPORTER_ASSERT(reporter, dimensionsMatch);
117 if (!dimensionsMatch) {
121 // Only do the comparison if the two bitmaps are both 8888.
122 if (bm8888.colorType() != kN32_SkColorType || bm8888Unpremul.colorType() != kN32_SkColorType) {
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 unpremultiplied
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));
140 // Alpha component must be exactly the same.
141 REPORTER_ASSERT(reporter, 0 == da);
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);
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.");
158 SkOSFile::Iter iter(resourcePath.c_str());
160 if (iter.next(&basename)) {
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));
167 SkDebugf("Failed to find any files :(\n");
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& filename,
174 bool requireUnpremul) {
176 SkFILEStream stream(filename.c_str());
178 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
179 if (NULL == decoder.get()) {
183 decoder->setRequireUnpremultipliedColors(requireUnpremul);
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);
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();
199 // rewind should always succeed on SkFILEStream.
200 success = stream.rewind();
201 REPORTER_ASSERT(reporter, success);
206 success = decoder->decode(&stream, &bm, kN32_SkColorType, SkImageDecoder::kDecodePixels_Mode);
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);
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);
223 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == boundsAlphaType
224 || kOpaque_SkAlphaType == boundsAlphaType);
227 // When decoding the full image, the alpha type should match the one
228 // returned by the bounds decode, unless the full decode determined that
229 // the alpha type is actually opaque.
230 REPORTER_ASSERT(reporter, bm.alphaType() == boundsAlphaType
231 || bm.alphaType() == kOpaque_SkAlphaType);
234 DEF_TEST(ImageDecoding_alphaType, reporter) {
235 SkString resourcePath = GetResourcePath();
236 if (resourcePath.isEmpty()) {
237 SkDebugf("Could not run alphaType test because resourcePath not specified.");
241 SkOSFile::Iter iter(resourcePath.c_str());
243 if (iter.next(&basename)) {
245 SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
246 for (int truth = 0; truth <= 1; ++truth) {
247 test_alphaType(reporter, filename, SkToBool(truth));
249 } while (iter.next(&basename));
251 SkDebugf("Failed to find any files :(\n");
256 // Using known images, test that decoding into unpremul and premul behave as expected.
257 DEF_TEST(ImageDecoding_unpremul, reporter) {
258 SkString resourcePath = GetResourcePath();
259 if (resourcePath.isEmpty()) {
260 SkDebugf("Could not run unpremul test because resourcePath not specified.");
263 const char* root = "half-transparent-white-pixel";
264 const char* suffixes[] = { ".png", ".webp" };
266 for (size_t i = 0; i < SK_ARRAY_COUNT(suffixes); ++i) {
267 SkString basename = SkStringPrintf("%s%s", root, suffixes[i]);
268 SkString fullName = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
271 SkFILEStream stream(fullName.c_str());
273 if (!stream.isValid()) {
274 SkDebugf("file %s missing from resource directoy %s\n",
275 basename.c_str(), resourcePath.c_str());
279 // This should never fail since we know the images we're decoding.
280 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
281 REPORTER_ASSERT(reporter, decoder.get());
282 if (NULL == decoder.get()) {
286 // Test unpremultiplied. We know what color this should result in.
287 decoder->setRequireUnpremultipliedColors(true);
288 bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
289 SkImageDecoder::kDecodePixels_Mode);
290 REPORTER_ASSERT(reporter, success);
295 REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
297 SkAutoLockPixels alp(bm);
298 REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7fffffff);
301 success = stream.rewind();
302 REPORTER_ASSERT(reporter, success);
307 // Test premultiplied. Once again, we know which color this should
309 decoder->setRequireUnpremultipliedColors(false);
310 success = decoder->decode(&stream, &bm, kN32_SkColorType,
311 SkImageDecoder::kDecodePixels_Mode);
312 REPORTER_ASSERT(reporter, success);
317 REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
319 SkAutoLockPixels alp(bm);
320 REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7f7f7f7f);
324 #endif // SK_BUILD_FOR_UNIX/ANDROID skbug.com/2388
327 // Create a stream containing a bitmap encoded to Type type.
328 static SkMemoryStream* create_image_stream(SkImageEncoder::Type type) {
331 bm.allocN32Pixels(size, size);
333 SkPoint points[2] = {
334 { SkIntToScalar(0), SkIntToScalar(0) },
335 { SkIntToScalar(size), SkIntToScalar(size) }
337 SkColor colors[2] = { SK_ColorWHITE, SK_ColorBLUE };
338 SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL,
339 SK_ARRAY_COUNT(colors),
340 SkShader::kClamp_TileMode);
342 paint.setShader(shader)->unref();
343 canvas.drawPaint(paint);
344 // Now encode it to a stream.
345 SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(bm, type, 100));
346 if (NULL == data.get()) {
349 return SkNEW_ARGS(SkMemoryStream, (data.get()));
352 // For every format that supports tile based decoding, ensure that
353 // calling decodeSubset will not fail if the caller has unreffed the
354 // stream provided in buildTileIndex.
355 // Only runs in debug mode since we are testing for a crash.
356 static void test_stream_life() {
357 const SkImageEncoder::Type gTypes[] = {
358 #ifdef SK_BUILD_FOR_ANDROID
359 SkImageEncoder::kJPEG_Type,
360 SkImageEncoder::kPNG_Type,
362 SkImageEncoder::kWEBP_Type,
364 for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) {
365 // SkDebugf("encoding to %i\n", i);
366 SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i]));
367 if (NULL == stream.get()) {
368 SkDebugf("no stream\n");
371 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
372 if (NULL == decoder.get()) {
373 SkDebugf("no decoder\n");
377 if (!decoder->buildTileIndex(stream.get(), &width, &height)) {
378 SkDebugf("could not build a tile index\n");
381 // Now unref the stream to make sure it survives
384 decoder->decodeSubset(&bm, SkIRect::MakeWH(width, height), kN32_SkColorType);
388 // Test inside SkScaledBitmapSampler.cpp
389 extern void test_row_proc_choice();
393 DEF_TEST(ImageDecoding, reporter) {
394 test_unpremul(reporter);
397 test_row_proc_choice();
401 // expected output for 8x8 bitmap
402 static const int kExpectedWidth = 8;
403 static const int kExpectedHeight = 8;
404 static const SkColor kExpectedPixels[] = {
405 0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
406 0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
407 0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
408 0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
409 0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
410 0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
411 0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
412 0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
413 0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
414 0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
415 0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
416 0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
417 0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
418 0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
419 0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
420 0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
422 SK_COMPILE_ASSERT((kExpectedWidth * kExpectedHeight)
423 == SK_ARRAY_COUNT(kExpectedPixels), array_size_mismatch);
425 DEF_TEST(WebP, reporter) {
426 const unsigned char encodedWebP[] = {
427 0x52, 0x49, 0x46, 0x46, 0x2c, 0x01, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
428 0x56, 0x50, 0x38, 0x4c, 0x20, 0x01, 0x00, 0x00, 0x2f, 0x07, 0xc0, 0x01,
429 0x00, 0xff, 0x01, 0x45, 0x03, 0x00, 0xe2, 0xd5, 0xae, 0x60, 0x2b, 0xad,
430 0xd9, 0x68, 0x76, 0xb6, 0x8d, 0x6a, 0x1d, 0xc0, 0xe6, 0x19, 0xd6, 0x16,
431 0xb7, 0xb4, 0xef, 0xcf, 0xc3, 0x15, 0x6c, 0xb3, 0xbd, 0x77, 0x0d, 0x85,
432 0x6d, 0x1b, 0xa9, 0xb1, 0x2b, 0xdc, 0x3d, 0x83, 0xdb, 0x00, 0x00, 0xc8,
433 0x26, 0xe5, 0x01, 0x99, 0x8a, 0xd5, 0xdd, 0xfc, 0x82, 0xcd, 0xcd, 0x9a,
434 0x8c, 0x13, 0xcc, 0x1b, 0xba, 0xf5, 0x05, 0xdb, 0xee, 0x6a, 0xdb, 0x38,
435 0x60, 0xfe, 0x43, 0x2c, 0xd4, 0x6a, 0x99, 0x4d, 0xc6, 0xc0, 0xd3, 0x28,
436 0x1b, 0xc1, 0xb1, 0x17, 0x4e, 0x43, 0x0e, 0x3d, 0x27, 0xe9, 0xe4, 0x84,
437 0x4f, 0x24, 0x62, 0x69, 0x85, 0x43, 0x8d, 0xc2, 0x04, 0x00, 0x07, 0x59,
438 0x60, 0xfd, 0x8b, 0x4d, 0x60, 0x32, 0x72, 0xcf, 0x88, 0x0c, 0x2f, 0x2f,
439 0xad, 0x62, 0xbd, 0x27, 0x09, 0x16, 0x70, 0x78, 0x6c, 0xd9, 0x82, 0xef,
440 0x1a, 0xa2, 0xcc, 0xf0, 0xf1, 0x6f, 0xd8, 0x78, 0x2e, 0x39, 0xa1, 0xcf,
441 0x14, 0x4b, 0x89, 0xb4, 0x1b, 0x48, 0x15, 0x7c, 0x48, 0x6f, 0x8c, 0x20,
442 0xb7, 0x00, 0xcf, 0xfc, 0xdb, 0xd0, 0xe9, 0xe7, 0x42, 0x09, 0xa4, 0x03,
443 0x40, 0xac, 0xda, 0x40, 0x01, 0x00, 0x5f, 0xa1, 0x3d, 0x64, 0xe1, 0xf4,
444 0x03, 0x45, 0x29, 0xe0, 0xe2, 0x4a, 0xc3, 0xa2, 0xe8, 0xe0, 0x25, 0x12,
445 0x74, 0xc6, 0xe8, 0xfb, 0x93, 0x4f, 0x9f, 0x5e, 0xc0, 0xa6, 0x91, 0x1b,
446 0xa4, 0x24, 0x82, 0xc3, 0x61, 0x07, 0x4c, 0x49, 0x4f, 0x53, 0xae, 0x5f,
447 0x5d, 0x39, 0x36, 0xc0, 0x5b, 0x57, 0x54, 0x60, 0x10, 0x00, 0x00, 0xd1,
448 0x68, 0xb6, 0x6d, 0xdb, 0x36, 0x22, 0xfa, 0x1f, 0x35, 0x75, 0x22, 0xec,
449 0x31, 0xbc, 0x5d, 0x8f, 0x87, 0x53, 0xa2, 0x05, 0x8c, 0x2f, 0xcd, 0xa8,
450 0xa7, 0xf3, 0xa3, 0xbd, 0x83, 0x8b, 0x2a, 0xc8, 0x58, 0xf5, 0xac, 0x80,
451 0xe3, 0xfe, 0x66, 0xa4, 0x7c, 0x1b, 0x6c, 0xd1, 0xa9, 0xd8, 0x14, 0xd0,
452 0xc5, 0xb5, 0x39, 0x71, 0x97, 0x19, 0x19, 0x1b
454 SkAutoDataUnref encoded(SkData::NewWithCopy(encodedWebP,
455 sizeof(encodedWebP)));
458 bool success = SkInstallDiscardablePixelRef(
459 SkDecodingImageGenerator::Create(encoded,
460 SkDecodingImageGenerator::Options()), &bm);
462 REPORTER_ASSERT(reporter, success);
466 SkAutoLockPixels alp(bm);
468 bool rightSize = ((kExpectedWidth == bm.width())
469 && (kExpectedHeight == bm.height()));
470 REPORTER_ASSERT(reporter, rightSize);
473 const SkColor* correctPixel = kExpectedPixels;
474 for (int y = 0; y < bm.height(); ++y) {
475 for (int x = 0; x < bm.width(); ++x) {
476 error |= (*correctPixel != bm.getColor(x, y));
480 REPORTER_ASSERT(reporter, !error);
484 ////////////////////////////////////////////////////////////////////////////////
486 // example of how Android will do this inside their BitmapFactory
487 static SkPixelRef* install_pixel_ref(SkBitmap* bitmap,
488 SkStreamRewindable* stream,
489 int sampleSize, bool ditherImage) {
490 SkASSERT(bitmap != NULL);
491 SkASSERT(stream != NULL);
492 SkASSERT(stream->rewind());
493 SkASSERT(stream->unique());
494 SkColorType colorType = bitmap->colorType();
495 SkDecodingImageGenerator::Options opts(sampleSize, ditherImage, colorType);
496 if (SkInstallDiscardablePixelRef(
497 SkDecodingImageGenerator::Create(stream, opts), bitmap)) {
498 return bitmap->pixelRef();
503 * A test for the SkDecodingImageGenerator::Create and
504 * SkInstallDiscardablePixelRef functions.
506 DEF_TEST(ImprovedBitmapFactory, reporter) {
507 SkString pngFilename = GetResourcePath("randPixels.png");
508 SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(pngFilename.c_str()));
509 if (sk_exists(pngFilename.c_str())) {
511 SkAssertResult(bm.setInfo(SkImageInfo::MakeN32Premul(1, 1)));
512 REPORTER_ASSERT(reporter,
513 install_pixel_ref(&bm, stream.detach(), 1, true));
514 SkAutoLockPixels alp(bm);
515 REPORTER_ASSERT(reporter, bm.getPixels());
520 ////////////////////////////////////////////////////////////////////////////////
522 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
523 static inline bool check_rounding(int value, int dividend, int divisor) {
524 // returns true if the value is greater than floor(dividend/divisor)
525 // and less than SkNextPow2(ceil(dividend - divisor))
526 return (((divisor * value) > (dividend - divisor))
527 && value <= SkNextPow2(((dividend - 1) / divisor) + 1));
529 #endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
532 #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
533 #define kBackwards_SkColorType kRGBA_8888_SkColorType
534 #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
535 #define kBackwards_SkColorType kBGRA_8888_SkColorType
537 #error "SK_*32_SHFIT values must correspond to BGRA or RGBA byte order"
540 static inline const char* SkColorType_to_string(SkColorType colorType) {
542 case kAlpha_8_SkColorType: return "Alpha_8";
543 case kRGB_565_SkColorType: return "RGB_565";
544 case kARGB_4444_SkColorType: return "ARGB_4444";
545 case kN32_SkColorType: return "N32";
546 case kBackwards_SkColorType: return "Backwards";
547 case kIndex_8_SkColorType: return "Index_8";
548 default: return "ERROR";
552 static inline const char* options_colorType(
553 const SkDecodingImageGenerator::Options& opts) {
554 if (opts.fUseRequestedColorType) {
555 return SkColorType_to_string(opts.fRequestedColorType);
561 static inline const char* yn(bool value) {
570 * Given either a SkStream or a SkData, try to decode the encoded
571 * image using the specified options and report errors.
573 static void test_options(skiatest::Reporter* reporter,
574 const SkDecodingImageGenerator::Options& opts,
575 SkStreamRewindable* encodedStream,
578 const SkString& path) {
580 bool success = false;
582 if (NULL == encodedData) {
585 success = SkInstallDiscardablePixelRef(
586 SkDecodingImageGenerator::Create(encodedData, opts), &bm);
588 if (NULL == encodedStream) {
591 success = SkInstallDiscardablePixelRef(
592 SkDecodingImageGenerator::Create(encodedStream->duplicate(), opts), &bm);
595 if (opts.fUseRequestedColorType
596 && (kARGB_4444_SkColorType == opts.fRequestedColorType)) {
597 return; // Ignore known conversion inabilities.
599 // If we get here, it's a failure and we will need more
600 // information about why it failed.
601 ERRORF(reporter, "Bounds decode failed [sampleSize=%d dither=%s "
602 "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
603 options_colorType(opts), path.c_str());
606 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
607 // Android is the only system that use Skia's image decoders in
608 // production. For now, we'll only verify that samplesize works
609 // on systems where it already is known to work.
610 REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight,
612 REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth,
614 // The ImageDecoder API doesn't guarantee that SampleSize does
615 // anything at all, but the decoders that this test excercises all
616 // produce an output size in the following range:
617 // (((sample_size * out_size) > (in_size - sample_size))
618 // && out_size <= SkNextPow2(((in_size - 1) / sample_size) + 1));
619 #endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
620 SkAutoLockPixels alp(bm);
621 if (bm.getPixels() == NULL) {
622 ERRORF(reporter, "Pixel decode failed [sampleSize=%d dither=%s "
623 "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
624 options_colorType(opts), path.c_str());
628 SkColorType requestedColorType = opts.fRequestedColorType;
629 REPORTER_ASSERT(reporter,
630 (!opts.fUseRequestedColorType)
631 || (bm.colorType() == requestedColorType));
633 // Condition under which we should check the decoding results:
634 if ((kN32_SkColorType == bm.colorType())
635 && (!path.endsWith(".jpg")) // lossy
636 && (opts.fSampleSize == 1)) { // scaled
637 const SkColor* correctPixels = kExpectedPixels;
638 SkASSERT(bm.height() == kExpectedHeight);
639 SkASSERT(bm.width() == kExpectedWidth);
641 for (int y = 0; y < bm.height(); ++y) {
642 for (int x = 0; x < bm.width(); ++x) {
643 if (*correctPixels != bm.getColor(x, y)) {
649 if (pixelErrors != 0) {
650 ERRORF(reporter, "Pixel-level mismatch (%d of %d) "
651 "[sampleSize=%d dither=%s colorType=%s %s]",
652 pixelErrors, kExpectedHeight * kExpectedWidth,
653 opts.fSampleSize, yn(opts.fDitherImage),
654 options_colorType(opts), path.c_str());
660 * SkDecodingImageGenerator has an Options struct which lets the
661 * client of the generator set sample size, dithering, and bitmap
662 * config. This test loops through many possible options and tries
663 * them on a set of 5 small encoded images (each in a different
664 * format). We test both SkData and SkStreamRewindable decoding.
666 DEF_TEST(ImageDecoderOptions, reporter) {
667 const char* files[] = {
672 #if !defined(SK_BUILD_FOR_WIN)
673 // TODO(halcanary): Find out why this fails sometimes.
678 SkString resourceDir = GetResourcePath();
679 if (!sk_exists(resourceDir.c_str())) {
683 int scaleList[] = {1, 2, 3, 4};
684 bool ditherList[] = {true, false};
685 SkColorType colorList[] = {
686 kAlpha_8_SkColorType,
687 kRGB_565_SkColorType,
688 kARGB_4444_SkColorType, // Most decoders will fail on 4444.
690 // Note that indexed color is left out of the list. Lazy
691 // decoding doesn't do indexed color.
693 const bool useDataList[] = {true, false};
695 for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
696 SkString path = SkOSPath::Join(resourceDir.c_str(), files[fidx]);
697 if (!sk_exists(path.c_str())) {
701 SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
702 REPORTER_ASSERT(reporter, encodedData.get() != NULL);
703 SkAutoTUnref<SkStreamRewindable> encodedStream(
704 SkStream::NewFromFile(path.c_str()));
705 REPORTER_ASSERT(reporter, encodedStream.get() != NULL);
707 for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
708 for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
709 for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
710 for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) {
711 SkDecodingImageGenerator::Options opts(scaleList[i],
714 test_options(reporter, opts, encodedStream, encodedData,
715 useDataList[m], path);
718 SkDecodingImageGenerator::Options options(scaleList[i],
720 test_options(reporter, options, encodedStream, encodedData,
721 useDataList[m], path);
728 DEF_TEST(DiscardablePixelRef_SecondLockColorTableCheck, r) {
729 SkString resourceDir = GetResourcePath();
730 SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.gif");
731 if (!sk_exists(path.c_str())) {
734 SkAutoDataUnref encoded(SkData::NewFromFileName(path.c_str()));
736 if (!SkInstallDiscardablePixelRef(
737 SkDecodingImageGenerator::Create(
738 encoded, SkDecodingImageGenerator::Options()), &bitmap)) {
739 #ifndef SK_BUILD_FOR_WIN
740 ERRORF(r, "SkInstallDiscardablePixelRef [randPixels.gif] failed.");
744 if (kIndex_8_SkColorType != bitmap.colorType()) {
748 SkAutoLockPixels alp(bitmap);
749 REPORTER_ASSERT(r, bitmap.getColorTable() && "first pass");
752 SkAutoLockPixels alp(bitmap);
753 REPORTER_ASSERT(r, bitmap.getColorTable() && "second pass");
758 ////////////////////////////////////////////////////////////////////////////////
760 class SingleAllocator : public SkBitmap::Allocator {
762 SingleAllocator(void* p, size_t s) : fPixels(p), fSize(s) { }
763 ~SingleAllocator() {}
764 // If the pixels in fPixels are big enough, use them.
765 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
767 if (bm->info().getSafeSize(bm->rowBytes()) <= fSize) {
768 bm->setPixels(fPixels, ct);
773 return bm->tryAllocPixels(NULL, ct);
775 bool ready() { return fPixels != NULL; }
782 /* This tests for a bug in libjpeg where INT32 is typedefed to long
783 and memory can be written to outside of the array. */
784 DEF_TEST(ImageDecoding_JpegOverwrite, r) {
785 SkString resourceDir = GetResourcePath();
786 SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.jpg");
787 SkAutoTUnref<SkStreamAsset> stream(
788 SkStream::NewFromFile(path.c_str()));
790 SkDebugf("\nPath '%s' missing.\n", path.c_str());
793 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
794 if (NULL == decoder.get()) {
795 ERRORF(r, "\nSkImageDecoder::Factory failed.\n");
798 SkAssertResult(stream->rewind());
800 static const uint16_t sentinal = 0xBEEF;
801 static const int pixelCount = 16;
802 SkAutoTMalloc<uint16_t> pixels(pixelCount + 1);
803 // pixels.get() should be 4-byte aligned.
804 // This is necessary to reproduce the bug.
806 pixels[pixelCount] = sentinal; // This value should not be changed.
808 SkAutoTUnref<SingleAllocator> allocator(
809 SkNEW_ARGS(SingleAllocator,
810 ((void*)pixels.get(), sizeof(uint16_t) * pixelCount)));
811 decoder->setAllocator(allocator);
812 decoder->setSampleSize(2);
814 bool success = decoder->decode(stream, &bitmap, kRGB_565_SkColorType,
815 SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
816 REPORTER_ASSERT(r, success);
817 REPORTER_ASSERT(r, !allocator->ready()); // Decoder used correct memory
818 REPORTER_ASSERT(r, sentinal == pixels[pixelCount]);