Parse ICC profiles from webps
authormsarett <msarett@google.com>
Wed, 24 Aug 2016 14:36:06 +0000 (07:36 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 24 Aug 2016 14:36:06 +0000 (07:36 -0700)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2269333002

Review-Url: https://codereview.chromium.org/2269333002

resources/webp-color-profile-crash.webp [new file with mode: 0644]
resources/webp-color-profile-lossless.webp [new file with mode: 0644]
resources/webp-color-profile-lossy-alpha.webp [new file with mode: 0644]
resources/webp-color-profile-lossy.webp [new file with mode: 0644]
src/codec/SkWebpCodec.cpp
src/codec/SkWebpCodec.h
tests/ColorSpaceTest.cpp

diff --git a/resources/webp-color-profile-crash.webp b/resources/webp-color-profile-crash.webp
new file mode 100644 (file)
index 0000000..3b0904e
Binary files /dev/null and b/resources/webp-color-profile-crash.webp differ
diff --git a/resources/webp-color-profile-lossless.webp b/resources/webp-color-profile-lossless.webp
new file mode 100644 (file)
index 0000000..4fd63d5
Binary files /dev/null and b/resources/webp-color-profile-lossless.webp differ
diff --git a/resources/webp-color-profile-lossy-alpha.webp b/resources/webp-color-profile-lossy-alpha.webp
new file mode 100644 (file)
index 0000000..1a13084
Binary files /dev/null and b/resources/webp-color-profile-lossy-alpha.webp differ
diff --git a/resources/webp-color-profile-lossy.webp b/resources/webp-color-profile-lossy.webp
new file mode 100644 (file)
index 0000000..fdff0a9
Binary files /dev/null and b/resources/webp-color-profile-lossy.webp differ
index e434142..c28d077 100644 (file)
@@ -18,6 +18,7 @@
 // If moving libwebp out of skia source tree, path for webp headers must be
 // updated accordingly. Here, we enforce using local copy in webp sub-directory.
 #include "webp/decode.h"
+#include "webp/demux.h"
 #include "webp/encode.h"
 
 bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) {
@@ -97,18 +98,35 @@ SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) {
             return nullptr;
     }
 
+    // FIXME (msarett):
+    // Temporary strategy for getting ICC profiles from webps.  Once the incremental decoding
+    // API lands, we will use the WebPDemuxer to manage the entire decode.
+    sk_sp<SkColorSpace> colorSpace = nullptr;
+    const void* memory = stream->getMemoryBase();
+    if (memory) {
+        WebPData data = { (const uint8_t*) memory, stream->getLength() };
+        WebPDemuxState state;
+        SkAutoTCallVProc<WebPDemuxer, WebPDemuxDelete> demux(WebPDemuxPartial(&data, &state));
+
+        WebPChunkIterator chunkIterator;
+        SkAutoTCallVProc<WebPChunkIterator, WebPDemuxReleaseChunkIterator> autoCI(&chunkIterator);
+        if (demux && WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) {
+            colorSpace = SkColorSpace::NewICC(chunkIterator.chunk.bytes, chunkIterator.chunk.size);
+        }
+    }
+
+    if (!colorSpace) {
+        colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+    }
+
     SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
-    return new SkWebpCodec(features.width, features.height, info, streamDeleter.release());
+    return new SkWebpCodec(features.width, features.height, info, colorSpace,
+                           streamDeleter.release());
 }
 
 // This version is slightly different from SkCodecPriv's version of conversion_possible. It
 // supports both byte orders for 8888.
 static bool webp_conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
-    // FIXME: skbug.com/4895
-    // Currently, we ignore the SkColorProfileType on the SkImageInfo.  We
-    // will treat the encoded data as linear regardless of what the client
-    // requests.
-
     if (!valid_alpha(dst.alphaType(), src.alphaType())) {
         return false;
     }
@@ -271,7 +289,7 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
     }
 }
 
-SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream)
-    // The spec says an unmarked image is sRGB, so we return that space here.
-    // TODO: Add support for parsing ICC profiles from webps.
-    : INHERITED(width, height, info, stream, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)) {}
+SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info,
+                         sk_sp<SkColorSpace> colorSpace, SkStream* stream)
+    : INHERITED(width, height, info, stream, colorSpace)
+{}
index 908bf2c..6fda7c2 100644 (file)
@@ -34,7 +34,7 @@ protected:
 
     bool onGetValidSubset(SkIRect* /* desiredSubset */) const override;
 private:
-    SkWebpCodec(int width, int height, const SkEncodedInfo&, SkStream*);
+    SkWebpCodec(int width, int height, const SkEncodedInfo&, sk_sp<SkColorSpace>, SkStream*);
 
     typedef SkCodec INHERITED;
 };
