Changeset 47689 in webkit


Ignore:
Timestamp:
Aug 23, 2009 12:18:17 AM (15 years ago)
Author:
xan@webkit.org
Message:

2009-08-22 Martin Robinson <martin.james.robinson@gmail.com>

Reviewed by Xan Lopez.

[GTK] BitmapImage::getGdkPixbuf does not handle alpha channels properly
https://bugs.webkit.org/show_bug.cgi?id=28345

When doing the conversion between cairo_surface_t* and GdkPixbuf*
account for the differences in the respective formats' in-memory
image format.

  • platform/graphics/gtk/ImageGtk.cpp: (WebCore::getCairoSurfacePixel): (WebCore::getGdkPixbufPixel): (WebCore::BitmapImage::getGdkPixbuf):
Location:
trunk/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r47688 r47689  
     12009-08-22  Martin Robinson  <martin.james.robinson@gmail.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [GTK] BitmapImage::getGdkPixbuf does not handle alpha channels properly
     6        https://bugs.webkit.org/show_bug.cgi?id=28345
     7
     8        When doing the conversion between cairo_surface_t* and GdkPixbuf*
     9        account for the differences in the respective formats' in-memory
     10        image format.
     11
     12        * platform/graphics/gtk/ImageGtk.cpp:
     13        (WebCore::getCairoSurfacePixel):
     14        (WebCore::getGdkPixbufPixel):
     15        (WebCore::BitmapImage::getGdkPixbuf):
     16
    1172009-08-22  Darin Adler  <darin@apple.com>
    218
  • trunk/WebCore/platform/graphics/gtk/ImageGtk.cpp

    r43955 r47689  
    8989}
    9090
     91static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride)
     92{
     93    return data + (y * rowStride) + x * 4;
     94}
     95
     96static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride)
     97{
     98    return data + (y * rowStride) + x * 4;
     99}
     100
    91101GdkPixbuf* BitmapImage::getGdkPixbuf()
    92102{
    93103    int width = cairo_image_surface_get_width(frameAtIndex(currentFrame()));
    94104    int height = cairo_image_surface_get_height(frameAtIndex(currentFrame()));
     105    unsigned char* surfaceData = cairo_image_surface_get_data(frameAtIndex(currentFrame()));
     106    int surfaceRowStride = cairo_image_surface_get_stride(frameAtIndex(currentFrame()));
    95107
    96     int bestDepth = gdk_visual_get_best_depth();
    97     GdkColormap* cmap = gdk_colormap_new(gdk_visual_get_best_with_depth(bestDepth), true);
     108    GdkPixbuf* dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
     109    if (!dest)
     110        return 0;
    98111
    99     GdkPixmap* pixmap = gdk_pixmap_new(0, width, height, bestDepth);
    100     gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), cmap);
    101     cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(pixmap));
    102     cairo_set_source_surface(cr, frameAtIndex(currentFrame()), 0, 0);
    103     cairo_paint(cr);
    104     cairo_destroy(cr);
     112    guchar* pixbufData = gdk_pixbuf_get_pixels(dest);
     113    int pixbufRowStride = gdk_pixbuf_get_rowstride(dest);
    105114
    106     GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(0, GDK_DRAWABLE(pixmap), 0, 0, 0, 0, 0, width, height);
    107     g_object_unref(pixmap);
    108     g_object_unref(cmap);
     115    /* From: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t
     116     * "CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with alpha in
     117     * the upper 8 bits, then red, then green, then blue. The 32-bit
     118     * quantities are stored native-endian. Pre-multiplied alpha is used.
     119     * (That is, 50% transparent red is 0x80800000, not 0x80ff0000.)"
     120     *
     121     * See http://developer.gimp.org/api/2.0/gdk-pixbuf/gdk-pixbuf-gdk-pixbuf.html#GdkPixbuf
     122     * for information on the structure of GdkPixbufs stored with GDK_COLORSPACE_RGB.
     123     *
     124     * RGB color channels in CAIRO_FORMAT_ARGB32 are stored based on the
     125     * endianness of the machine and are also multiplied by the alpha channel.
     126     * To properly transfer the data from the Cairo surface we must divide each
     127     * of the RGB channels by the alpha channel and then reorder all channels
     128     * if this machine is little-endian.
     129     */
     130    for (int y = 0; y < height; y++) {
     131        for (int x = 0; x < height; x++) {
     132            unsigned char* source = getCairoSurfacePixel(surfaceData, x, y, surfaceRowStride);
     133            guchar* dest = getGdkPixbufPixel(pixbufData, x, y, pixbufRowStride);
    109134
    110     return pixbuf;
     135#if G_BYTE_ORDER == G_LITTLE_ENDIAN
     136            guchar alpha = source[3];
     137            dest[0] = alpha ? ((source[2] * 255) / alpha) : 0;
     138            dest[1] = alpha ? ((source[1] * 255) / alpha) : 0;
     139            dest[2] = alpha ? ((source[0] * 255) / alpha) : 0;
     140            dest[3] = alpha;
     141#else
     142            guchar alpha = source[0];
     143            dest[0] = alpha ? ((source[1] * 255) / alpha) : 0;
     144            dest[1] = alpha ? ((source[2] * 255) / alpha) : 0;
     145            dest[2] = alpha ? ((source[3] * 255) / alpha) : 0;
     146            dest[3] = alpha;
     147#endif
     148        }
     149    }
     150
     151    return dest;
    111152}
    112153
Note: See TracChangeset for help on using the changeset viewer.