Author: spouliot
Date: 2007-01-10 16:21:56 -0500 (Wed, 10 Jan 2007)
New Revision: 70814

Modified:
   trunk/libgdiplus/src/ChangeLog
   trunk/libgdiplus/src/bmpcodec.c
   trunk/libgdiplus/src/bmpcodec.h
   trunk/libgdiplus/src/icocodec.c
   trunk/libgdiplus/src/icocodec.h
   trunk/libgdiplus/src/image.c
Log:
2007-01-10  Sebastien Pouliot  <[EMAIL PROTECTED]>

        * bmpcodec.c|h: Refactor some decoding code to share with the ICON 
        decoder.
        * icocodec.c|h: Implement icon decoder, reusing some parts of the BMP
         codec.
        * image.c: Add ICON format support to GdipLoadImageFromDelegate_linux.



Modified: trunk/libgdiplus/src/ChangeLog
===================================================================
--- trunk/libgdiplus/src/ChangeLog      2007-01-10 21:03:04 UTC (rev 70813)
+++ trunk/libgdiplus/src/ChangeLog      2007-01-10 21:21:56 UTC (rev 70814)
@@ -1,3 +1,11 @@
+2007-01-10  Sebastien Pouliot  <[EMAIL PROTECTED]>
+
+       * bmpcodec.c|h: Refactor some decoding code to share with the ICON 
+       decoder.
+       * icocodec.c|h: Implement icon decoder, reusing some parts of the BMP
+        codec.
+       * image.c: Add ICON format support to GdipLoadImageFromDelegate_linux.
+
 2007-01-08  Sebastien Pouliot  <[EMAIL PROTECTED]>
 
        * bmpcodec.c: Add missing SigPattern and SigMask to codec;

Modified: trunk/libgdiplus/src/bmpcodec.c
===================================================================
--- trunk/libgdiplus/src/bmpcodec.c     2007-01-10 21:03:04 UTC (rev 70813)
+++ trunk/libgdiplus/src/bmpcodec.c     2007-01-10 21:21:56 UTC (rev 70814)
@@ -692,6 +692,93 @@
        return Ok;
 }
 
