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