From daaea2d51f145fd43221a2b923721b218c8ff777 Mon Sep 17 00:00:00 2001 From: "scroggo@google.com" Date: Fri, 14 Jun 2013 20:39:48 +0000 Subject: Fixes for unpremul decode. SkImageDecoder_CG.cpp: If a non opaque bitmap was decoded, and the caller wants unpremultiplied, unpremultiply the colors. Always use the RGB colorspace, since the other colorspaces do not match the desired bitmap format. ImageDecodingTest: Allow for a difference of 1 in each color component when comparing the result of premultiplying the unpremultiplied decode with the premultiplied decode, since I found an image (in WEBP format) where the unpremultiplied colors did not compare perfectly in my comparison. R=reed@google.com Review URL: https://codereview.chromium.org/17084012 git-svn-id: http://skia.googlecode.com/svn/trunk@9628 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/ports/SkImageDecoder_CG.cpp | 37 ++++++++++++++++++++++++++----------- tests/ImageDecodingTest.cpp | 11 +++++------ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp index 5fe6fddf90..7734ea527b 100644 --- a/src/ports/SkImageDecoder_CG.cpp +++ b/src/ports/SkImageDecoder_CG.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2008 The Android Open Source Project * @@ -6,14 +5,14 @@ * found in the LICENSE file. */ +#include "SkCGUtils.h" #include "SkColorPriv.h" - #include "SkImageDecoder.h" #include "SkImageEncoder.h" #include "SkMovie.h" #include "SkStream.h" #include "SkTemplates.h" -#include "SkCGUtils.h" +#include "SkUnPreMultiply.h" #ifdef SK_BUILD_FOR_MAC #include @@ -50,6 +49,17 @@ protected: virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); }; +// Returns an unpremultiplied version of color. It will have the same ordering and size as an +// SkPMColor, but the alpha will not be premultiplied. +static SkPMColor unpremultiply_pmcolor(SkPMColor color) { + U8CPU a = SkGetPackedA32(color); + const SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(a); + return SkPackARGB32NoCheck(a, + SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(color)), + SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(color)), + SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(color))); +} + #define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast) bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { @@ -80,15 +90,10 @@ bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { bm->lockPixels(); bm->eraseColor(SK_ColorTRANSPARENT); - // use the same colorspace, so we don't change the pixels at all - CGColorSpaceRef cs = CGImageGetColorSpace(image); + CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); CGContextRef cg = CGBitmapContextCreate(bm->getPixels(), width, height, 8, bm->rowBytes(), cs, BITMAP_INFO); - if (NULL == cg) { - // perhaps the image's colorspace does not work for a context, so try just rgb - cs = CGColorSpaceCreateDeviceRGB(); - cg = CGBitmapContextCreate(bm->getPixels(), width, height, 8, bm->rowBytes(), cs, BITMAP_INFO); - CFRelease(cs); - } + CFRelease(cs); + CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image); CGContextRelease(cg); @@ -104,6 +109,16 @@ bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { // we don't know if we're opaque or not, so compute it. bm->computeAndSetOpaquePredicate(); } + if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) { + // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied. + // Convert to unpremultiplied. + for (int i = 0; i < width; ++i) { + for (int j = 0; j < height; ++j) { + uint32_t* addr = bm->getAddr32(i, j); + *addr = unpremultiply_pmcolor(*addr); + } + } + } bm->unlockPixels(); return true; } diff --git a/tests/ImageDecodingTest.cpp b/tests/ImageDecodingTest.cpp index f30a0b25b7..9a5d45bcfa 100644 --- a/tests/ImageDecodingTest.cpp +++ b/tests/ImageDecodingTest.cpp @@ -123,12 +123,11 @@ static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filen // Alpha component must be exactly the same. REPORTER_ASSERT(reporter, 0 == da); - // Other components may differ if rounding is done differently, - // but currently that is not the case. If an image fails here - // in the future, we can change these to account for differences. - REPORTER_ASSERT(reporter, 0 == dr); - REPORTER_ASSERT(reporter, 0 == dg); - REPORTER_ASSERT(reporter, 0 == db); + + // Color components may not match exactly due to rounding error. + REPORTER_ASSERT(reporter, dr <= 1); + REPORTER_ASSERT(reporter, dg <= 1); + REPORTER_ASSERT(reporter, db <= 1); } } } -- cgit v1.2.3