Changeset 96000 in webkit


Ignore:
Timestamp:
Sep 26, 2011 3:07:33 PM (13 years ago)
Author:
commit-queue@webkit.org
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 <jbauman@chromium.org> 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 <jbauman@chromium.org> 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:
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r95990 r96000  
     12011-09-26  John Bauman  <jbauman@chromium.org>
     2
     3        Fix nonpremultiplied webgl toDataURL to jpeg
     4        https://bugs.webkit.org/show_bug.cgi?id=68366
     5
     6        Update the premultiplyalpha-test from the WebGL conformance tests.
     7        Also use the correct expected result for toDataURL.jpeg.alpha.html.
     8
     9        Reviewed by Kenneth Russell.
     10
     11        * fast/canvas/webgl/premultiplyalpha-test-expected.txt:
     12        * fast/canvas/webgl/premultiplyalpha-test.html:
     13        * platform/mac/canvas/philip/tests/toDataURL.jpeg.alpha-expected.txt:
     14
    1152011-09-26  Ryosuke Niwa  <rniwa@webkit.org>
    216
  • trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test-expected.txt

    r95494 r96000  
    44
    55
    6 testing: premultipliedAlpha: true toDataURL: true
     6testing: premultipliedAlpha: true imageFormat: image/png
    77PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
     8PASS gl.getContextAttributes().preserveDrawingBuffer is true
    89PASS getError was expected value: NO_ERROR : Should be no errors from setup.
    910PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
     
    1213PASS should draw with 64,128,255,128
    1314
    14 testing: premultipliedAlpha: true toDataURL: false
     15testing: premultipliedAlpha: true imageFormat: undefined
    1516PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
     17PASS gl.getContextAttributes().preserveDrawingBuffer is true
    1618PASS getError was expected value: NO_ERROR : Should be no errors from setup.
    1719PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
     
    2022PASS should draw with 64,128,255,128
    2123
    22 testing: premultipliedAlpha: false toDataURL: true
     24testing: premultipliedAlpha: false imageFormat: image/png
    2325PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
     26PASS gl.getContextAttributes().preserveDrawingBuffer is true
    2427PASS getError was expected value: NO_ERROR : Should be no errors from setup.
    2528PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
     
    2831PASS should draw with 255,192,128,1
    2932
    30 testing: premultipliedAlpha: false toDataURL: false
     33testing: premultipliedAlpha: false imageFormat: undefined
    3134PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
     35PASS gl.getContextAttributes().preserveDrawingBuffer is true
    3236PASS getError was expected value: NO_ERROR : Should be no errors from setup.
    3337PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
     
    3640PASS should draw with 255,192,128,1
    3741
     42testing: premultipliedAlpha: false imageFormat: image/jpeg
     43PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
     44PASS gl.getContextAttributes().preserveDrawingBuffer is true
     45PASS getError was expected value: NO_ERROR : Should be no errors from setup.
     46PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
     47PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
     48PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
     49PASS should draw with 128,128,128,255
     50
     51testing: premultipliedAlpha: true imageFormat: image/jpeg
     52PASS gl.getContextAttributes().premultipledAlpha is premultipledAlpha
     53PASS gl.getContextAttributes().preserveDrawingBuffer is true
     54PASS getError was expected value: NO_ERROR : Should be no errors from setup.
     55PASS getError was expected value: NO_ERROR : Should be no errors from drawing.
     56PASS getError was expected value: NO_ERROR : Should be no errors from creating copy.
     57PASS getError was expected value: NO_ERROR : Should be no errors from 2nd drawing.
     58PASS should draw with 128,128,128,255
     59
  • trunk/LayoutTests/fast/canvas/webgl/premultiplyalpha-test.html

    r95494 r96000  
    1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    2   "http://www.w3.org/TR/html4/loose.dtd">
     1<!DOCTYPE html>
    32<html>
    43<head>
     4<meta charset="utf-8">
    55<title>Test the WebGL premultipledAlpha context creation flag.</title>
    66<link rel="stylesheet" href="../../js/resources/js-test-style.css"/>
     
    2222    expectedColor: [64, 128, 255, 128],
    2323    errorRange: 2,
    24     useToDataURL: true,
     24    imageFormat: "image/png"
    2525  },
    2626  // If premultipledAlpha is true then
     
    3131    expectedColor: [64, 128, 255, 128],
    3232    errorRange: 2,
    33     useToDataURL: false,
    3433  },
    3534  // If premultipledAlpha is false then
     
    4039    expectedColor: [255, 192, 128, 1],
    4140    errorRange: 0,
    42     useToDataURL: true,
     41    imageFormat: "image/png"
    4342  },
    4443  // If premultipledAlpha is false then
     
    4948    expectedColor: [255, 192, 128, 1],
    5049    errorRange: 0,
    51     useToDataURL: false,
     50  },
     51  // If premultipledAlpha is false then
     52  // [texture]             [canvas]            [dataURL]
     53  // 255, 255, 255, 128 -> 255, 255, 255, 128 -> 128, 128, 128, 255
     54  { creationAttributes: {premultipliedAlpha: false},
     55    sentColor: [255, 255, 255, 128],
     56    expectedColor: [128, 128, 128, 255],
     57    errorRange: 2,
     58    imageFormat: "image/jpeg"
     59  },
     60  // If premultipledAlpha is true then
     61  // [texture]             [canvas]            [dataURL]
     62  // 128, 128, 128, 128 -> 255, 255, 255, 128 -> 128, 128, 128, 255
     63  { creationAttributes: {},
     64    sentColor: [128, 128, 128, 128],
     65    expectedColor: [128, 128, 128, 255],
     66    errorRange: 2,
     67    imageFormat: "image/jpeg"
    5268  }
    5369];
     
    6985     var test = tests[g_count++];
    7086     canvas = document.createElement("canvas");
     87     // Need to preserve drawing buffer to load it in a callback
     88     test.creationAttributes.preserveDrawingBuffer = true;
    7189     gl = wtu.create3DContext(canvas, test.creationAttributes);
    7290     var premultipliedAlpha = test.creationAttributes.premultipliedAlpha != false;
    7391     debug("")
    74      debug("testing: premultipliedAlpha: " + premultipliedAlpha + " toDataURL: " + test.useToDataURL);
     92     debug("testing: premultipliedAlpha: " + premultipliedAlpha + " imageFormat: " + test.imageFormat);
    7593
    7694     shouldBe('gl.getContextAttributes().premultipledAlpha', 'premultipledAlpha');
     95     shouldBeTrue('gl.getContextAttributes().preserveDrawingBuffer');
    7796
    7897     var program = wtu.setupTexturedQuad(gl);
     
    97116       gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false);
    98117       gl.bindTexture(gl.TEXTURE_2D, pngTex);
    99        if (test.useToDataURL) {
     118       if (test.imageFormat) {
    100119          // create texture from image
    101120          gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this);
     
    118137     }
    119138
    120      if (test.useToDataURL) {
     139     if (test.imageFormat) {
    121140        // Load canvas into string using toDataURL
    122         var png = canvas.toDataURL();
    123         // Load string into the texture
    124         var input = document.createElement("img");
    125         input.onload = loadTexture;
    126         input.src = png;
     141        var imageUrl = canvas.toDataURL(test.imageFormat);
     142        if (test.imageFormat != "image/png" &&
     143            (imageUrl.indexOf("data:image/png,") == 0 ||
     144             imageUrl.indexOf("data:image/png;") == 0)) {
     145          debug("Image format " + test.imageFormat + " not supported; skipping");
     146          setTimeout(doNextTest, 0);
     147        } else {
     148          // Load string into the texture
     149          var input = document.createElement("img");
     150          input.onload = loadTexture;
     151          input.src = imageUrl;
     152        }
    127153     } else {
    128154        // Load canvas into the texture asynchronously (to prevent unbounded stack consumption)
     
    139165</script>
    140166
    141 <script>
    142 </script>
    143 
    144167</body>
    145168</html>
  • trunk/LayoutTests/platform/mac/canvas/philip/tests/toDataURL.jpeg.alpha-expected.txt

    r84509 r96000  
    1 Failed assertion: got pixel [193,255,192,255] at (50,25), expected [63,127,63,255] +/- 8
     1Passed
  • trunk/Source/WebCore/ChangeLog

    r95998 r96000  
     12011-09-26  John Bauman  <jbauman@chromium.org>
     2
     3        Fix nonpremultiplied webgl toDataURL to jpeg
     4        https://bugs.webkit.org/show_bug.cgi?id=68366
     5
     6        The canvas spec says that toDataURL to formats without an alpha must
     7        be "composited onto a solid black background using the source-over
     8        operator." Do that.
     9
     10        Reviewed by Kenneth Russell.
     11
     12        * platform/graphics/cg/ImageBufferCG.cpp:
     13        (WebCore::CGImageToDataURL):
     14        (WebCore::ImageBuffer::toDataURL):
     15        (WebCore::ImageDataToDataURL):
     16        * platform/image-encoders/skia/JPEGImageEncoder.cpp:
     17        (WebCore::RGBAtoRGB):
     18
    1192011-09-26  Raphael Kubo da Costa  <kubo@profusion.mobi>
    220
  • trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp

    r95174 r96000  
    344344    }
    345345
     346    // Setting kCGImageDestinationBackgroundColor to black in imageProperties would allow saving some math in the
     347    // calling functions, but it doesn't seem to work.
     348
    346349    CGImageDestinationAddImage(destination.get(), image, imageProperties.get());
    347350    CGImageDestinationFinalize(destination.get());
     
    356359{
    357360    ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
    358 
    359     RetainPtr<CGImageRef> image(AdoptCF, copyNativeImage(CopyBackingStore));
     361    RetainPtr<CGImageRef> image;
     362    RetainPtr<CFStringRef> uti = utiFromMIMEType(mimeType);
     363    ASSERT(uti);
     364
     365    if (CFEqual(uti.get(), jpegUTI())) {
     366        // JPEGs don't have an alpha channel, so we have to manually composite on top of black.
     367        RefPtr<ByteArray> arr = getPremultipliedImageData(IntRect(IntPoint(0, 0), m_size));
     368
     369        unsigned char *data = arr->data();
     370        for (int i = 0; i < width() * height(); i++)
     371            data[i * 4 + 3] = 255; // The image is already premultiplied, so we just need to make it opaque.
     372
     373        RetainPtr<CGDataProviderRef> dataProvider;
     374   
     375        dataProvider.adoptCF(CGDataProviderCreateWithData(0, data,
     376                                                          4 * width() * height(), 0));
     377   
     378        if (!dataProvider)
     379            return "data:,";
     380
     381        image.adoptCF(CGImageCreate(width(), height(), 8, 32, 4 * width(),
     382                                    CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault | kCGImageAlphaLast,
     383                                    dataProvider.get(), 0, false, kCGRenderingIntentDefault));
     384    } else
     385        image.adoptCF(copyNativeImage(CopyBackingStore));
    360386
    361387    if (!image)
     
    371397    RetainPtr<CGImageRef> image;
    372398    RetainPtr<CGDataProviderRef> dataProvider;
     399
     400    unsigned char* data = source.data()->data()->data();
     401    RetainPtr<CFStringRef> uti = utiFromMIMEType(mimeType);
     402    ASSERT(uti);
     403    Vector<uint8_t> dataVector;
     404    if (CFEqual(uti.get(), jpegUTI())) {
     405        // JPEGs don't have an alpha channel, so we have to manually composite on top of black.
     406        dataVector.resize(4 * source.width() * source.height());
     407        unsigned char *out = dataVector.data();
     408       
     409        for (int i = 0; i < source.width() * source.height(); i++) {
     410            // Multiply color data by alpha, and set alpha to 255.
     411            int alpha = data[4 * i + 3];
     412            if (alpha != 255) {
     413                out[4 * i + 0] = data[4 * i + 0] * alpha / 255;
     414                out[4 * i + 1] = data[4 * i + 1] * alpha / 255;
     415                out[4 * i + 2] = data[4 * i + 2] * alpha / 255;
     416            } else {
     417                out[4 * i + 0] = data[4 * i + 0];
     418                out[4 * i + 1] = data[4 * i + 1];
     419                out[4 * i + 2] = data[4 * i + 2];
     420            }
     421            out[4 * i + 3] = 255;
     422        }
     423
     424        data = out;
     425    }
    373426   
    374     dataProvider.adoptCF(CGDataProviderCreateWithData(0, source.data()->data()->data(),
     427    dataProvider.adoptCF(CGDataProviderCreateWithData(0, data,
    375428                                                      4 * source.width() * source.height(), 0));
    376429   
  • trunk/Source/WebCore/platform/image-encoders/skia/JPEGImageEncoder.cpp

    r95901 r96000  
    9393{
    9494    for (; pixelCount-- > 0; pixels += 4) {
    95         *output++ = pixels[0];
    96         *output++ = pixels[1];
    97         *output++ = pixels[2];
     95        // Do source-over composition on black.
     96        unsigned char alpha = pixels[3];
     97        if (alpha != 255) {
     98            *output++ = SkMulDiv255Round(pixels[0], alpha);
     99            *output++ = SkMulDiv255Round(pixels[1], alpha);
     100            *output++ = SkMulDiv255Round(pixels[2], alpha);
     101        } else {
     102            *output++ = pixels[0];
     103            *output++ = pixels[1];
     104            *output++ = pixels[2];
     105        }
    98106    }
    99107}
Note: See TracChangeset for help on using the changeset viewer.