oleaut32: handle transparency data when loading PNG images

Evan Stade estade at gmail.com
Wed Aug 8 21:42:33 CDT 2007


Hi,

Instead of flattening the alpha channel completely, this maps pixels
with full transparency (alpha channel 0x00) to transparent.  Alpha
channel of anything else is still mapped to full opacity.

 dlls/oleaut32/olepicture.c |   98 +++++++++++++++++++++++++++++++++++++-------
 1 files changed, 82 insertions(+), 16 deletions(-)

-- 
Evan Stade
-------------- next part --------------
diff --git a/dlls/oleaut32/olepicture.c b/dlls/oleaut32/olepicture.c
index b12a85b..d8f01db 100644
--- a/dlls/oleaut32/olepicture.c
+++ b/dlls/oleaut32/olepicture.c
@@ -1376,6 +1376,9 @@ MAKE_FUNCPTR(png_set_bgr);
 MAKE_FUNCPTR(png_destroy_read_struct);
 MAKE_FUNCPTR(png_set_palette_to_rgb);
 MAKE_FUNCPTR(png_read_update_info);
+MAKE_FUNCPTR(png_get_tRNS);
+MAKE_FUNCPTR(png_get_PLTE);
+MAKE_FUNCPTR(png_set_expand);
 #undef MAKE_FUNCPTR
 
 static void *load_libpng(void)
@@ -1397,6 +1400,9 @@ #define LOAD_FUNCPTR(f) \
         LOAD_FUNCPTR(png_destroy_read_struct);
         LOAD_FUNCPTR(png_set_palette_to_rgb);
         LOAD_FUNCPTR(png_read_update_info);
+        LOAD_FUNCPTR(png_get_tRNS);
+        LOAD_FUNCPTR(png_get_PLTE);
+        LOAD_FUNCPTR(png_set_expand);
 
 #undef LOAD_FUNCPTR
     }
@@ -1410,13 +1416,17 @@ #ifdef SONAME_LIBPNG
     png_io              io;
     png_structp         png_ptr = NULL;
     png_infop           info_ptr = NULL;
-    INT                 row, rowsize, height, width;
+    INT                 row, rowsize, height, width, num_trans, i, j;
     png_bytep*          row_pointers = NULL;
     png_bytep           pngdata = NULL;
     BITMAPINFOHEADER    bmi;
-    HDC                 hdcref = NULL;
+    HDC                 hdcref = NULL, hdcXor, hdcMask;
     HRESULT             ret;
-    BOOL                set_bgr = FALSE;
+    BOOL                transparency;
+    png_bytep           trans;
+    png_color_16p       trans_values;
+    COLORREF            white = RGB(255, 255, 255), black = RGB(0, 0, 0);
+    HBITMAP             hbmoldXor, hbmoldMask, temp;
 
     if(!libpng_handle) {
         if(!load_libpng()) {
@@ -1435,7 +1445,7 @@ #ifdef SONAME_LIBPNG
     if(setjmp(png_jmpbuf(png_ptr))){
         TRACE("Error in libpng\n");
         ret = E_FAIL;
-        goto pngend;
+        goto end;
     }
 
     info_ptr = ppng_create_info_struct(png_ptr);
@@ -1447,19 +1457,16 @@ #ifdef SONAME_LIBPNG
          png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
         FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
         ret = E_FAIL;
-        goto pngend;
+        goto end;
     }
 
-    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE){
-        ppng_set_palette_to_rgb(png_ptr);
-        set_bgr = TRUE;
-    }
+    transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
+                       == PNG_INFO_tRNS);
 
-    if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
-        png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
-        set_bgr){
-        ppng_set_bgr(png_ptr);
-    }
+    /* sets format from anything to RGBA */
+    ppng_set_expand(png_ptr);
+    /* sets format to BGRA */
+    ppng_set_bgr(png_ptr);
 
     ppng_read_update_info(png_ptr, info_ptr);
 
@@ -1474,7 +1481,7 @@ #ifdef SONAME_LIBPNG
 
     if(!pngdata || !row_pointers){
         ret = E_FAIL;
-        goto pngend;
+        goto end;
     }
 
     for (row = 0; row < height; row++){
@@ -1504,12 +1511,71 @@ #ifdef SONAME_LIBPNG
         (BITMAPINFO*)&bmi,
         DIB_RGB_COLORS
     );
+
+    /* only fully-transparent alpha is handled */
+    if((info_ptr->channels != 4) || !transparency){
+        ReleaseDC(0, hdcref);
+        goto succ;
+    }
+
+    This->hbmXor = CreateDIBitmap(
+        hdcref,
+        &bmi,
+        CBM_INIT,
+        pngdata,
+        (BITMAPINFO*)&bmi,
+        DIB_RGB_COLORS
+    );
+
+    /* set transparent pixels to black, all others to white */
+    for(i = 0; i < height; i++){
+        for(j = 3; j < rowsize; j += 4){
+            if(row_pointers[i][j] == 0)
+                *((DWORD*)(&row_pointers[i][j - 3])) = black;
+            else
+                *((DWORD*)(&row_pointers[i][j - 3])) = white;
+        }
+    }
+
+    temp = CreateDIBitmap(
+        hdcref,
+        &bmi,
+        CBM_INIT,
+        pngdata,
+        (BITMAPINFO*)&bmi,
+        DIB_RGB_COLORS
+    );
+
     ReleaseDC(0, hdcref);
+
+    This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
+    hdcXor = CreateCompatibleDC(NULL);
+    hdcMask = CreateCompatibleDC(NULL);
+
+    hbmoldXor = SelectObject(hdcXor,temp);
+    hbmoldMask = SelectObject(hdcMask,This->hbmMask);
+    SetBkColor(hdcXor,black);
+    BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
+
+    SelectObject(hdcXor,This->hbmXor);
+    DeleteObject(temp);
+
+    SetTextColor(hdcXor,white);
+    SetBkColor(hdcXor,black);
+    BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
+
+    SelectObject(hdcXor,hbmoldXor);
+    SelectObject(hdcMask,hbmoldMask);
+
+    DeleteDC(hdcXor);
+    DeleteDC(hdcMask);
+
+succ:
     This->desc.picType = PICTYPE_BITMAP;
     OLEPictureImpl_SetBitmap(This);
     ret = S_OK;
 
-pngend:
+end:
     if(png_ptr)
         ppng_destroy_read_struct(&png_ptr,
                                 (info_ptr ? &info_ptr : (png_infopp) NULL),
-- 
1.4.1


More information about the wine-patches mailing list