Title: [96000] trunk
Revision
96000
Author
[email protected]
Date
2011-09-26 15:07:33 -0700 (Mon, 26 Sep 2011)

Log Message

Fix nonpremultiplied webgl toDataURL to jpeg
https://bugs.webkit.org/show_bug.cgi?id=68366

Source/WebCore:

The canvas spec says that toDataURL to formats without an alpha must
be "composited onto a solid black background using the source-over
operator." Do that.

Patch by John Bauman <[email protected]> on 2011-09-26
Reviewed by Kenneth Russell.

* platform/graphics/cg/ImageBufferCG.cpp:
(WebCore::CGImageToDataURL):
(WebCore::ImageBuffer::toDataURL):
(WebCore::ImageDataToDataURL):
* platform/image-encoders/skia/JPEGImageEncoder.cpp:
(WebCore::RGBAtoRGB):

LayoutTests:

Update the premultiplyalpha-test from the WebGL conformance tests.
Also use the correct expected result for toDataURL.jpeg.alpha.html.

Patch by John Bauman <[email protected]> on 2011-09-26
Reviewed by Kenneth Russell.

* fast/canvas/webgl/premultiplyalpha-test-expected.txt:
* fast/canvas/webgl/premultiplyalpha-test.html:
* platform/mac/canvas/philip/tests/toDataURL.jpeg.alpha-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (95999 => 96000)


--- trunk/LayoutTests/ChangeLog	2011-09-26 22:00:06 UTC (rev 95999)
+++ trunk/LayoutTests/ChangeLog	2011-09-26 22:07:33 UTC (rev 96000)
@@ -1,3 +1,17 @@
+2011-09-26  John Bauman  <[email protected]>
+
+        Fix nonpremultiplied webgl toDataURL to jpeg
+        https://bugs.webkit.org/show_bug.cgi?id=68366
+
+        Update the premultiplyalpha-test from the WebGL conformance tests.
+        Also use the correct expected result for toDataURL.jpeg.alpha.html.
+
+        Reviewed by Kenneth Russell.
+
+        * fast/canvas/webgl/premultiplyalpha-test-expected.txt:
+        * fast/canvas/webgl/premultiplyalpha-test.html:
+        * platform/mac/canvas/philip/tests/toDataURL.jpeg.alpha-expected.txt:
+
 2011-09-26  Ryosuke Niwa  <[email protected]>
 
         Add a failing expectation to the test added by r95964 on Chromium Linux and Chromium Windows.

Modified: trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test-expected.txt (95999 => 96000)


--- trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test-expected.txt	2011-09-26 22:00:06 UTC (rev 95999)
+++ trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test-expected.txt	2011-09-26 22:07:33 UTC (rev 96000)
@@ -3,35 +3,57 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-testing: premultipliedAlpha: true toDataURL: true
+testing: premultipliedAlpha: true imageFormat: image/png
 PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
+PASS gl.getContextAttributes().preserveDrawingBuffer is true
 PASS getError was expected value: NO_ERROR : Should be no errors from setup.
 PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
 PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
 PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
 PASS should draw with 64,128,255,128
 
-testing: premultipliedAlpha: true toDataURL: false
+testing: premultipliedAlpha: true imageFormat: undefined
 PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
+PASS gl.getContextAttributes().preserveDrawingBuffer is true
 PASS getError was expected value: NO_ERROR : Should be no errors from setup.
 PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
 PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
 PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
 PASS should draw with 64,128,255,128
 
-testing: premultipliedAlpha: false toDataURL: true
+testing: premultipliedAlpha: false imageFormat: image/png
 PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
+PASS gl.getContextAttributes().preserveDrawingBuffer is true
 PASS getError was expected value: NO_ERROR : Should be no errors from setup.
 PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
 PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
 PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
 PASS should draw with 255,192,128,1
 
-testing: premultipliedAlpha: false toDataURL: false
+testing: premultipliedAlpha: false imageFormat: undefined
 PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
