diff src/img_ldr_imlib2.c @ 1106:b5145de15ace

Fix issue of alpha channel not working. Cairo is referene design of our graphic engine. It always trade an image as pre-multiplied, but imlib2 is not. It causes no opacity effects for the images loaded with imlib2. It is fixed by pre-multipling images loaded by imlib2.
author Thinker K.F. Li <thinker@codemud.net>
date Mon, 06 Dec 2010 01:05:32 +0800
parents 7b4e80ab671a
children 1c64a9cec2f2
line wrap: on
line diff
--- a/src/img_ldr_imlib2.c	Sun Dec 05 21:04:12 2010 +0800
+++ b/src/img_ldr_imlib2.c	Mon Dec 06 01:05:32 2010 +0800
@@ -1,6 +1,7 @@
 // -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*-
 // vim: sw=4:ts=8:sts=4
 #include <stdio.h>
+#include <stdint.h>
 #include <string.h>
 #include <Imlib2.h>
 #include "mb_graph_engine.h"
@@ -19,7 +20,6 @@
 
 struct _simple_mb_img_data {
     mb_img_data_t img;
-    Imlib_Image img_hdl;
 };
 typedef struct _simple_mb_img_data simple_mb_img_data_t;
 
@@ -31,7 +31,11 @@
     simple_mb_img_data_t *img;
     Imlib_Image img_hdl;
     int w, h;
-    void *data;
+    int i, j, pos;
+    uint32_t alpha;
+    uint32_t value;
+    uint32_t *data;
+    uint32_t *premultiple_data;
     char *fname;
     int sz;
 
@@ -50,21 +54,54 @@
     imlib_context_set_image(img_hdl);
     w = imlib_image_get_width();
     h = imlib_image_get_height();
-    data = imlib_image_get_data_for_reading_only();
+    data = (uint32_t *)imlib_image_get_data_for_reading_only();
 
     img = O_ALLOC(simple_mb_img_data_t);
     if(img == NULL) {
 	imlib_free_image();
 	return NULL;
     }
-    img->img.content = data;
+    
+    premultiple_data = (uint32_t *)malloc(4 * w * h);
+    if(premultiple_data == NULL) {
+	free(img);
+	imlib_free_image();
+	return NULL;
+    }
+    memcpy(premultiple_data, data, 4 * w * h);
+
+    /* Pre-multiply
+     *
+     * Our reference model is Cairo.  In Cairo model, image is
+     * pre-multiplied with alpha, but imlib2 is not.  So, we do it
+     * here.
+     */
+    pos = 0;
+    for(i = 0; i < h; i++) {
+	for(j = 0; j < w; j++) {
+	    value = data[pos];
+	    alpha = value >> 24;
+	    if(alpha == 0)
+		value = 0;
+	    else if(alpha != 0xff) {
+		value = (value & 0xff000000) |
+		    (((value & 0xff0000) * alpha / 0xff) & 0xff0000) |
+		    (((value & 0xff00) * alpha / 0xff) & 0xff00) |
+		    ((value & 0xff) * alpha / 0xff);
+	    }
+	    premultiple_data[pos++] = value;
+	}
+    }
+    
+    img->img.content = premultiple_data;
     img->img.w = w;
     img->img.h = h;
     img->img.stride = w * 4;
     img->img.fmt = MB_IFMT_ARGB32;
     img->img.free = simple_mb_img_ldr_img_free;
-    img->img_hdl = img_hdl;
 
+    imlib_free_image();
+    
     return (mb_img_data_t *)img;
 }
 
@@ -72,8 +109,7 @@
 void simple_mb_img_ldr_img_free(mb_img_data_t *img) {
     simple_mb_img_data_t *simg = (simple_mb_img_data_t *)img;
 
-    imlib_context_set_image(simg->img_hdl);
-    imlib_free_image();
+    free(simg->img.content);
     free(img);
 }