+GpStatus
+gdip_read_BITMAPINFOHEADER (void *pointer, BITMAPINFOHEADER *bmi, bool 
useFile, BOOL *os2format, BOOL *upsidedown)
+{
+       DWORD dw = 0;
+       byte *data_read = (byte*)&dw;
+       int size = sizeof (DWORD);
+       int size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+
+       bmi->biSize = (data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | 
data_read[0]);
+       if (bmi->biSize > BITMAPCOREHEADER_SIZE){   /* New Windows headers can 
be bigger */ 
+               dw = 0;
+               size_read = gdip_read_bmp_data (pointer, data_read, size, 
useFile);
+               if (size_read < size)
+                       return InvalidParameter;
+               bmi->biWidth = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
+
+               dw = 0;
+               size_read = gdip_read_bmp_data (pointer, data_read, size, 
useFile);
+               if (size_read < size)
+                       return InvalidParameter;
+               bmi->biHeight = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
+       } else if (bmi->biSize == BITMAPCOREHEADER_SIZE) {
+               /* Old OS/2 format. Width and Height fields are WORDs instead 
of DWORDS */
+               dw = 0;
+               size_read = gdip_read_bmp_data (pointer, data_read, size, 
useFile);
+               if (size_read < size)
+                       return InvalidParameter;
+               bmi->biWidth = (data_read[1]<<8 | data_read[0]);
+               bmi->biHeight = (data_read[3]<<8 | data_read[2]);
+               *os2format = TRUE;
+       } else {
+               return UnknownImageFormat;
+       }
+
+       dw = 0;
+       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+       bmi->biPlanes = (data_read[1]<<8 | data_read[0]); 
+       bmi->biBitCount = (data_read[3]<<8 | data_read[2]); 
+
+       dw = 0;
+       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+       bmi->biCompression = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
+               
+       if (bmi->biHeight < 0) { /* Negative height indicates that the bitmap 
is sideup*/
+               upsidedown = FALSE;
+               bmi->biHeight = -bmi->biHeight;
+       }
+
+       dw = 0;
+       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+       bmi->biSizeImage = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
+               
+       dw = 0;
+       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+       bmi->biXPelsPerMeter = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
+       
+       dw = 0;
+       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+       bmi->biYPelsPerMeter = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
+               
+       dw = 0;
+       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+       bmi->biClrUsed = (data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 
| data_read[0]);
+               
+       dw = 0;
+       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
+       if (size_read < size)
+               return InvalidParameter;
+       bmi->biClrImportant = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
+
+       return Ok;
+}
+
 GpStatus 
 gdip_read_bmp_image_from_file_stream (void *pointer, GpImage **image, bool 
useFile)
 {
@@ -737,118 +824,10 @@
        bmfh.bfOffBits = (data_read[13]<<24 | data_read[12]<<16 | 
data_read[11]<<8 | data_read[10]);
        GdipFree(data_read);
 
-       size = sizeof(DWORD);
-       data_read = (byte*)GdipAlloc(size);
-       if (data_read == NULL) {
-               status = OutOfMemory;
+       status = gdip_read_BITMAPINFOHEADER (pointer, &bmi, useFile, 
&os2format, &upsidedown);
+       if (status != Ok)
                goto error;
-       }
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
 
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-
-       bmi.biSize = (data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 | 
data_read[0]);
-
-       if (bmi.biSize > BITMAPCOREHEADER_SIZE){   /* New Windows headers can 
be bigger */ 
-               memset (data_read, 0, size);
-               size_read = gdip_read_bmp_data (pointer, data_read, size, 
useFile);
-               if (size_read < size) {
-                       status = InvalidParameter;
-                       goto error;
-               }
-               bmi.biWidth = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
-
-               memset (data_read, 0, size);
-               size_read = gdip_read_bmp_data (pointer, data_read, size, 
useFile);
-               if (size_read < size) {
-                       status = InvalidParameter;
-                       goto error;
-               }
-               bmi.biHeight = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
-       } else  {
-               if (bmi.biSize ==  BITMAPCOREHEADER_SIZE) {
-                       /* Old OS/2 format. Width and Height fields are WORDs 
instead of DWORDS */
-                       memset (data_read, 0, size);
-                       size_read = gdip_read_bmp_data (pointer, data_read, 
size, useFile);
-                       if (size_read < size) {
-                               status = InvalidParameter;
-                               goto error;
-                       }
-                       bmi.biWidth = (data_read[1]<<8 | data_read[0]);
-                       bmi.biHeight = (data_read[3]<<8 | data_read[2]);
-                       os2format = TRUE;
-               } else {
-                       status = UnknownImageFormat;
-                       goto error;
-               }
-       }
-
-       memset (data_read, 0, size);
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-       bmi.biPlanes = (data_read[1]<<8 | data_read[0]); 
-       bmi.biBitCount = (data_read[3]<<8 | data_read[2]); 
-
-       memset (data_read, 0, size);
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-       bmi.biCompression = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
-               
-       if (bmi.biHeight < 0) { /* Negative height indicates that the bitmap is 
sideup*/
-               upsidedown = FALSE;
-               bmi.biHeight =  -bmi.biHeight;
-       }
-
-       memset (data_read, 0, size);
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-       bmi.biSizeImage = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
-               
-       memset (data_read, 0, size);
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-       bmi.biXPelsPerMeter = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
-       
-       memset (data_read, 0, size);
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-       bmi.biYPelsPerMeter = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
-               
-       memset (data_read, 0, size);
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-       bmi.biClrUsed = (data_read[3]<<24 | data_read[2]<<16 | data_read[1]<<8 
| data_read[0]);
-               
-       memset (data_read, 0, size);
-       size_read = gdip_read_bmp_data (pointer, data_read, size, useFile);
-       if (size_read < size) {
-               status = InvalidParameter;
-               goto error;
-       }
-
-       bmi.biClrImportant = (data_read[3]<<24 | data_read[2]<<16 | 
data_read[1]<<8 | data_read[0]);
-               
        colours = (bmi.biClrUsed == 0 && bmi.biBitCount <= 8) ? (1 << 
bmi.biBitCount) : bmi.biClrUsed;
 
        status = gdip_get_bmp_pixelformat (bmi.biBitCount, bmi.biCompression, 
&format);
@@ -877,7 +856,6 @@
                        break;
        }
 