+PASS gl.getContextAttributes().preserveDrawingBuffer is true
 PASS getError was expected value: NO_ERROR : Should be no errors from setup.
 PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
 PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
 PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
 PASS should draw with 255,192,128,1
 
+testing: premultipliedAlpha: false imageFormat: image/jpeg
+PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
+PASS gl.getContextAttributes().preserveDrawingBuffer is true
+PASS getError was expected value: NO_ERROR : Should be no errors from setup.
+PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
+PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
+PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
+PASS should draw with 128,128,128,255
+
+testing: premultipliedAlpha: true imageFormat: image/jpeg
+PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
+PASS gl.getContextAttributes().preserveDrawingBuffer is true
+PASS getError was expected value: NO_ERROR : Should be no errors from setup.
+PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
+PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
+PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
+PASS should draw with 128,128,128,255
+

Modified: trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test.html (95999 => 96000)


--- trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test.html	2011-09-26 22:00:06 UTC (rev 95999)
+++ trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test.html	2011-09-26 22:07:33 UTC (rev 96000)
@@ -1,7 +1,7 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-  "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE html>
 <html>
 <head>
+<meta charset="utf-8">
 <title>Test the WebGL premultipledAlpha context creation flag.</title>
 <link rel="stylesheet" href=""
 <script src=""
@@ -21,7 +21,7 @@
     sentColor: [32, 64, 128, 128],
     expectedColor: [64, 128, 255, 128],
     errorRange: 2,
-    useToDataURL: true,
+    imageFormat: "image/png"
   },
   // If premultipledAlpha is true then
   // [texture]           [canvas]             [texture]
@@ -30,7 +30,6 @@
     sentColor: [32, 64, 128, 128],
     expectedColor: [64, 128, 255, 128],
     errorRange: 2,
-    useToDataURL: false,
   },
   // If premultipledAlpha is false then
   // [texture]           [canvas]            [dataURL]
@@ -39,7 +38,7 @@
     sentColor: [255, 192, 128, 1],
     expectedColor: [255, 192, 128, 1],
     errorRange: 0,
-    useToDataURL: true,
+    imageFormat: "image/png"
   },
   // If premultipledAlpha is false then
   // [texture]           [canvas]            [texture]
@@ -48,7 +47,24 @@
     sentColor: [255, 192, 128, 1],
     expectedColor: [255, 192, 128, 1],
     errorRange: 0,
-    useToDataURL: false,
+  },
+  // If premultipledAlpha is false then
+  // [texture]             [canvas]            [dataURL]
+  // 255, 255, 255, 128 -> 255, 255, 255, 128 -> 128, 128, 128, 255
+  { creationAttributes: {premultipliedAlpha: false},
+    sentColor: [255, 255, 255, 128],
+    expectedColor: [128, 128, 128, 255],
+    errorRange: 2,
+    imageFormat: "image/jpeg"
+  },
+  // If premultipledAlpha is true then
+  // [texture]             [canvas]            [dataURL]
+  // 128, 128, 128, 128 -> 255, 255, 255, 128 -> 128, 128, 128, 255
+  { creationAttributes: {},
+    sentColor: [128, 128, 128, 128],
+    expectedColor: [128, 128, 128, 255],
+    errorRange: 2,
+    imageFormat: "image/jpeg"
   }
 ];
 
@@ -68,12 +84,15 @@
   if (g_count < tests.length) {
      var test = tests[g_count++];
      canvas = document.createElement("canvas");
+     // Need to preserve drawing buffer to load it in a callback
+     test.creationAttributes.preserveDrawingBuffer = true;
      gl = wtu.create3DContext(canvas, test.creationAttributes);
      var premultipliedAlpha = test.creationAttributes.premultipliedAlpha != false;
      debug("")
-     debug("testing: premultipliedAlpha: " + premultipliedAlpha + " toDataURL: " + test.useToDataURL);
+     debug("testing: premultipliedAlpha: " + premultipliedAlpha + " imageFormat: " + test.imageFormat);
 
      shouldBe('gl.getContextAttributes().premultipledAlpha', 'premultipledAlpha');
+     shouldBeTrue('gl.getContextAttributes().preserveDrawingBuffer');
 
      var program = wtu.setupTexturedQuad(gl);
 
@@ -96,7 +115,7 @@
        // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
        gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false);
        gl.bindTexture(gl.TEXTURE_2D, pngTex);
