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