-       GdipFree(data_read);
        data_read = NULL;
 
        /* Ensure pixman_bits_t alignment */

Modified: trunk/libgdiplus/src/bmpcodec.h
===================================================================
--- trunk/libgdiplus/src/bmpcodec.h     2007-01-10 21:03:04 UTC (rev 70813)
+++ trunk/libgdiplus/src/bmpcodec.h     2007-01-10 21:21:56 UTC (rev 70814)
@@ -99,4 +99,8 @@
 int
 gdip_read_bmp_data (void *pointer, byte *data, int size, bool useFile);
 
+/* helper functions / shared with ICOn codec */
+GpStatus gdip_read_BITMAPINFOHEADER (void *pointer, BITMAPINFOHEADER *bmi, 
bool useFile, BOOL *os2format, BOOL *upsidedown);
+int gdip_read_bmp_data (void *pointer, byte *data, int size, bool useFile);
+
 #endif /* _BMPCODEC_H */

Modified: trunk/libgdiplus/src/icocodec.c
===================================================================
--- trunk/libgdiplus/src/icocodec.c     2007-01-10 21:03:04 UTC (rev 70813)
+++ trunk/libgdiplus/src/icocodec.c     2007-01-10 21:21:56 UTC (rev 70814)
@@ -51,14 +51,225 @@
        return &ico_codec; 
 }
 
