ImageDecodingTest.cpp revision 58674817a7a5003556a1d0b5b8fa522782a729fa
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 "Test.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 "SkImageGenerator.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 28__SK_FORCE_IMAGE_DECODER_LINKING; 29 30/** 31 * Interprets c as an unpremultiplied color, and returns the 32 * premultiplied equivalent. 33 */ 34static SkPMColor premultiply_unpmcolor(SkPMColor c) { 35 U8CPU a = SkGetPackedA32(c); 36 U8CPU r = SkGetPackedR32(c); 37 U8CPU g = SkGetPackedG32(c); 38 U8CPU b = SkGetPackedB32(c); 39 return SkPreMultiplyARGB(a, r, g, b); 40} 41 42/** 43 * Return true if this stream format should be skipped, due 44 * to do being an opaque format or not a valid format. 45 */ 46static bool skip_image_format(SkImageDecoder::Format format) { 47 switch (format) { 48 case SkImageDecoder::kPNG_Format: 49 case SkImageDecoder::kWEBP_Format: 50 return false; 51 // Skip unknown since it will not be decoded anyway. 52 case SkImageDecoder::kUnknown_Format: 53 // Technically ICO and BMP supports alpha channels, but our image 54 // decoders do not, so skip them as well. 55 case SkImageDecoder::kICO_Format: 56 case SkImageDecoder::kBMP_Format: 57 // The rest of these are opaque. 58 case SkImageDecoder::kWBMP_Format: 59 case SkImageDecoder::kGIF_Format: 60 case SkImageDecoder::kJPEG_Format: 61 return true; 62 } 63 SkASSERT(false); 64 return true; 65} 66 67/** 68 * Test decoding an image in premultiplied mode and unpremultiplied mode and compare 69 * them. 70 */ 71static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filename) { 72 // Decode a resource: 73 SkBitmap bm8888; 74 SkBitmap bm8888Unpremul; 75 76 SkFILEStream stream(filename.c_str()); 77 78 SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream); 79 if (skip_image_format(format)) { 80 return; 81 } 82 83 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream)); 84 if (NULL == decoder.get()) { 85 SkDebugf("couldn't decode %s\n", filename.c_str()); 86 return; 87 } 88 89 bool success = decoder->decode(&stream, &bm8888, SkBitmap::kARGB_8888_Config, 90 SkImageDecoder::kDecodePixels_Mode); 91 if (!success) { 92 return; 93 } 94 95 success = stream.rewind(); 96 REPORTER_ASSERT(reporter, success); 97 if (!success) { 98 return; 99 } 100 101 decoder->setRequireUnpremultipliedColors(true); 102 success = decoder->decode(&stream, &bm8888Unpremul, SkBitmap::kARGB_8888_Config, 103 SkImageDecoder::kDecodePixels_Mode); 104 if (!success) { 105 return; 106 } 107 108 bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width() 109 && bm8888.height() == bm8888Unpremul.height(); 110 REPORTER_ASSERT(reporter, dimensionsMatch); 111 if (!dimensionsMatch) { 112 return; 113 } 114 115 // Only do the comparison if the two bitmaps are both 8888. 116 if (bm8888.config() != SkBitmap::kARGB_8888_Config 117 || bm8888Unpremul.config() != SkBitmap::kARGB_8888_Config) { 118 return; 119 } 120 121 // Now compare the two bitmaps. 122 for (int i = 0; i < bm8888.width(); ++i) { 123 for (int j = 0; j < bm8888.height(); ++j) { 124 // "c0" is the color of the premultiplied bitmap at (i, j). 125 const SkPMColor c0 = *bm8888.getAddr32(i, j); 126 // "c1" is the result of premultiplying the color of the unpremultiplied 127 // bitmap at (i, j). 128 const SkPMColor c1 = premultiply_unpmcolor(*bm8888Unpremul.getAddr32(i, j)); 129 // Compute the difference for each component. 130 int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1)); 131 int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1)); 132 int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1)); 133 int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1)); 134 135 // Alpha component must be exactly the same. 136 REPORTER_ASSERT(reporter, 0 == da); 137 138 // Color components may not match exactly due to rounding error. 139 REPORTER_ASSERT(reporter, dr <= 1); 140 REPORTER_ASSERT(reporter, dg <= 1); 141 REPORTER_ASSERT(reporter, db <= 1); 142 } 143 } 144} 145 146static void test_unpremul(skiatest::Reporter* reporter) { 147 // This test cannot run if there is no resource path. 148 SkString resourcePath = skiatest::Test::GetResourcePath(); 149 if (resourcePath.isEmpty()) { 150 SkDebugf("Could not run unpremul test because resourcePath not specified."); 151 return; 152 } 153 SkOSFile::Iter iter(resourcePath.c_str()); 154 SkString basename; 155 if (iter.next(&basename)) { 156 do { 157 SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), basename.c_str()); 158 // SkDebugf("about to decode \"%s\"\n", filename.c_str()); 159 compare_unpremul(reporter, filename); 160 } while (iter.next(&basename)); 161 } else { 162 SkDebugf("Failed to find any files :(\n"); 163 } 164} 165 166#ifdef SK_DEBUG 167// Create a stream containing a bitmap encoded to Type type. 168static SkMemoryStream* create_image_stream(SkImageEncoder::Type type) { 169 SkBitmap bm; 170 const int size = 50; 171 bm.setConfig(SkBitmap::kARGB_8888_Config, size, size); 172 bm.allocPixels(); 173 SkCanvas canvas(bm); 174 SkPoint points[2] = { 175 { SkIntToScalar(0), SkIntToScalar(0) }, 176 { SkIntToScalar(size), SkIntToScalar(size) } 177 }; 178 SkColor colors[2] = { SK_ColorWHITE, SK_ColorBLUE }; 179 SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL, 180 SK_ARRAY_COUNT(colors), 181 SkShader::kClamp_TileMode); 182 SkPaint paint; 183 paint.setShader(shader)->unref(); 184 canvas.drawPaint(paint); 185 // Now encode it to a stream. 186 SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(bm, type, 100)); 187 if (NULL == data.get()) { 188 return NULL; 189 } 190 return SkNEW_ARGS(SkMemoryStream, (data.get())); 191} 192 193// For every format that supports tile based decoding, ensure that 194// calling decodeSubset will not fail if the caller has unreffed the 195// stream provided in buildTileIndex. 196// Only runs in debug mode since we are testing for a crash. 197static void test_stream_life() { 198 const SkImageEncoder::Type gTypes[] = { 199#ifdef SK_BUILD_FOR_ANDROID 200 SkImageEncoder::kJPEG_Type, 201 SkImageEncoder::kPNG_Type, 202#endif 203 SkImageEncoder::kWEBP_Type, 204 }; 205 for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) { 206 // SkDebugf("encoding to %i\n", i); 207 SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i])); 208 if (NULL == stream.get()) { 209 SkDebugf("no stream\n"); 210 continue; 211 } 212 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); 213 if (NULL == decoder.get()) { 214 SkDebugf("no decoder\n"); 215 continue; 216 } 217 int width, height; 218 if (!decoder->buildTileIndex(stream.get(), &width, &height)) { 219 SkDebugf("could not build a tile index\n"); 220 continue; 221 } 222 // Now unref the stream to make sure it survives 223 stream.reset(NULL); 224 SkBitmap bm; 225 decoder->decodeSubset(&bm, SkIRect::MakeWH(width, height), 226 SkBitmap::kARGB_8888_Config); 227 } 228} 229 230// Test inside SkScaledBitmapSampler.cpp 231extern void test_row_proc_choice(); 232 233#endif // SK_DEBUG 234 235DEF_TEST(ImageDecoding, reporter) { 236 test_unpremul(reporter); 237#ifdef SK_DEBUG 238 test_stream_life(); 239 test_row_proc_choice(); 240#endif 241} 242 243// expected output for 8x8 bitmap 244static const int kExpectedWidth = 8; 245static const int kExpectedHeight = 8; 246static const SkColor kExpectedPixels[] = { 247 0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666, 248 0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093, 249 0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4, 250 0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3, 251 0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e, 252 0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689, 253 0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d, 254 0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46, 255 0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67, 256 0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4, 257 0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283, 258 0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4, 259 0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4, 260 0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a, 261 0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738, 262 0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df 263}; 264SK_COMPILE_ASSERT((kExpectedWidth * kExpectedHeight) 265 == SK_ARRAY_COUNT(kExpectedPixels), array_size_mismatch); 266 267DEF_TEST(WebP, reporter) { 268 const unsigned char encodedWebP[] = { 269 0x52, 0x49, 0x46, 0x46, 0x2c, 0x01, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, 270 0x56, 0x50, 0x38, 0x4c, 0x20, 0x01, 0x00, 0x00, 0x2f, 0x07, 0xc0, 0x01, 271 0x00, 0xff, 0x01, 0x45, 0x03, 0x00, 0xe2, 0xd5, 0xae, 0x60, 0x2b, 0xad, 272 0xd9, 0x68, 0x76, 0xb6, 0x8d, 0x6a, 0x1d, 0xc0, 0xe6, 0x19, 0xd6, 0x16, 273 0xb7, 0xb4, 0xef, 0xcf, 0xc3, 0x15, 0x6c, 0xb3, 0xbd, 0x77, 0x0d, 0x85, 274 0x6d, 0x1b, 0xa9, 0xb1, 0x2b, 0xdc, 0x3d, 0x83, 0xdb, 0x00, 0x00, 0xc8, 275 0x26, 0xe5, 0x01, 0x99, 0x8a, 0xd5, 0xdd, 0xfc, 0x82, 0xcd, 0xcd, 0x9a, 276 0x8c, 0x13, 0xcc, 0x1b, 0xba, 0xf5, 0x05, 0xdb, 0xee, 0x6a, 0xdb, 0x38, 277 0x60, 0xfe, 0x43, 0x2c, 0xd4, 0x6a, 0x99, 0x4d, 0xc6, 0xc0, 0xd3, 0x28, 278 0x1b, 0xc1, 0xb1, 0x17, 0x4e, 0x43, 0x0e, 0x3d, 0x27, 0xe9, 0xe4, 0x84, 279 0x4f, 0x24, 0x62, 0x69, 0x85, 0x43, 0x8d, 0xc2, 0x04, 0x00, 0x07, 0x59, 280 0x60, 0xfd, 0x8b, 0x4d, 0x60, 0x32, 0x72, 0xcf, 0x88, 0x0c, 0x2f, 0x2f, 281 0xad, 0x62, 0xbd, 0x27, 0x09, 0x16, 0x70, 0x78, 0x6c, 0xd9, 0x82, 0xef, 282 0x1a, 0xa2, 0xcc, 0xf0, 0xf1, 0x6f, 0xd8, 0x78, 0x2e, 0x39, 0xa1, 0xcf, 283 0x14, 0x4b, 0x89, 0xb4, 0x1b, 0x48, 0x15, 0x7c, 0x48, 0x6f, 0x8c, 0x20, 284 0xb7, 0x00, 0xcf, 0xfc, 0xdb, 0xd0, 0xe9, 0xe7, 0x42, 0x09, 0xa4, 0x03, 285 0x40, 0xac, 0xda, 0x40, 0x01, 0x00, 0x5f, 0xa1, 0x3d, 0x64, 0xe1, 0xf4, 286 0x03, 0x45, 0x29, 0xe0, 0xe2, 0x4a, 0xc3, 0xa2, 0xe8, 0xe0, 0x25, 0x12, 287 0x74, 0xc6, 0xe8, 0xfb, 0x93, 0x4f, 0x9f, 0x5e, 0xc0, 0xa6, 0x91, 0x1b, 288 0xa4, 0x24, 0x82, 0xc3, 0x61, 0x07, 0x4c, 0x49, 0x4f, 0x53, 0xae, 0x5f, 289 0x5d, 0x39, 0x36, 0xc0, 0x5b, 0x57, 0x54, 0x60, 0x10, 0x00, 0x00, 0xd1, 290 0x68, 0xb6, 0x6d, 0xdb, 0x36, 0x22, 0xfa, 0x1f, 0x35, 0x75, 0x22, 0xec, 291 0x31, 0xbc, 0x5d, 0x8f, 0x87, 0x53, 0xa2, 0x05, 0x8c, 0x2f, 0xcd, 0xa8, 292 0xa7, 0xf3, 0xa3, 0xbd, 0x83, 0x8b, 0x2a, 0xc8, 0x58, 0xf5, 0xac, 0x80, 293 0xe3, 0xfe, 0x66, 0xa4, 0x7c, 0x1b, 0x6c, 0xd1, 0xa9, 0xd8, 0x14, 0xd0, 294 0xc5, 0xb5, 0x39, 0x71, 0x97, 0x19, 0x19, 0x1b 295 }; 296 SkAutoDataUnref encoded(SkData::NewWithCopy(encodedWebP, 297 sizeof(encodedWebP))); 298 SkBitmap bm; 299 300 bool success = SkInstallDiscardablePixelRef( 301 SkDecodingImageGenerator::Create(encoded, 302 SkDecodingImageGenerator::Options()), &bm, NULL); 303 304 REPORTER_ASSERT(reporter, success); 305 if (!success) { 306 return; 307 } 308 SkAutoLockPixels alp(bm); 309 310 bool rightSize = ((kExpectedWidth == bm.width()) 311 && (kExpectedHeight == bm.height())); 312 REPORTER_ASSERT(reporter, rightSize); 313 if (rightSize) { 314 bool error = false; 315 const SkColor* correctPixel = kExpectedPixels; 316 for (int y = 0; y < bm.height(); ++y) { 317 for (int x = 0; x < bm.width(); ++x) { 318 error |= (*correctPixel != bm.getColor(x, y)); 319 ++correctPixel; 320 } 321 } 322 REPORTER_ASSERT(reporter, !error); 323 } 324} 325 326//////////////////////////////////////////////////////////////////////////////// 327 328// example of how Android will do this inside their BitmapFactory 329static SkPixelRef* install_pixel_ref(SkBitmap* bitmap, 330 SkStreamRewindable* stream, 331 int sampleSize, bool ditherImage) { 332 SkASSERT(bitmap != NULL); 333 SkASSERT(stream != NULL); 334 SkASSERT(stream->rewind()); 335 SkASSERT(stream->unique()); 336 SkColorType colorType; 337 if (!SkBitmapConfigToColorType(bitmap->config(), &colorType)) { 338 return NULL; 339 } 340 SkDecodingImageGenerator::Options opts(sampleSize, ditherImage, colorType); 341 SkAutoTDelete<SkImageGenerator> gen( 342 SkDecodingImageGenerator::Create(stream, opts)); 343 SkImageInfo info; 344 if ((NULL == gen.get()) || !gen->getInfo(&info)) { 345 return NULL; 346 } 347 SkDiscardableMemory::Factory* factory = NULL; 348 if (info.getSafeSize(info.minRowBytes()) < (32 * 1024)) { 349 // only use ashmem for large images, since mmaps come at a price 350 factory = SkGetGlobalDiscardableMemoryPool(); 351 } 352 if (SkInstallDiscardablePixelRef(gen.detach(), bitmap, factory)) { 353 return bitmap->pixelRef(); 354 } 355 return NULL; 356} 357/** 358 * A test for the SkDecodingImageGenerator::Create and 359 * SkInstallDiscardablePixelRef functions. 360 */ 361DEF_TEST(ImprovedBitmapFactory, reporter) { 362 SkString resourcePath = skiatest::Test::GetResourcePath(); 363 SkString directory = SkOSPath::SkPathJoin(resourcePath.c_str(), "encoding"); 364 SkString path = SkOSPath::SkPathJoin(directory.c_str(), "randPixels.png"); 365 SkAutoTUnref<SkStreamRewindable> stream( 366 SkStream::NewFromFile(path.c_str())); 367 if (sk_exists(path.c_str())) { 368 SkBitmap bm; 369 SkAssertResult(bm.setConfig(SkBitmap::kARGB_8888_Config, 1, 1)); 370 REPORTER_ASSERT(reporter, 371 NULL != install_pixel_ref(&bm, stream.detach(), 1, true)); 372 SkAutoLockPixels alp(bm); 373 REPORTER_ASSERT(reporter, NULL != bm.getPixels()); 374 } 375} 376 377 378//////////////////////////////////////////////////////////////////////////////// 379 380#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 381static inline bool check_rounding(int value, int dividend, int divisor) { 382 // returns true if (dividend/divisor) rounds up OR down to value 383 return (((divisor * value) > (dividend - divisor)) 384 && ((divisor * value) < (dividend + divisor))); 385} 386#endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX 387 388 389#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) 390 #define kBackwards_SkColorType kRGBA_8888_SkColorType 391#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) 392 #define kBackwards_SkColorType kBGRA_8888_SkColorType 393#else 394 #error "SK_*32_SHFIT values must correspond to BGRA or RGBA byte order" 395#endif 396 397static inline const char* SkColorType_to_string(SkColorType colorType) { 398 switch(colorType) { 399 case kAlpha_8_SkColorType: return "Alpha_8"; 400 case kRGB_565_SkColorType: return "RGB_565"; 401 case kARGB_4444_SkColorType: return "ARGB_4444"; 402 case kPMColor_SkColorType: return "PMColor"; 403 case kBackwards_SkColorType: return "Backwards"; 404 case kIndex_8_SkColorType: return "Index_8"; 405 default: return "ERROR"; 406 } 407} 408 409static inline const char* options_colorType( 410 const SkDecodingImageGenerator::Options& opts) { 411 if (opts.fUseRequestedColorType) { 412 return SkColorType_to_string(opts.fRequestedColorType); 413 } else { 414 return "(none)"; 415 } 416} 417 418static inline const char* yn(bool value) { 419 if (value) { 420 return "yes"; 421 } else { 422 return "no"; 423 } 424} 425 426/** 427 * Given either a SkStream or a SkData, try to decode the encoded 428 * image using the specified options and report errors. 429 */ 430static void test_options(skiatest::Reporter* reporter, 431 const SkDecodingImageGenerator::Options& opts, 432 SkStreamRewindable* encodedStream, 433 SkData* encodedData, 434 bool useData, 435 const SkString& path) { 436 SkBitmap bm; 437 bool success = false; 438 if (useData) { 439 if (NULL == encodedData) { 440 return; 441 } 442 success = SkInstallDiscardablePixelRef( 443 SkDecodingImageGenerator::Create(encodedData, opts), &bm, NULL); 444 } else { 445 if (NULL == encodedStream) { 446 return; 447 } 448 success = SkInstallDiscardablePixelRef( 449 SkDecodingImageGenerator::Create(encodedStream->duplicate(), opts), 450 &bm, NULL); 451 } 452 if (!success) { 453 if (opts.fUseRequestedColorType 454 && (kARGB_4444_SkColorType == opts.fRequestedColorType)) { 455 return; // Ignore known conversion inabilities. 456 } 457 // If we get here, it's a failure and we will need more 458 // information about why it failed. 459 ERRORF(reporter, "Bounds decode failed [sampleSize=%d dither=%s " 460 "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage), 461 options_colorType(opts), path.c_str()); 462 return; 463 } 464 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 465 // Android is the only system that use Skia's image decoders in 466 // production. For now, we'll only verify that samplesize works 467 // on systems where it already is known to work. 468 REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight, 469 opts.fSampleSize)); 470 REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth, 471 opts.fSampleSize)); 472 #endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX 473 SkAutoLockPixels alp(bm); 474 if (bm.getPixels() == NULL) { 475 ERRORF(reporter, "Pixel decode failed [sampleSize=%d dither=%s " 476 "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage), 477 options_colorType(opts), path.c_str()); 478 return; 479 } 480 481 SkBitmap::Config requestedConfig 482 = SkColorTypeToBitmapConfig(opts.fRequestedColorType); 483 REPORTER_ASSERT(reporter, 484 (!opts.fUseRequestedColorType) 485 || (bm.config() == requestedConfig)); 486 487 // Condition under which we should check the decoding results: 488 if ((SkBitmap::kARGB_8888_Config == bm.config()) 489 && (!path.endsWith(".jpg")) // lossy 490 && (opts.fSampleSize == 1)) { // scaled 491 const SkColor* correctPixels = kExpectedPixels; 492 SkASSERT(bm.height() == kExpectedHeight); 493 SkASSERT(bm.width() == kExpectedWidth); 494 int pixelErrors = 0; 495 for (int y = 0; y < bm.height(); ++y) { 496 for (int x = 0; x < bm.width(); ++x) { 497 if (*correctPixels != bm.getColor(x, y)) { 498 ++pixelErrors; 499 } 500 ++correctPixels; 501 } 502 } 503 if (pixelErrors != 0) { 504 ERRORF(reporter, "Pixel-level mismatch (%d of %d) " 505 "[sampleSize=%d dither=%s colorType=%s %s]", 506 pixelErrors, kExpectedHeight * kExpectedWidth, 507 opts.fSampleSize, yn(opts.fDitherImage), 508 options_colorType(opts), path.c_str()); 509 } 510 } 511} 512 513/** 514 * SkDecodingImageGenerator has an Options struct which lets the 515 * client of the generator set sample size, dithering, and bitmap 516 * config. This test loops through many possible options and tries 517 * them on a set of 5 small encoded images (each in a different 518 * format). We test both SkData and SkStreamRewindable decoding. 519 */ 520DEF_TEST(ImageDecoderOptions, reporter) { 521 const char* files[] = { 522 "randPixels.bmp", 523 "randPixels.jpg", 524 "randPixels.png", 525 "randPixels.webp", 526 #if !defined(SK_BUILD_FOR_WIN) 527 // TODO(halcanary): Find out why this fails sometimes. 528 "randPixels.gif", 529 #endif 530 }; 531 532 SkString resourceDir = skiatest::Test::GetResourcePath(); 533 SkString directory = SkOSPath::SkPathJoin(resourceDir.c_str(), "encoding"); 534 if (!sk_exists(directory.c_str())) { 535 return; 536 } 537 538 int scaleList[] = {1, 2, 3, 4}; 539 bool ditherList[] = {true, false}; 540 SkColorType colorList[] = { 541 kAlpha_8_SkColorType, 542 kRGB_565_SkColorType, 543 kARGB_4444_SkColorType, // Most decoders will fail on 4444. 544 kPMColor_SkColorType 545 // Note that indexed color is left out of the list. Lazy 546 // decoding doesn't do indexed color. 547 }; 548 const bool useDataList[] = {true, false}; 549 550 for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) { 551 SkString path = SkOSPath::SkPathJoin(directory.c_str(), files[fidx]); 552 if (!sk_exists(path.c_str())) { 553 continue; 554 } 555 556 SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str())); 557 REPORTER_ASSERT(reporter, encodedData.get() != NULL); 558 SkAutoTUnref<SkStreamRewindable> encodedStream( 559 SkStream::NewFromFile(path.c_str())); 560 REPORTER_ASSERT(reporter, encodedStream.get() != NULL); 561 562 for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) { 563 for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) { 564 for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) { 565 for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) { 566 SkDecodingImageGenerator::Options opts(scaleList[i], 567 ditherList[j], 568 colorList[k]); 569 test_options(reporter, opts, encodedStream, encodedData, 570 useDataList[m], path); 571 572 } 573 SkDecodingImageGenerator::Options options(scaleList[i], 574 ditherList[j]); 575 test_options(reporter, options, encodedStream, encodedData, 576 useDataList[m], path); 577 } 578 } 579 } 580 } 581} 582