index 393d753..3eb145b 100644 (file)
@@ -21,9 +21,9 @@ static void test_space(skiatest::Reporter* r, SkColorSpace* space,
                        const float red[], const float green[], const float blue[],
                        const SkColorSpace::GammaNamed expectedGamma) {
 
+    REPORTER_ASSERT(r, nullptr != space);
     REPORTER_ASSERT(r, expectedGamma == space->gammaNamed());
 
-
     const SkMatrix44& mat = space->xyz();
     const float src[] = {
         1, 0, 0, 1,
@@ -39,23 +39,15 @@ static void test_space(skiatest::Reporter* r, SkColorSpace* space,
     }
 }
 
-const float g_sRGB_XYZ[] = { 0.4358f, 0.2224f, 0.0139f,   // R
-                             0.3853f, 0.7170f, 0.0971f,   // G
-                             0.1430f, 0.0606f, 0.7139f }; // B
-
-DEF_TEST(ColorSpace_sRGB, r) {
-    test_space(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(),
-               g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], SkColorSpace::kSRGB_GammaNamed);
-
-}
-
 static SkStreamAsset* resource(const char path[]) {
     SkString fullPath = GetResourcePath(path);
     return SkStream::NewFromFile(fullPath.c_str());
 }
 
-DEF_TEST(ColorSpaceParsePngICCProfile, r) {
-    SkAutoTDelete<SkStream> stream(resource("color_wheel_with_profile.png"));
+static void test_path(skiatest::Reporter* r, const char* path,
+                      const float red[], const float green[], const float blue[],
+                      const SkColorSpace::GammaNamed expectedGamma) {
+    SkAutoTDelete<SkStream> stream(resource(path));
     REPORTER_ASSERT(r, nullptr != stream);
     if (!stream) {
         return;
@@ -63,36 +55,44 @@ DEF_TEST(ColorSpaceParsePngICCProfile, r) {
 
     SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
     REPORTER_ASSERT(r, nullptr != codec);
+    if (!codec) {
+        return;
+    }
 
-#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
     SkColorSpace* colorSpace = codec->getInfo().colorSpace();
-    REPORTER_ASSERT(r, nullptr != colorSpace);
-
-    test_space(r, colorSpace, &g_sRGB_XYZ[0], &g_sRGB_XYZ[3], &g_sRGB_XYZ[6],
-               SkColorSpace::kSRGB_GammaNamed);
-#endif
+    test_space(r, colorSpace, red, green, blue, expectedGamma);
 }
 
-DEF_TEST(ColorSpaceParseJpegICCProfile, r) {
-    SkAutoTDelete<SkStream> stream(resource("icc-v2-gbr.jpg"));
-    REPORTER_ASSERT(r, nullptr != stream);
-    if (!stream) {
-        return;
-    }
+const float g_sRGB_XYZ[] = { 0.4358f, 0.2224f, 0.0139f,   // R
+                             0.3853f, 0.7170f, 0.0971f,   // G
+                             0.1430f, 0.0606f, 0.7139f }; // B
 
-    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
-    REPORTER_ASSERT(r, nullptr != codec);
-    if (!codec) {
-        return;
-    }
+DEF_TEST(ColorSpace_sRGB, r) {
+    test_space(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(),
+               g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], SkColorSpace::kSRGB_GammaNamed);
 
-    SkColorSpace* colorSpace = codec->getInfo().colorSpace();
-    REPORTER_ASSERT(r, nullptr != colorSpace);
+}
+
+DEF_TEST(ColorSpaceParseICCProfiles, r) {
+
+#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
+    test_path(r, "color_wheel_with_profile.png", &g_sRGB_XYZ[0], &g_sRGB_XYZ[3], &g_sRGB_XYZ[6],
+              SkColorSpace::kSRGB_GammaNamed);
+#endif
 
     const float red[] = { 0.385117f, 0.716904f, 0.0970612f };
     const float green[] = { 0.143051f, 0.0606079f, 0.713913f };
     const float blue[] = { 0.436035f, 0.222488f, 0.013916f };
-    test_space(r, colorSpace, red, green, blue, SkColorSpace::k2Dot2Curve_GammaNamed);
+    test_path(r, "icc-v2-gbr.jpg", red, green, blue, SkColorSpace::k2Dot2Curve_GammaNamed);
+
+    test_path(r, "webp-color-profile-crash.webp",
+            red, green, blue, SkColorSpace::kNonStandard_GammaNamed);
+    test_path(r, "webp-color-profile-lossless.webp",
+            red, green, blue, SkColorSpace::kNonStandard_GammaNamed);
+    test_path(r, "webp-color-profile-lossy.webp",
+            red, green, blue, SkColorSpace::kNonStandard_GammaNamed);
+    test_path(r, "webp-color-profile-lossy-alpha.webp",
+            red, green, blue, SkColorSpace::kNonStandard_GammaNamed);
 }
 
 DEF_TEST(ColorSpaceSRGBCompare, r) {