+static BYTE
+get_ico_data (BYTE *data, int x, int y, int bpp, int line_length)
+{
+       BYTE result = 0;
+       BYTE *line_data = data + y * line_length;
+
+       switch (bpp) {
+       case 1:
+               result = (line_data [x >> 3] >> (7 - (x & 7))) & 0x01;
+               break;
+       case 4:
+               result = line_data [x >> 1];
+               if ((x & 1) == 1)
+                       result &= 0x0F;
+               else
+                       result >>= 4;
+               break;
+       case 8:
+               result = line_data [x];
+               break;
+       }
+       return result;
+}
+
+static GpStatus
+gdip_read_ico_image_from_file_stream (void *pointer, GpImage **image, bool 
useFile)
+{
+       GpStatus status = InvalidParameter;
+       GpBitmap *result = NULL;
+       guchar *pixels = NULL;
+       WORD w, count;
+       void *p = &w;
+       BYTE *b = (BYTE*)&w;
+       ICONDIRENTRY entry;
+       int i, pos;
+       BOOL upsidedown = TRUE;
+       BOOL os2format = FALSE;
+       BITMAPINFOHEADER bih;
+       int palette_entries;
+       ARGB *colors = NULL;
+       int x, y;
+       int line_xor_length, xor_size;
+       int line_and_length, and_size;
+       BYTE *xor_data = NULL, *and_data = NULL;
+
+       /* WORD ICONDIR.idReserved / reversed, MUST be 0 */
+       if (gdip_read_ico_data (pointer, p, sizeof (WORD), useFile) != sizeof 
(WORD))
+               goto error;
+       if (w != 0)
+               goto error;
+
+       /* WORD ICONDIR.idType / resource type, MUST be 1 for icons */
+       if (gdip_read_ico_data (pointer, p, sizeof (WORD), useFile) != sizeof 
(WORD))
+               goto error;
+       if (w != 1)
+               goto error;
+
+       /* WORD ICONDIR.idCount / number of icons, must be greater than 0 */
+       if (gdip_read_ico_data (pointer, p, sizeof (WORD), useFile) != sizeof 
(WORD))
+               goto error;
+       count = (b[1] << 8 | b[0]); 
+       if (count < 1)
+               goto error;
+
+       pos = 6;
+       /*
+        * NOTE: it looks like (from unit tests) that we get the last icon 
+        * (e.g. it can return the 16 pixel version, instead of the 32 or 48 
pixels available in the same file)
+        */ 
+       for (i = 0; i < count; i++) {
+               if (gdip_read_ico_data (pointer, (void*)&entry, sizeof 
(ICONDIRENTRY), useFile) != sizeof (ICONDIRENTRY))
+                       goto error;
+               pos += sizeof (ICONDIRENTRY);
+       }
+
+       while (pos < entry.dwImageOffset) {
+               if (gdip_read_ico_data (pointer, p, sizeof (WORD), useFile) != 
sizeof (WORD))
+                       goto error;
+               pos += sizeof (WORD);
+       }
+
+       /* BITMAPINFOHEADER */
+       status = gdip_read_BITMAPINFOHEADER (pointer, &bih, useFile, 
&os2format, &upsidedown);
+       if (status != Ok)
+               goto error;
+       
+       result = gdip_bitmap_new_with_frame (NULL, TRUE);
+       result->type = imageBitmap;
+       result->image_format = ICON;
+       result->active_bitmap->pixel_format = Format32bppArgb; /* icons are 
always promoted to 32 bbp */
+       result->active_bitmap->width = entry.bWidth;
+       result->active_bitmap->height = entry.bHeight;
+       result->active_bitmap->stride = result->active_bitmap->width * 4;
+       /* Ensure pixman_bits_t alignment */
+       result->active_bitmap->stride += (sizeof(pixman_bits_t) - 1);
+       result->active_bitmap->stride &= ~(sizeof(pixman_bits_t) - 1);
+       result->active_bitmap->dpi_horz = 96.0f;
+       result->active_bitmap->dpi_vert = 96.0f;
+
+       switch (bih.biBitCount) {
+       case 1:
+       case 4:
+       case 8:
+               /* support 2, 16 and 256 colors icons, no compression */
+               if (bih.biCompression == 0) {
+                       palette_entries = 1 << bih.biBitCount;
+                       break;
+               }
+                /* fall through */
+       default:
+               status = InvalidParameter;
+               goto error;
+       }
+
+       /*
+        * Strangely, even if we're supplying a 32bits ARGB image, 
+        * the icon's palette is also supplied with the image.
+        */
+       result->active_bitmap->palette = GdipAlloc (sizeof(ColorPalette) + 
sizeof(ARGB) * palette_entries);
+       if (result->active_bitmap->palette == NULL) {
+               status = OutOfMemory;
+               goto error;
+       }
+       result->active_bitmap->palette->Flags = 0;
+       result->active_bitmap->palette->Count = palette_entries;
+
+       for (i = 0; i < palette_entries; i++) {
+               /* colors are stored as R, G, B and reserved (always 0) */
+               BYTE color[4]; 
+               void *p = &color;
+
+               if (gdip_read_ico_data (pointer, p, 4, useFile) < 4) {
+                       status = InvalidParameter;
+                       goto error;
+               }
+
+               set_pixel_bgra (result->active_bitmap->palette->Entries, i * 4,
+                       (color[0] & 0xFF),              /* B */
+                       (color[1] & 0xFF),              /* G */
+                       (color[2] & 0xFF),              /* R */
+                       0xFF);                          /* Alpha */
+       }
+
+       /*
+        * Let's build the 32bpp ARGB bitmap from the icon's XOR and AND bitmaps
+        * notes:
+        * - XORBitmap can be a 1, 4 or 8 bpp bitmap
+        * - ANDBitmap is *always* a monochrome (1bpp) bitmap
+        * - in every case each line is padded to 32 bits boundary
+        */
+       pixels = GdipAlloc (result->active_bitmap->stride * 
result->active_bitmap->height);
+       if (pixels == NULL) {
+               status = OutOfMemory;
+               goto error;
+       }
+
+       result->active_bitmap->scan0 = pixels;
+       result->active_bitmap->reserved = GBD_OWN_SCAN0;
+       result->active_bitmap->image_flags = ImageFlagsReadOnly | 
ImageFlagsHasRealPixelSize | ImageFlagsColorSpaceRGB | ImageFlagsHasAlpha;
+
+       line_xor_length = (((bih.biBitCount * entry.bWidth + 31) & ~31) >> 3);
+       xor_size = line_xor_length * entry.bHeight;
+       xor_data = (BYTE*) GdipAlloc (xor_size);
+       if (!xor_data) {
+               status = OutOfMemory;
+               goto error;
+       }
+       if (gdip_read_ico_data (pointer, xor_data, xor_size, useFile) < 
xor_size) {
+               status = InvalidParameter;
+               goto error;
+       }
+
+       line_and_length = (((entry.bWidth + 31) & ~31) >> 3);
+       and_size = line_and_length * entry.bHeight;
+       and_data = (BYTE*) GdipAlloc (and_size);
+       if (!and_data) {
+               status = OutOfMemory;
+               goto error;
+       }
+       if (gdip_read_ico_data (pointer, and_data, and_size, useFile) < 
and_size) {
+               status = InvalidParameter;
+               goto error;
+       }
+
+       colors = result->active_bitmap->palette->Entries;
+       for (y = 0; y < entry.bHeight; y++) {
+               for (x = 0; x < entry.bWidth; x++) {
+                       ARGB color = colors [get_ico_data (xor_data, x, y, 
bih.biBitCount, line_xor_length)];
+                       if (get_ico_data (and_data, x, y, 1, line_and_length) 
== 1)
+                               color = color & 0x00FFFFFF;
+                       /* image is reversed (y) */
+                       GdipBitmapSetPixel (result, x, entry.bHeight - y - 1, 
color);
+               }
+       }
+
+       GdipFree (xor_data);
+       GdipFree (and_data);
+
+       *image = result;
+       return Ok;
+
+error:
+       if (result->active_bitmap->palette)
+               GdipFree (result->active_bitmap->palette);
+       if (xor_data)
+               GdipFree (xor_data);
+       if (and_data)
+               GdipFree (and_data);
+       return status;
+}
+
 GpStatus 
 gdip_load_ico_image_from_file (FILE *fp, GpImage **image)
 {
-       return NotImplemented;
+       return gdip_read_ico_image_from_file_stream ((void*)fp, image, TRUE);
 }
 
 GpStatus 
 gdip_load_ico_image_from_stream_delegate (dstream_t *loader, GpImage **image)
 {
-       return NotImplemented;
+       return gdip_read_ico_image_from_file_stream ((void *)loader, image, 
FALSE);
 }

