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