Bug 83973 - [GTK] Should pass canvas/philip/tests/toDataURL.jpeg.alpha.html
Summary: [GTK] Should pass canvas/philip/tests/toDataURL.jpeg.alpha.html
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Canvas (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: noel gordon
URL: http://w3c-test.org/html/tests/approv...
Keywords:
Depends on: 40147
Blocks:
  Show dependency treegraph
 
Reported: 2012-04-14 00:55 PDT by noel gordon
Modified: 2012-04-24 15:34 PDT (History)
3 users (show)

See Also:


Attachments
Patch (7.55 KB, patch)
2012-04-16 08:35 PDT, noel gordon
no flags Details | Formatted Diff | Diff
Patch (7.51 KB, patch)
2012-04-17 02:13 PDT, noel gordon
no flags Details | Formatted Diff | Diff
Patch (3.81 KB, patch)
2012-04-23 02:27 PDT, Carlos Garcia Campos
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description noel gordon 2012-04-14 00:55:24 PDT
To pass this test, pass premultiplied color to the JPEG encoder. Modify the cairoImageSurfaceToGdkPixbuf() function added in

  https://bugs.webkit.org/attachment.cgi?id=62763&action=prettypatch

to have an default second argument (default false) that requests premultiplied color output when creating the GdkPixbuf.
Comment 1 noel gordon 2012-04-14 01:25:56 PDT
... or else create a specific function, cairoImageSurfaceToGdkPixbufPremultiplied() say, for the purpose.  Martin, let me know which you'd prefer and I'll prepare a patch.
Comment 2 noel gordon 2012-04-16 08:32:03 PDT
Given bug 49532, seems cairoImageSurfaceToGdkPixbufPremultiplied() is the way to go.
Comment 3 noel gordon 2012-04-16 08:35:44 PDT
Created attachment 137350 [details]
Patch
Comment 4 noel gordon 2012-04-17 02:12:43 PDT
Update.
Comment 5 noel gordon 2012-04-17 02:13:43 PDT
Created attachment 137494 [details]
Patch
Comment 6 noel gordon 2012-04-17 02:17:54 PDT
I have no means to run GTK tests in my setup.  So maybe we submit and check the webkit GTK bots, or you could patch it locally and see if the toDataURL.jpeg.alpha test passes.
Comment 8 Carlos Garcia Campos 2012-04-17 03:05:11 PDT
I guess this should be handled by GdkPixbuf jpeg encoder, no? gdk_pixbuf_get_from_surface() returns a valid GdkPixbuf (using an alpha channel or not depending on the cairo surface image format). So gdk_pixbuf_save should work with that pixbuf.
Comment 9 noel gordon 2012-04-18 18:28:59 PDT
(In reply to comment #8)
> I guess this should be handled by GdkPixbuf jpeg encoder, no? 

Nope.  JPEG encoders ignore alpha channel and encode the RGB channels only.  The encoder used by GTK looks right to me; see real_save_jpeg() here:

  http://gdk-pixbuf.sourcearchive.com/documentation/2.22.0-1/io-jpeg_8c-source.html

I believe the JPEG encoder should remain dumb and encode whatever RGB it's given.  That RGB can be in one of two states: premultiplied or not.
Comment 10 noel gordon 2012-04-18 18:34:47 PDT
(In reply to comment #8)
> gdk_pixbuf_get_from_surface() returns a valid GdkPixbuf (using an alpha channel or not depending on the cairo surface image format). So gdk_pixbuf_save should work with that pixbuf.

The cairo surface of an ImageBuffer is CAIRO_FORMAT_ARGB32 premultiplied.  gdk_pixbuf_get_from_surface() converts the cairo surface pixels to un-premultiplied color.  Thus, gdk_pixbuf_save() would send un-premultiplied color to the JPEG encoder if gdk_pixbuf_get_from_surface() was used to create the GdkPixbuf.

The <canvas> spec states that toDataURL() must encode a Porter-Duff composite source-over black for image types that do not support alpha, JPEG for example.  The toDataURL.jpeg.alpha.html checks for that. The test has been vetted for accuracy (bug 40147) and approved by the W3C

   http://w3c-test.org/html/tests/approved/canvas/toDataURL.jpeg.alpha.html

The pass this test, you must send premultiplied color to the JPEG encoder.  The reasons are documented in ChangeLog https://bugs.webkit.org/attachment.cgi?id=76964&action=prettypatch
Comment 11 Carlos Garcia Campos 2012-04-19 00:08:34 PDT
(In reply to comment #10)
> (In reply to comment #8)
> > gdk_pixbuf_get_from_surface() returns a valid GdkPixbuf (using an alpha channel or not depending on the cairo surface image format). So gdk_pixbuf_save should work with that pixbuf.
> 
> The cairo surface of an ImageBuffer is CAIRO_FORMAT_ARGB32 premultiplied.  gdk_pixbuf_get_from_surface() converts the cairo surface pixels to un-premultiplied color.  Thus, gdk_pixbuf_save() would send un-premultiplied color to the JPEG encoder if gdk_pixbuf_get_from_surface() was used to create the GdkPixbuf.
> 
> The <canvas> spec states that toDataURL() must encode a Porter-Duff composite source-over black for image types that do not support alpha, JPEG for example.  The toDataURL.jpeg.alpha.html checks for that. The test has been vetted for accuracy (bug 40147) and approved by the W3C
> 
>    http://w3c-test.org/html/tests/approved/canvas/toDataURL.jpeg.alpha.html
> 
> The pass this test, you must send premultiplied color to the JPEG encoder.  The reasons are documented in ChangeLog https://bugs.webkit.org/attachment.cgi?id=76964&action=prettypatch

In that case I think we should do exactly that, something like this should work:


    GRefPtr<GdkPixbuf> pixbuf;
    if (type == "jpeg" && cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32) {
        // JPEG doesn't support alpha channel. The <canvas> spec states that toDataURL() must encode a Porter-Duff                                                                           
        // composite source-over black for image types that do not support alpha.                                                                                                            
        RefPtr<cairo_surface_t> newSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_RGB24,
                                                                                 cairo_image_surface_get_width(surface),
                                                                                 cairo_image_surface_get_height(surface)));
        RefPtr<cairo_t> cr = adoptRef(cairo_create(newSurface.get()));
        cairo_set_source_surface(cr.get(), surface, 0, 0);
        cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE);
        cairo_paint(cr.get());
        pixbuf = adoptGRef(cairoImageSurfaceToGdkPixbuf(newSurface.get()));
    } else
        pixbuf = adoptGRef(cairoImageSurfaceToGdkPixbuf(surface));
    if (!pixbuf)
        return false;
Comment 12 noel gordon 2012-04-19 00:28:21 PDT
>     RefPtr<cairo_t> cr = adoptRef(cairo_create(newSurface.get()));
>     cairo_set_source_surface(cr.get(), surface, 0, 0);
>     cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE);
>     cairo_paint(cr.get());
>      pixbuf = adoptGRef(cairoImageSurfaceToGdkPixbuf(newSurface.get()));

Does cairoImageSurfaceToGdkPixbuf produce un-premultiplied colors here?
Comment 13 Carlos Garcia Campos 2012-04-19 00:47:50 PDT
(In reply to comment #12)
> >     RefPtr<cairo_t> cr = adoptRef(cairo_create(newSurface.get()));
> >     cairo_set_source_surface(cr.get(), surface, 0, 0);
> >     cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE);
> >     cairo_paint(cr.get());
> >      pixbuf = adoptGRef(cairoImageSurfaceToGdkPixbuf(newSurface.get()));
> 
> Does cairoImageSurfaceToGdkPixbuf produce un-premultiplied colors here?

It doesn't un-premultiply because there's no alpha in the source image.
Comment 14 noel gordon 2012-04-19 00:57:49 PDT
Ok and when cairo paints a CAIRO_FORMAT_ARGB32 source into a CAIRO_FORMAT_RGB24 surface,  the alpha channel is just ignored?
Comment 15 noel gordon 2012-04-20 22:27:09 PDT
Because maybe it's not ignored given that the another plausible answer to my question is that since CAIRO_FORMAT_ARGB32 is premultipled data, it gets un-premultipled on write to a CAIRO_FORMAT_RGB24 target.

I done a bunch of web searching trying to work out the correct answer, but so far I've found no canonical reference to the fact, nor in  the cairo docs, or by reading through the cairo code trying to understand what it does.  I guess I'm stuck here.  What's a reasonable way for us to proceed here?
Comment 16 Carlos Garcia Campos 2012-04-21 01:27:01 PDT
Data is not un-premultiplied, you can test the code I pasted and check that test toDataURL.jpeg.alpha.html passes.
Comment 17 noel gordon 2012-04-21 01:52:53 PDT
Was comment #6 unclear?
Comment 18 Carlos Garcia Campos 2012-04-21 02:05:16 PDT
(In reply to comment #17)
> Was comment #6 unclear?

You an test it with GtkLauncher and loading http://w3c-test.org/html/tests/approved/canvas/toDataURL.jpeg.alpha.html you don't need to run the tests
Comment 19 noel gordon 2012-04-21 02:05:42 PDT
Was is the GtkLauncher ?
Comment 20 noel gordon 2012-04-21 02:07:06 PDT
And whatever is is, I doubt I can build on on windows box.
Comment 21 noel gordon 2012-04-21 02:12:35 PDT
Sorry, whatever GtkLauncher is, I doubt I can build it on a windows box.
Comment 22 Carlos Garcia Campos 2012-04-21 02:20:13 PDT
(In reply to comment #21)
> Sorry, whatever GtkLauncher is, I doubt I can build it on a windows box.

Ok, I thought you could build webkit but not run the tests. GtkLauncher is a small web browser for testing that is built with the GTK+ port. I can simply submit a patch with the code I pasted if you want.
Comment 23 noel gordon 2012-04-21 02:27:24 PDT
(In reply to comment #22)
> (In reply to comment #21)
> > Sorry, whatever GtkLauncher is, I doubt I can build it on a windows box.
> 
> Ok, I thought you could build webkit but not run the tests. GtkLauncher is a small web browser for testing that is built with the GTK+ port.

Appreciate the explanation.  And no I can't build webkit gtk and run tests with my current setup (win32). 

> I can simply submit a patch with the code I pasted if you want.

Yes please, that sounds good to me, if you like to do it.
Comment 24 noel gordon 2012-04-22 21:03:05 PDT
One more thought was that Martin's original code, now modified, is much like a single memcpy.  The code in comment #11 seems to cost two memcpy operations (one for the paint and one for cairoImageSurfaceToGdkPixbuf step).  Should I worry about performance?
Comment 25 Martin Robinson 2012-04-22 21:22:36 PDT
(In reply to comment #24)
> One more thought was that Martin's original code, now modified, is much like a single memcpy.  The code in comment #11 seems to cost two memcpy operations (one for the paint and one for cairoImageSurfaceToGdkPixbuf step).  Should I worry about performance?

Indeed it might be nice to do this in a single pass instead of two. How can you be sure your original patch fixes the test without testing it though? If necessary, I can do that locally.
Comment 26 noel gordon 2012-04-22 23:52:27 PDT
Indeed.  Testing that the test works means we either 1) submit and watch the GTK+ build bot, or

> If necessary, I can do that locally.

do as you suggest.  If you have time, that'd sure help.
Comment 27 Carlos Garcia Campos 2012-04-23 02:27:52 PDT
Created attachment 138311 [details]
Patch
Comment 28 Carlos Garcia Campos 2012-04-23 02:28:48 PDT
(In reply to comment #24)
> One more thought was that Martin's original code, now modified, is much like a single memcpy.  The code in comment #11 seems to cost two memcpy operations (one for the paint and one for cairoImageSurfaceToGdkPixbuf step).  Should I worry about performance?

We can actually use the same data to avoid the memory allocation since cairo use the same 32 bits also for RGB24.
Comment 29 noel gordon 2012-04-23 19:37:51 PDT
Comment on attachment 138311 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=138311&action=review

> Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp:45
> +        // JPEG doesn't support alpha channel. The <canvas> spec states that toDataURL() must encode a Porter-Duff

Patch looks fine to me.

nit: CAIRO_FORMAT_ARGB32 is a given, right?  We could just assert if we're concerned about it.

if (type == "jpeg") {
  ASSERT(cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32);
     ...
Comment 30 Philippe Normand 2012-04-24 06:59:20 PDT
Comment on attachment 138311 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=138311&action=review

r=me but please consider this question before landing:

>> Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp:45
>> +        // JPEG doesn't support alpha channel. The <canvas> spec states that toDataURL() must encode a Porter-Duff
> 
> Patch looks fine to me.
> 
> nit: CAIRO_FORMAT_ARGB32 is a given, right?  We could just assert if we're concerned about it.
> 
> if (type == "jpeg") {
>   ASSERT(cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32);
>      ...

Yes I think it'd be ok to proceed as Noel advises. Carlos?
Comment 31 Carlos Garcia Campos 2012-04-24 08:08:19 PDT
(In reply to comment #30)
> (From update of attachment 138311 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=138311&action=review
> 
> r=me but please consider this question before landing:
> 
> >> Source/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp:45
> >> +        // JPEG doesn't support alpha channel. The <canvas> spec states that toDataURL() must encode a Porter-Duff
> > 
> > Patch looks fine to me.
> > 
> > nit: CAIRO_FORMAT_ARGB32 is a given, right?  We could just assert if we're concerned about it.
> > 
> > if (type == "jpeg") {
> >   ASSERT(cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32);
> >      ...
> 
> Yes I think it'd be ok to proceed as Noel advises. Carlos?

es, or even remove the check since surface is created unconditionally as ARGB32 in ImageBuffer constructor
Comment 32 Carlos Garcia Campos 2012-04-24 08:25:34 PDT
Committed r115058: <http://trac.webkit.org/changeset/115058>
Comment 33 noel gordon 2012-04-24 13:56:42 PDT
(In reply to comment #31)
> or even remove the check since surface is created unconditionally as ARGB32 in ImageBuffer constructor

Exactly. Thanks for helping everybody, test passes.