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 "TestClassDef.h" 10 #include "SkBitmap.h" 11 #include "SkCanvas.h" 12 #include "SkColor.h" 13 #include "SkColorPriv.h" 14 #include "SkData.h" 15 #include "SkForceLinking.h" 16 #include "SkGradientShader.h" 17 #include "SkImageDecoder.h" 18 #include "SkImageEncoder.h" 19 #include "SkOSFile.h" 20 #include "SkPoint.h" 21 #include "SkShader.h" 22 #include "SkStream.h" 23 #include "SkString.h" 24 25 __SK_FORCE_IMAGE_DECODER_LINKING; 26 27 /** 28 * Interprets c as an unpremultiplied color, and returns the 29 * premultiplied equivalent. 30 */ 31 static SkPMColor premultiply_unpmcolor(SkPMColor c) { 32 U8CPU a = SkGetPackedA32(c); 33 U8CPU r = SkGetPackedR32(c); 34 U8CPU g = SkGetPackedG32(c); 35 U8CPU b = SkGetPackedB32(c); 36 return SkPreMultiplyARGB(a, r, g, b); 37 } 38 39 /** 40 * Return true if this stream format should be skipped, due 41 * to do being an opaque format or not a valid format. 42 */ 43 static bool skip_image_format(SkImageDecoder::Format format) { 44 switch (format) { 45 case SkImageDecoder::kPNG_Format: 46 case SkImageDecoder::kWEBP_Format: 47 return false; 48 // Skip unknown since it will not be decoded anyway. 49 case SkImageDecoder::kUnknown_Format: 50 // Technically ICO and BMP supports alpha channels, but our image 51 // decoders do not, so skip them as well. 52 case SkImageDecoder::kICO_Format: 53 case SkImageDecoder::kBMP_Format: 54 // The rest of these are opaque. 55 case SkImageDecoder::kWBMP_Format: 56 case SkImageDecoder::kGIF_Format: 57 case SkImageDecoder::kJPEG_Format: 58 return true; 59 } 60 SkASSERT(false); 61 return true; 62 } 63 64 /** 65 * Test decoding an image in premultiplied mode and unpremultiplied mode and compare 66 * them. 67 */ 68 static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filename) { 69 // Decode a resource: 70 SkBitmap bm8888; 71 SkBitmap bm8888Unpremul; 72 73 SkFILEStream stream(filename.c_str()); 74 75 SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream); 76 if (skip_image_format(format)) { 77 return; 78 } 79 80 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream)); 81 if (NULL == decoder.get()) { 82 SkDebugf("couldn't decode %s\n", filename.c_str()); 83 return; 84 } 85 86 bool success = decoder->decode(&stream, &bm8888, SkBitmap::kARGB_8888_Config, 87 SkImageDecoder::kDecodePixels_Mode); 88 if (!success) { 89 return; 90 } 91 92 success = stream.rewind(); 93 REPORTER_ASSERT(reporter, success); 94 if (!success) { 95 return; 96 } 97 98 decoder->setRequireUnpremultipliedColors(true); 99 success = decoder->decode(&stream, &bm8888Unpremul, SkBitmap::kARGB_8888_Config, 100 SkImageDecoder::kDecodePixels_Mode); 101 if (!success) { 102 return; 103 } 104 105 bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width() 106 && bm8888.height() == bm8888Unpremul.height(); 107 REPORTER_ASSERT(reporter, dimensionsMatch); 108 if (!dimensionsMatch) { 109 return; 110 } 111 112 // Only do the comparison if the two bitmaps are both 8888. 113 if (bm8888.config() != SkBitmap::kARGB_8888_Config 114 || bm8888Unpremul.config() != SkBitmap::kARGB_8888_Config) { 115 return; 116 } 117 118 // Now compare the two bitmaps. 119 for (int i = 0; i < bm8888.width(); ++i) { 120 for (int j = 0; j < bm8888.height(); ++j) { 121 // "c0" is the color of the premultiplied bitmap at (i, j). 122 const SkPMColor c0 = *bm8888.getAddr32(i, j); 123 // "c1" is the result of premultiplying the color of the unpremultiplied 124 // bitmap at (i, j). 125 const SkPMColor c1 = premultiply_unpmcolor(*bm8888Unpremul.getAddr32(i, j)); 126 // Compute the difference for each component. 127 int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1)); 128 int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1)); 129 int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1)); 130 int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1)); 131 132 // Alpha component must be exactly the same. 133 REPORTER_ASSERT(reporter, 0 == da); 134 135 // Color components may not match exactly due to rounding error. 136 REPORTER_ASSERT(reporter, dr <= 1); 137 REPORTER_ASSERT(reporter, dg <= 1); 138 REPORTER_ASSERT(reporter, db <= 1); 139 } 140 } 141 } 142 143 static void test_unpremul(skiatest::Reporter* reporter) { 144 // This test cannot run if there is no resource path. 145 SkString resourcePath = skiatest::Test::GetResourcePath(); 146 if (resourcePath.isEmpty()) { 147 SkDebugf("Could not run unpremul test because resourcePath not specified."); 148 return; 149 } 150 SkOSFile::Iter iter(resourcePath.c_str()); 151 SkString basename; 152 if (iter.next(&basename)) { 153 do { 154 SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), basename.c_str()); 155 //SkDebugf("about to decode \"%s\"\n", filename.c_str()); 156 compare_unpremul(reporter, filename); 157 } while (iter.next(&basename)); 158 } else { 159 SkDebugf("Failed to find any files :(\n"); 160 } 161 } 162 163 #ifdef SK_DEBUG 164 // Create a stream containing a bitmap encoded to Type type. 165 static SkMemoryStream* create_image_stream(SkImageEncoder::Type type) { 166 SkBitmap bm; 167 const int size = 50; 168 bm.setConfig(SkBitmap::kARGB_8888_Config, size, size); 169 bm.allocPixels(); 170 SkCanvas canvas(bm); 171 SkPoint points[2] = { 172 { SkIntToScalar(0), SkIntToScalar(0) }, 173 { SkIntToScalar(size), SkIntToScalar(size) } 174 }; 175 SkColor colors[2] = { SK_ColorWHITE, SK_ColorBLUE }; 176 SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL, 177 SK_ARRAY_COUNT(colors), 178 SkShader::kClamp_TileMode); 179 SkPaint paint; 180 paint.setShader(shader)->unref(); 181 canvas.drawPaint(paint); 182 // Now encode it to a stream. 183 SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(bm, type, 100)); 184 if (NULL == data.get()) { 185 return NULL; 186 } 187 return SkNEW_ARGS(SkMemoryStream, (data.get())); 188 } 189 190 // For every format that supports tile based decoding, ensure that 191 // calling decodeSubset will not fail if the caller has unreffed the 192 // stream provided in buildTileIndex. 193 // Only runs in debug mode since we are testing for a crash. 194 static void test_stream_life() { 195 const SkImageEncoder::Type gTypes[] = { 196 #ifdef SK_BUILD_FOR_ANDROID 197 SkImageEncoder::kJPEG_Type, 198 SkImageEncoder::kPNG_Type, 199 #endif 200 SkImageEncoder::kWEBP_Type, 201 }; 202 for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) { 203 //SkDebugf("encoding to %i\n", i); 204 SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i])); 205 if (NULL == stream.get()) { 206 SkDebugf("no stream\n"); 207 continue; 208 } 209 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); 210 if (NULL == decoder.get()) { 211 SkDebugf("no decoder\n"); 212 continue; 213 } 214 int width, height; 215 if (!decoder->buildTileIndex(stream.get(), &width, &height)) { 216 SkDebugf("could not build a tile index\n"); 217 continue; 218 } 219 // Now unref the stream to make sure it survives 220 stream.reset(NULL); 221 SkBitmap bm; 222 decoder->decodeSubset(&bm, SkIRect::MakeWH(width, height), 223 SkBitmap::kARGB_8888_Config); 224 } 225 } 226 227 // Test inside SkScaledBitmapSampler.cpp 228 extern void test_row_proc_choice(); 229 230 #endif // SK_DEBUG 231 232 DEF_TEST(ImageDecoding, reporter) { 233 test_unpremul(reporter); 234 #ifdef SK_DEBUG 235 test_stream_life(); 236 test_row_proc_choice(); 237 #endif 238 } 239