| Index: tests/ImageDecodingTest.cpp
|
| diff --git a/tests/ImageDecodingTest.cpp b/tests/ImageDecodingTest.cpp
|
| index bbc31cc81fed21663885bccc497bee0c3534f72c..d39a51a134f413a5680012f9d4bb84b6e8dd9aad 100644
|
| --- a/tests/ImageDecodingTest.cpp
|
| +++ b/tests/ImageDecodingTest.cpp
|
| @@ -13,10 +13,13 @@
|
| #include "SkColorPriv.h"
|
| #include "SkData.h"
|
| #include "SkDecodingImageGenerator.h"
|
| +#include "SkDiscardableMemoryPool.h"
|
| #include "SkForceLinking.h"
|
| #include "SkGradientShader.h"
|
| #include "SkImageDecoder.h"
|
| #include "SkImageEncoder.h"
|
| +#include "SkImageGenerator.h"
|
| +#include "SkImagePriv.h"
|
| #include "SkOSFile.h"
|
| #include "SkPoint.h"
|
| #include "SkShader.h"
|
| @@ -153,7 +156,7 @@ static void test_unpremul(skiatest::Reporter* reporter) {
|
| if (iter.next(&basename)) {
|
| do {
|
| SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), basename.c_str());
|
| - //SkDebugf("about to decode \"%s\"\n", filename.c_str());
|
| + // SkDebugf("about to decode \"%s\"\n", filename.c_str());
|
| compare_unpremul(reporter, filename);
|
| } while (iter.next(&basename));
|
| } else {
|
| @@ -201,7 +204,7 @@ static void test_stream_life() {
|
| SkImageEncoder::kWEBP_Type,
|
| };
|
| for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) {
|
| - //SkDebugf("encoding to %i\n", i);
|
| + // SkDebugf("encoding to %i\n", i);
|
| SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i]));
|
| if (NULL == stream.get()) {
|
| SkDebugf("no stream\n");
|
| @@ -228,7 +231,7 @@ static void test_stream_life() {
|
| // Test inside SkScaledBitmapSampler.cpp
|
| extern void test_row_proc_choice();
|
|
|
| -#endif // SK_DEBUG
|
| +#endif // SK_DEBUG
|
|
|
| DEF_TEST(ImageDecoding, reporter) {
|
| test_unpremul(reporter);
|
| @@ -239,6 +242,31 @@ DEF_TEST(ImageDecoding, reporter) {
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| +namespace {
|
| +// expected output for 8x8 bitmap
|
| +const int kExpectedWidth = 8;
|
| +const int kExpectedHeight = 8;
|
| +const SkColor kExpectedPixels[] = {
|
| + 0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
|
| + 0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
|
| + 0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
|
| + 0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
|
| + 0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
|
| + 0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
|
| + 0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
|
| + 0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
|
| + 0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
|
| + 0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
|
| + 0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
|
| + 0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
|
| + 0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
|
| + 0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
|
| + 0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
|
| + 0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
|
| +};
|
| +SK_COMPILE_ASSERT((kExpectedWidth * kExpectedHeight)
|
| + == SK_ARRAY_COUNT(kExpectedPixels), array_size_mismatch);
|
| +} // namespace
|
|
|
| DEF_TEST(WebP, reporter) {
|
| const unsigned char encodedWebP[] = {
|
| @@ -269,38 +297,26 @@ DEF_TEST(WebP, reporter) {
|
| 0xe3, 0xfe, 0x66, 0xa4, 0x7c, 0x1b, 0x6c, 0xd1, 0xa9, 0xd8, 0x14, 0xd0,
|
| 0xc5, 0xb5, 0x39, 0x71, 0x97, 0x19, 0x19, 0x1b
|
| };
|
| - const SkColor thePixels[] = {
|
| - 0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
|
| - 0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
|
| - 0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
|
| - 0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
|
| - 0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
|
| - 0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
|
| - 0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
|
| - 0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
|
| - 0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
|
| - 0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
|
| - 0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
|
| - 0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
|
| - 0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
|
| - 0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
|
| - 0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
|
| - 0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
|
| - };
|
| SkAutoDataUnref encoded(SkData::NewWithCopy(encodedWebP,
|
| sizeof(encodedWebP)));
|
| SkBitmap bm;
|
| - bool success = SkDecodingImageGenerator::Install(encoded, &bm, NULL);
|
| +
|
| + bool success = SkInstallDiscardablePixelRef(
|
| + SkDecodingImageGenerator::Create(encoded,
|
| + SkDecodingImageGenerator::Options()), &bm, NULL);
|
| +
|
| REPORTER_ASSERT(reporter, success);
|
| if (!success) {
|
| return;
|
| }
|
| SkAutoLockPixels alp(bm);
|
| - bool rightSize = SK_ARRAY_COUNT(thePixels) == bm.width() * bm.height();
|
| +
|
| + bool rightSize = ((kExpectedWidth == bm.width())
|
| + && (kExpectedHeight == bm.height()));
|
| REPORTER_ASSERT(reporter, rightSize);
|
| if (rightSize) {
|
| bool error = false;
|
| - const SkColor* correctPixel = thePixels;
|
| + const SkColor* correctPixel = kExpectedPixels;
|
| for (int y = 0; y < bm.height(); ++y) {
|
| for (int x = 0; x < bm.width(); ++x) {
|
| error |= (*correctPixel != bm.getColor(x, y));
|
| @@ -310,3 +326,256 @@ DEF_TEST(WebP, reporter) {
|
| REPORTER_ASSERT(reporter, !error);
|
| }
|
| }
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +// example of how Android will do this inside their BitmapFactory
|
| +static SkPixelRef* install_pixel_ref(SkBitmap* bitmap,
|
| + SkStreamRewindable* stream,
|
| + int sampleSize, bool ditherImage) {
|
| + SkASSERT(bitmap != NULL);
|
| + SkASSERT(stream != NULL);
|
| + SkASSERT(stream->rewind());
|
| + SkASSERT(stream->unique());
|
| + SkColorType colorType;
|
| + if (!SkBitmapConfigToColorType(bitmap->config(), &colorType)) {
|
| + return NULL;
|
| + }
|
| + SkDecodingImageGenerator::Options opts(sampleSize, ditherImage, colorType);
|
| + SkAutoTDelete<SkImageGenerator> gen(
|
| + SkDecodingImageGenerator::Create(stream, opts));
|
| + SkImageInfo info;
|
| + if ((NULL == gen.get()) || !gen->getInfo(&info)) {
|
| + return NULL;
|
| + }
|
| + SkDiscardableMemory::Factory* factory = NULL;
|
| + if (info.getSafeSize(info.minRowBytes()) < (32 * 1024)) {
|
| + // only use ashmem for large images, since mmaps come at a price
|
| + factory = SkGetGlobalDiscardableMemoryPool();
|
| + }
|
| + if (SkInstallDiscardablePixelRef(gen.detach(), bitmap, factory)) {
|
| + return bitmap->pixelRef();
|
| + }
|
| + return NULL;
|
| +}
|
| +/**
|
| + * A test for the SkDecodingImageGenerator::Create and
|
| + * SkInstallDiscardablePixelRef functions.
|
| + */
|
| +DEF_TEST(ImprovedBitmapFactory, reporter) {
|
| + SkString resourcePath = skiatest::Test::GetResourcePath();
|
| + SkString directory = SkOSPath::SkPathJoin(resourcePath.c_str(), "encoding");
|
| + SkString path = SkOSPath::SkPathJoin(directory.c_str(), "randPixels.png");
|
| + SkAutoTUnref<SkStreamRewindable> stream(
|
| + SkStream::NewFromFile(path.c_str()));
|
| + if (sk_exists(path.c_str())) {
|
| + SkBitmap bm;
|
| + SkAssertResult(bm.setConfig(SkBitmap::kARGB_8888_Config, 1, 1));
|
| + REPORTER_ASSERT(reporter,
|
| + NULL != install_pixel_ref(&bm, stream.detach(), 1, true));
|
| + SkAutoLockPixels alp(bm);
|
| + REPORTER_ASSERT(reporter, NULL != bm.getPixels());
|
| + }
|
| +}
|
| +
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
|
| +static inline bool check_rounding(int value, int dividend, int divisor) {
|
| + // returns true if (dividend/divisor) rounds up OR down to value
|
| + return (((divisor * value) > (dividend - divisor))
|
| + && ((divisor * value) < (dividend + divisor)));
|
| +}
|
| +#endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
|
| +
|
| +
|
| +#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
|
| + #define kBackwards_SkColorType kRGBA_8888_SkColorType
|
| +#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
|
| + #define kBackwards_SkColorType kBGRA_8888_SkColorType
|
| +#else
|
| + #error "SK_*32_SHFIT values must correspond to BGRA or RGBA byte order"
|
| +#endif
|
| +
|
| +static inline const char* SkColorType_to_string(SkColorType colorType) {
|
| + switch(colorType) {
|
| + case kAlpha_8_SkColorType: return "Alpha_8";
|
| + case kRGB_565_SkColorType: return "RGB_565";
|
| + case kARGB_4444_SkColorType: return "ARGB_4444";
|
| + case kPMColor_SkColorType: return "PMColor";
|
| + case kBackwards_SkColorType: return "Backwards";
|
| + case kIndex_8_SkColorType: return "Index_8";
|
| + default: return "ERROR";
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Given either a SkStream or a SkData, try to decode the encoded
|
| + * image using the specified options and report errors.
|
| + */
|
| +static void test_options(skiatest::Reporter* reporter,
|
| + const SkDecodingImageGenerator::Options& opts,
|
| + SkStreamRewindable* encodedStream,
|
| + SkData* encodedData,
|
| + bool useData,
|
| + const SkString& path) {
|
| + SkBitmap bm;
|
| + bool success = false;
|
| + if (useData) {
|
| + if (NULL == encodedData) {
|
| + return;
|
| + }
|
| + success = SkInstallDiscardablePixelRef(
|
| + SkDecodingImageGenerator::Create(encodedData, opts), &bm, NULL);
|
| + } else {
|
| + if (NULL == encodedStream) {
|
| + return;
|
| + }
|
| + success = SkInstallDiscardablePixelRef(
|
| + SkDecodingImageGenerator::Create(encodedStream->duplicate(), opts),
|
| + &bm, NULL);
|
| + }
|
| + if (!success) {
|
| + if (opts.fUseRequestedColorType
|
| + && (kARGB_4444_SkColorType == opts.fRequestedColorType)) {
|
| + return; // Ignore known conversion inabilities.
|
| + }
|
| + // If we get here, it's a failure and we will need more
|
| + // information about why it failed.
|
| + reporter->reportFailed(SkStringPrintf(
|
| + "Bounds decode failed "
|
| + "[sampleSize=%d dither=%s colorType=%s %s] %s:%d",
|
| + opts.fSampleSize, (opts.fDitherImage ? "yes" : "no"),
|
| + (opts.fUseRequestedColorType
|
| + ? SkColorType_to_string(opts.fRequestedColorType) : "(none)"),
|
| + path.c_str(), __FILE__, __LINE__));
|
| + return;
|
| + }
|
| + #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
|
| + // Android is the only system that use Skia's image decoders in
|
| + // production. For now, we'll only verify that samplesize works
|
| + // on systems where it already is known to work.
|
| + REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight,
|
| + opts.fSampleSize));
|
| + REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth,
|
| + opts.fSampleSize));
|
| + #endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
|
| + SkAutoLockPixels alp(bm);
|
| + if (bm.getPixels() == NULL) {
|
| + reporter->reportFailed(SkStringPrintf(
|
| + "Pixel decode failed "
|
| + "[sampleSize=%d dither=%s colorType=%s %s] %s:%d",
|
| + opts.fSampleSize, (opts.fDitherImage ? "yes" : "no"),
|
| + (opts.fUseRequestedColorType
|
| + ? SkColorType_to_string(opts.fRequestedColorType) : "(none)"),
|
| + path.c_str(), __FILE__, __LINE__));
|
| + return;
|
| + }
|
| +
|
| + SkBitmap::Config requestedConfig
|
| + = SkColorTypeToBitmapConfig(opts.fRequestedColorType);
|
| + REPORTER_ASSERT(reporter,
|
| + (!opts.fUseRequestedColorType)
|
| + || (bm.config() == requestedConfig));
|
| +
|
| + // Condition under which we should check the decoding results:
|
| + if ((SkBitmap::kARGB_8888_Config == bm.config())
|
| + && (!path.endsWith(".jpg")) // lossy
|
| + && (opts.fSampleSize == 1)) { // scaled
|
| + const SkColor* correctPixels = kExpectedPixels;
|
| + SkASSERT(bm.height() == kExpectedHeight);
|
| + SkASSERT(bm.width() == kExpectedWidth);
|
| + int pixelErrors = 0;
|
| + for (int y = 0; y < bm.height(); ++y) {
|
| + for (int x = 0; x < bm.width(); ++x) {
|
| + if (*correctPixels != bm.getColor(x, y)) {
|
| + ++pixelErrors;
|
| + }
|
| + ++correctPixels;
|
| + }
|
| + }
|
| + if (pixelErrors != 0) {
|
| + reporter->reportFailed(SkStringPrintf(
|
| + "Pixel-level mismatch (%d of %d) [sampleSize=%d "
|
| + "dither=%s colorType=%s %s] %s:%d",
|
| + pixelErrors, kExpectedHeight * kExpectedWidth,
|
| + opts.fSampleSize, (opts.fDitherImage ? "yes" : "no"),
|
| + (opts.fUseRequestedColorType
|
| + ? SkColorType_to_string(opts.fRequestedColorType)
|
| + : "(none)"), path.c_str(), __FILE__, __LINE__));
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * SkDecodingImageGenerator has an Options struct which lets the
|
| + * client of the generator set sample size, dithering, and bitmap
|
| + * config. This test loops through many possible options and tries
|
| + * them on a set of 5 small encoded images (each in a different
|
| + * format). We test both SkData and SkStreamRewindable decoding.
|
| + */
|
| +DEF_TEST(ImageDecoderOptions, reporter) {
|
| + const char* files[] = {
|
| + "randPixels.bmp",
|
| + "randPixels.jpg",
|
| + "randPixels.png",
|
| + "randPixels.webp",
|
| + #if !defined(SK_BUILD_FOR_WIN)
|
| + // TODO(halcanary): Find out why this fails sometimes.
|
| + "randPixels.gif",
|
| + #endif
|
| + };
|
| +
|
| + SkString resourceDir = skiatest::Test::GetResourcePath();
|
| + SkString directory = SkOSPath::SkPathJoin(resourceDir.c_str(), "encoding");
|
| + if (!sk_exists(directory.c_str())) {
|
| + return;
|
| + }
|
| +
|
| + int scaleList[] = {1, 2, 3, 4};
|
| + bool ditherList[] = {true, false};
|
| + SkColorType colorList[] = {
|
| + kAlpha_8_SkColorType,
|
| + kRGB_565_SkColorType,
|
| + kARGB_4444_SkColorType, // Most decoders will fail on 4444.
|
| + kPMColor_SkColorType
|
| + // Note that indexed color is left out of the list. Lazy
|
| + // decoding doesn't do indexed color.
|
| + };
|
| + const bool useDataList[] = {true, false};
|
| +
|
| + for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
|
| + SkString path = SkOSPath::SkPathJoin(directory.c_str(), files[fidx]);
|
| + if (!sk_exists(path.c_str())) {
|
| + continue;
|
| + }
|
| +
|
| + SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
|
| + REPORTER_ASSERT(reporter, encodedData.get() != NULL);
|
| + SkAutoTUnref<SkStreamRewindable> encodedStream(
|
| + SkStream::NewFromFile(path.c_str()));
|
| + REPORTER_ASSERT(reporter, encodedStream.get() != NULL);
|
| +
|
| + for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
|
| + for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
|
| + for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
|
| + for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) {
|
| + SkDecodingImageGenerator::Options opts(scaleList[i],
|
| + ditherList[j],
|
| + colorList[k]);
|
| + test_options(reporter, opts, encodedStream, encodedData,
|
| + useDataList[m], path);
|
| +
|
| + }
|
| + SkDecodingImageGenerator::Options options(scaleList[i],
|
| + ditherList[j]);
|
| + test_options(reporter, options, encodedStream, encodedData,
|
| + useDataList[m], path);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
|
|