Modified: trunk/libgdiplus/src/icocodec.h
===================================================================
--- trunk/libgdiplus/src/icocodec.h     2007-01-10 21:03:04 UTC (rev 70813)
+++ trunk/libgdiplus/src/icocodec.h     2007-01-10 21:21:56 UTC (rev 70814)
@@ -27,7 +27,23 @@
 #include "gdip.h"
 #include "gdipImage.h"
 #include "dstream.h"
+#include "bmpcodec.h"
 
+/* Information about the icon format can be found @ 
http://www.daubnet.com/formats/ICO.html */
+
+typedef struct {
+       BYTE    bWidth;
+       BYTE    bHeight;
+       BYTE    bColorCount;
+       BYTE    bReserved;
+       WORD    wPlanes;
+       WORD    wBitCount;
+       DWORD   dwBytesInRes;
+       DWORD   dwImageOffset;
+} ICONDIRENTRY;
+
+#define gdip_read_ico_data     gdip_read_bmp_data
+
 GpStatus gdip_load_ico_image_from_file (FILE *fp, GpImage **image);
 
 GpStatus gdip_load_ico_image_from_stream_delegate (dstream_t *loader, GpImage 
**image);

Modified: trunk/libgdiplus/src/image.c
===================================================================
--- trunk/libgdiplus/src/image.c        2007-01-10 21:03:04 UTC (rev 70813)
+++ trunk/libgdiplus/src/image.c        2007-01-10 21:21:56 UTC (rev 70814)
@@ -950,6 +950,10 @@
                        memcpy(format, &gdip_membmp_image_format_guid, 16);
                        return Ok;
 
+               case ICON:
+                       memcpy (format, &gdip_ico_image_format_guid, 16);
+                       return Ok;
+
                default:
                        return InvalidParameter;
        }

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to