Home | History | Annotate | Download | only in tests
      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