-       if (test.useToDataURL) {
+       if (test.imageFormat) {
           // create texture from image
           gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this);
        } else {
@@ -117,13 +136,20 @@
        doNextTest();
      }
 
-     if (test.useToDataURL) {
+     if (test.imageFormat) {
         // Load canvas into string using toDataURL
-        var png = canvas.toDataURL();
-        // Load string into the texture
-        var input = document.createElement("img");
-        input._onload_ = loadTexture;
-        input.src = ""
+        var imageUrl = canvas.toDataURL(test.imageFormat);
+        if (test.imageFormat != "image/png" &&
+            (imageUrl.indexOf("data:image/png,") == 0 ||
+             imageUrl.indexOf("data:image/png;") == 0)) {
+          debug("Image format " + test.imageFormat + " not supported; skipping");
+          setTimeout(doNextTest, 0);
+        } else {
+          // Load string into the texture
+          var input = document.createElement("img");
+          input._onload_ = loadTexture;
+          input.src = ""
+        }
      } else {
         // Load canvas into the texture asynchronously (to prevent unbounded stack consumption)
         setTimeout(loadTexture, 0);
@@ -138,9 +164,6 @@
 
 </script>
 
-<script>
-</script>
-
 </body>
 </html>
 

Modified: trunk/LayoutTests/platform/mac/canvas/philip/tests/toDataURL.jpeg.alpha-expected.txt (95999 => 96000)


--- trunk/LayoutTests/platform/mac/canvas/philip/tests/toDataURL.jpeg.alpha-expected.txt	2011-09-26 22:00:06 UTC (rev 95999)
+++ trunk/LayoutTests/platform/mac/canvas/philip/tests/toDataURL.jpeg.alpha-expected.txt	2011-09-26 22:07:33 UTC (rev 96000)
@@ -1 +1 @@
-Failed assertion: got pixel [193,255,192,255] at (50,25), expected [63,127,63,255] +/- 8
+Passed

Modified: trunk/Source/WebCore/ChangeLog (95999 => 96000)


--- trunk/Source/WebCore/ChangeLog	2011-09-26 22:00:06 UTC (rev 95999)
+++ trunk/Source/WebCore/ChangeLog	2011-09-26 22:07:33 UTC (rev 96000)
@@ -1,3 +1,21 @@
+2011-09-26  John Bauman  <[email protected]>
+
+        Fix nonpremultiplied webgl toDataURL to jpeg
+        https://bugs.webkit.org/show_bug.cgi?id=68366
+
+        The canvas spec says that toDataURL to formats without an alpha must
+        be "composited onto a solid black background using the source-over
+        operator." Do that.
+
+        Reviewed by Kenneth Russell.
+
+        * platform/graphics/cg/ImageBufferCG.cpp:
+        (WebCore::CGImageToDataURL):
+        (WebCore::ImageBuffer::toDataURL):
+        (WebCore::ImageDataToDataURL):
+        * platform/image-encoders/skia/JPEGImageEncoder.cpp:
+        (WebCore::RGBAtoRGB):
+
 2011-09-26  Raphael Kubo da Costa  <[email protected]>
 
         [CMake] Remove FindFreetype.cmake

Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp (95999 => 96000)


--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp	2011-09-26 22:00:06 UTC (rev 95999)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp	2011-09-26 22:07:33 UTC (rev 96000)
@@ -343,6 +343,9 @@
         imageProperties.adoptCF(CFDictionaryCreate(0, &key, &value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
     }
 
+    // Setting kCGImageDestinationBackgroundColor to black in imageProperties would allow saving some math in the
+    // calling functions, but it doesn't seem to work.
+
     CGImageDestinationAddImage(destination.get(), image, imageProperties.get());
     CGImageDestinationFinalize(destination.get());
 
@@ -355,9 +358,32 @@
 String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
 {
     ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+    RetainPtr<CGImageRef> image;
+    RetainPtr<CFStringRef> uti = utiFromMIMEType(mimeType);
+    ASSERT(uti);
 
-    RetainPtr<CGImageRef> image(AdoptCF, copyNativeImage(CopyBackingStore));
+    if (CFEqual(uti.get(), jpegUTI())) {
+        // JPEGs don't have an alpha channel, so we have to manually composite on top of black.
+        RefPtr<ByteArray> arr = getPremultipliedImageData(IntRect(IntPoint(0, 0), m_size));
 
+        unsigned char *data = ""
+        for (int i = 0; i < width() * height(); i++)
+            data[i * 4 + 3] = 255; // The image is already premultiplied, so we just need to make it opaque.
+
+        RetainPtr<CGDataProviderRef> dataProvider;
+    
+        dataProvider.adoptCF(CGDataProviderCreateWithData(0, data,
+                                                          4 * width() * height(), 0));
+    
+        if (!dataProvider)
+            return "data:,";
+
+        image.adoptCF(CGImageCreate(width(), height(), 8, 32, 4 * width(),
+                                    CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault | kCGImageAlphaLast,
+                                    dataProvider.get(), 0, false, kCGRenderingIntentDefault));
+    } else
+        image.adoptCF(copyNativeImage(CopyBackingStore));
+
     if (!image)
         return "data:,";
 
@@ -370,8 +396,35 @@
         
     RetainPtr<CGImageRef> image;
     RetainPtr<CGDataProviderRef> dataProvider;
+
+    unsigned char* data = ""
+    RetainPtr<CFStringRef> uti = utiFromMIMEType(mimeType);
+    ASSERT(uti);
+    Vector<uint8_t> dataVector;
+    if (CFEqual(uti.get(), jpegUTI())) {
+        // JPEGs don't have an alpha channel, so we have to manually composite on top of black.
+        dataVector.resize(4 * source.width() * source.height());
+        unsigned char *out = dataVector.data();
+        
+        for (int i = 0; i < source.width() * source.height(); i++) {
+            // Multiply color data by alpha, and set alpha to 255.
+            int alpha = data[4 * i + 3];
+            if (alpha != 255) {
+                out[4 * i + 0] = data[4 * i + 0] * alpha / 255;
+                out[4 * i + 1] = data[4 * i + 1] * alpha / 255;
+                out[4 * i + 2] = data[4 * i + 2] * alpha / 255;
+            } else {
+                out[4 * i + 0] = data[4 * i + 0];
+                out[4 * i + 1] = data[4 * i + 1];
+                out[4 * i + 2] = data[4 * i + 2];
+            }
+            out[4 * i + 3] = 255;
+        }
+
+        data = ""
+    }
     
-    dataProvider.adoptCF(CGDataProviderCreateWithData(0, source.data()->data()->data(),
+    dataProvider.adoptCF(CGDataProviderCreateWithData(0, data,
                                                       4 * source.width() * source.height(), 0));
     
     if (!dataProvider)

Modified: trunk/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp (95999 => 96000)


--- trunk/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp	2011-09-26 22:00:06 UTC (rev 95999)
+++ trunk/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp	2011-09-26 22:07:33 UTC (rev 96000)
@@ -92,9 +92,17 @@
 static void RGBAtoRGB(const unsigned char* pixels, unsigned int pixelCount, unsigned char* output)
 {
     for (; pixelCount-- > 0; pixels += 4) {
-        *output++ = pixels[0];
-        *output++ = pixels[1];
-        *output++ = pixels[2];
+        // Do source-over composition on black.
+        unsigned char alpha = pixels[3];
+        if (alpha != 255) {
+            *output++ = SkMulDiv255Round(pixels[0], alpha);
+            *output++ = SkMulDiv255Round(pixels[1], alpha);
+            *output++ = SkMulDiv255Round(pixels[2], alpha);
+        } else {
+            *output++ = pixels[0];
+            *output++ = pixels[1];
+            *output++ = pixels[2];
+        }
     }
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to