[Mono-winforms-list] libgdiplus/System.Drawing patch: native support for indexed Bitmaps

Jonathan Gilbert 2a5gjx302@sneakemail.com
Fri, 11 Mar 2005 13:22:22 -0500


--=====================_1110583342==_
Content-Type: text/plain; charset="us-ascii"

At 02:12 AM 05/03/2005 -0500, I wrote:
>Please find attached the following files:
>
>* libgdiplus.diff (patch -p0 in ./libgdiplus)
>* System.Drawing.diff (patch -p0 in ./mcs/class/System.Drawing)
>* lockbits.tgz (tar zvfx in ./)

Updated diffs and some extra testing code: testgif.tgz (DOES NOT contain a
subdirectory; untar directly within the intended destination)

Changes from the previous patch:
* Fixed the call to gdip_is_an_indexed_pixelformat that did not actually
call the function because it was missing the argument list.
* Added indexed loading & saving support to gifcodec.c.
* Updated Image.Palette to behave like Microsoft's implementation. I
discovered its bizarre behaviour when I tried to write a program for the
Microsoft framework to save an indexed 8-bit Bitmap with a custom palette.
It does not actually behave like a property, and should really have been
engineered as two separate functions, since there is no persistence
involved. Reading from the property creates a new instance of
System.Drawing.Imaging.ColorPalette and fills it from the underlying GDI+
GpImage object. However, the underlying GpImage's palette is only updated
if you assign to the property. Since you are not allowed to create
instances of ColorPalette directly, you end up having to write code like this:

ColorPalette palette = my_bitmap.Palette;

for (int i=0; i < palette.Entries.Length; i++)
  palette.Entries[i] = Color.FromArgb(ar, gu, ments);

my_bitmap.Palette = palette; /* assign the same instance back! if this is
skipped, the image file will display and save with the old palette */

This is not documented in MSDN! But whatever the case, mono now behaves the
same way.

Oh, and one other thing: This time I actually verified that the diffs apply
cleanly :-)

Jonathan Gilbert

--=====================_1110583342==_
Content-Type: application/octet-stream; name="testgif.tgz"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="testgif.tgz"

H4sIAB61MEICA+yaB1wT99/Hv2HGQGOqCLEFSQQtQcCEHdAKQQViUQxttSgq
U9l7iFWDqCgooqI4UBkiILKHIC6KUEAUd1ERUVSqshwVKkqeTJJggOT1vGqf
5//3xyW5z929ecMlH3J3xM7Z293D08cd/sFBJBGJxoaGQOSM4Y9EfZIRkJj3
hiQDfQMjY+b2JH0SEXBE+AwjNDjEOQiHgyB//5DRthtr/f/T4ebu4RzqE2KG
c/bxQaGYd2a4EPfgED33CHf2jD5rDoXiLeOudQ1GjfN1DeYFnG6QmcPa4BB3
X725Qc7hnn6rOYQ+H9EXYvRFQ/BlfO7BejZIxnouvgH/Vv9J+gZEY3b/DUxM
jAz1iaz+GzIXfen/ZxgUu1olzlwY86bF+ovAvSFAhr3cnrn+EppzEx509gR0
OueB9cVaxLy7ePEicwmDPQGDwXlgfbEWsbLo8aGxsUnkir8PwkhMY2Oj6BUH
R2RG0YzIjKIZiRlNc2wEZjQNQzQzqmYEZlSNaGZ0jWhmdI1IZgyNSGYMjShm
LI0oZiyNCGZMjQhmTM2nzNiaT5mxNZ8wYmg+YcTQDGfE0QxnxNEMY8TSDGPE
0ggz4mmEGfE0QoyYGiFGTI0gI65GkBFXI8CIrRFgxNbwGfE1fEZ8zRAjgWaI
kUDDYyTR8BhJNFxGIg2XkUjDYSTTcBjJNGxGQg2bkVDDYiTVsBhJNUxGYg2T
kVjDZiTUsBkJNR9GZEbWNDKZJgk1jSMd842iGZEZRTMSM5pmJGY0TZNoZlTN
CMeJo2pEM6NrRDOja0QyY2hEMmNoRDFjaUQxY2lEMGNqRDBjaj5lxtZ8yoyt
+YQRQ/MJI4ZmOCOOZjgjjmYYI5ZmGCOWRpgRTyPMiKcRYsTUCDFiagQZcTWC
jLgaAUZsjQAjtobPiK/hM+JrhhgJNEOMBBoeI4mGx0ii4TISabiMRBoOI5mG
w0imYTMSatiMhBoWI6mGxUiqYTISa5jMiJrGkY4GWcyxkX6yRsaIjIRX7Rhf
ruL/L6///7OX/8f6/58ByeST6/8G+kZfrv9/nuv/G+Q4c99/cv0fwV5uISf6
+v/QdfxBefYDHXjXIcYPtZI906/O3moo987hnt1xc9tG9lYYXr7I2YrIy1Gc
rQJ4WZqzVS83c/VRvMzVS/MyVy/Py1z9eF7m6tV5maufw8tc/UZe5uoZ3MzT
8zJPz8s8PS/z9LzM0/MyT8/LPD0v8/TcPKTn5iE9Nw/puXlIz81Dem4e0nPz
kJ6bh/SczNdzMl/PyXw9J/P1nMzXczJfz8l8PSfz9ewsoGdnAT07C+jZWUDP
zgJ6dhbQs7OAnp2lBV+gzCygZ2cBPaONl7k/JOs/YuoCL1C6cD8Yw/oxOKwf
/L5w9Py+RA3ri7RwX3j6Yf2IEu4Hvy9cvbxwP/h94erVhfvB74u0cF94+mH9
iBLuB78vPL1wP/h94emF+8Hvi7RwX4b0wv2IEu4Hvy9DeqF+8PsypBfqB78v
0sJ94euF+hEl3A9+X/h6wX7w+8LXC/aD3xdp4b4I6AX7ESXcD35fBPQC/eD3
RUAv0A9+X7j92CjcD/qwfvD78mX8Xzj+Y30a59/8/JcJcx3v+M+YqM86/iMZ
fTn+g8/z63v6rcZxPodljhJMvE9liV6qZ+vrvJq9FuXq4xwcjLNz9vSzYs2h
1qFwOOZODfF0xYX5e7qx12gRmAtZK3A4imeIr3MAjnnKsZLk4hmCm43T4iwi
cB705gf5+8739HHXmjp0cjKVYD6cNRSHNebBbJqn1HNwDhv67gF+q6fq4Fi/
jft8/yBf5xA9e7/VXB3PIwAYjgl8Yljt6TEMsPb0GM0wEiCsmOsZHOAf7K41
/DsJLV+PWo9CjdX/f7j+Y/bfwHDo/M/A0MSI1X+iicmX/v9H95/5Il/pyXqJ
j1pizxAfd3YfeC//IYzXGNYW+qN0bMwG/Je///P28L/Wf33mmz3zPZ/53m9g
SDIkct7/DUy+fP77swxr2/mmJs4WiDro4yxAAjDPLLEAeAACAAmADEABoALQ
2KuR7C2QGMCwt0NiAcPeGokHDB6wbAxJAAwBsATAM+dJgCEBlgR4EiDJgKQA
hgwY5j0VMDTAOALGFbAUwFIBSwOsI2BdAU8GPAXwNCAYAWE+kMhAogDZBgg0
INGATAMKDajMtY5AdgSKI1AdAe8KBFfAeAPWG/DegAkGbDDgmfcbAb8OSJ5g
HArW7jA3FGiuQPMG6jqghcOU7YBNBMI2mJYI2GSYlgz4DMAXgm4KkHLBcgfY
pAKhFAjnwOA0zC8DQi0QrgLhDhA6gFQLpKtAugOkViA3APkOUKuBcgfIrUBt
BVIHkDuA0gHUDqAxN+4Bcg9QeoDaA6Q+IPcBpQ+ofUDrAxIDyAygMIDKYO5a
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
yWrIrmpG77rxNgXxFOdohaIH1BrulFWTGf/yORqVkrhrhtrLBRkv0LlFb1S/
aa7RSyYmZCmHnVyWHCcX8miTRl570YGPj5ZcOOnQuKKsoP2DtsasgbuhRKnj
Ly75OM/8Nr4kLxDxDDfYNf/jNzdkk9NLDvj6WjIqFt84OqE0FdflZTVwZXGb
cjHmp040tEGgarjahGQF6eWFccg65WK/Bz421useHIwMxTwp91syBwUdDXcq
cbI1oTWPHEknT1d6TtpMaFtw8+8GZTVFJEEurxIdVG6hUmkzT+63Gcvabs9T
qAyYJ9dfiV6y6RVGfUuA5TSdbadWJKl6Jvb6TbZsk9q1uHrl8t71xfftkEv6
zwR/nLqtEhv/Ms0Vox4KZnkLXCZFL740xfhS7IWlSwYPUaTVMTU7Zi9Pqn9B
qVJcEUPQ7nVGqv9Wbxamn3hMcZlcXHSC8fc/yuk0Prz5wrTBbGGuj+yAG9G8
orjoq5rBpIwPT9vSlmLc9YrxLT/c2180uWFxaOHKns4nE9+oqFnt1/3YuQfl
hD0kZXv+FGEuPcP88NqGrRH+e+y+jkW74aRTsLIzJtihTfP/bjy8sDhWzXeb
Uu8fmQ77iRpe+Na9tXcvZZbrzZil1kHcu+lC8NM3SXZH/iQ93ILYavxWfmlq
/LLlZc0vlloX7rqCWtz29jZtf9CWnbmdXjPv32s4EVZ0OrfLK33SvZUtPWXF
O+MVowcwr8+9K7+t6GsZQr/dvsL4ZKoaIjRgoDk3pTRZxQIVuuTwJEXT8GSV
VQobH357PxPUnFwS4pZjIxVSie90NY/6bHdoUT6Bc5t69MOTneq/tW9KqTEb
nP7969hdyY815qytd1j4epmmubRqX8RB26gg110/PVPv6ccr2yvE5Sc3bu9/
LLXjftBelfEd34anX/5FL/Dw07NxSs0lTU5+aNSl5HZyUwXuN1LoXpXZqqjM
yxNCrgcUvbRQUj5Wfm9R3rvtSVMvqD8sbyGjYzPy1z+e5F/x4K+j4a5Nkd2B
1iYzuruDwuQ3dGfUmt9f5BeLTp4pfai1smZX66sKhcdKyj3rdI8qI1D0NKUy
07UPPQMdL37n0j3FRObKzdawsmIXzNrrlOrVxxQ0d6RM8g1f2/3q+1d/rHTq
3m76qvuXRf0txU5d6ddIveSjUQ/yq5URc85dfaq38vHLB/2Vp2s6tQfz31jZ
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
if1/+j/3a3IzAHgAAA==

--=====================_1110583342==_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="libgdiplus.diff"

Index: src/bmpcodec.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/bmpcodec.c	(revision 41706)
+++ src/bmpcodec.c	(working copy)
@@ -39,6 +39,7 @@
 #include <stdio.h>
 #include "bmpcodec.h"
 #include "gdip.h"
+#include "gdipImage.h"


 /* Codecinfo related data*/
@@ -81,6 +82,8 @@
                 return Format8bppIndexed;
         case 4:
                 return Format4bppIndexed;
+	case 1:
+		return Format1bppIndexed;
         default:
                 return 0;
         }
@@ -96,7 +99,7 @@
 	bmi->biWidth =3D GULONG_FROM_LE (bitmap->data.Width);
 	bmi->biHeight =3D GULONG_FROM_LE (bitmap->data.Height);
 	bmi->biPlanes =3D GUINT16_FROM_LE (1);
-	bmi->biBitCount =3D GUINT16_FROM_LE (32); /*PIXEL_FORMAT_BPP (bitmap->ima=
ge.pixFormat); */
+	bmi->biBitCount =3D GUINT16_FROM_LE (gdip_get_pixel_format_bpp (bitmap->d=
ata.PixelFormat));
 	bmi->biCompression =3D GUINT32_FROM_LE (BI_RGB);
 	bmi->biSizeImage =3D  GUINT32_FROM_LE (0); /* Many tools expect this may =
be set to zero for BI_RGB bitmaps */
 	bmi->biXPelsPerMeter =3D GULONG_FROM_LE ((int) (0.5f + ((gdip_get_display=
_dpi() * 3937) / 100)));
@@ -106,7 +109,7 @@
 	bmi->biWidth =3D bitmap->data.Width;
 	bmi->biHeight =3D bitmap->data.Height;
 	bmi->biPlanes =3D 1;
-	bmi->biBitCount =3D 32; /*PIXEL_FORMAT_BPP (bitmap->image.pixFormat); */
+	bmi->biBitCount =3D gdip_get_pixel_format_bpp (bitmap->data.PixelFormat);
 	bmi->biCompression =3D BI_RGB;
 	bmi->biSizeImage =3D  0; /* Many tools expect this may be set to zero for=
 BI_RGB bitmaps */
 	bmi->biXPelsPerMeter =3D (int) (0.5f + ((gdip_get_display_dpi() * 3937) /=
 100));
@@ -130,7 +133,31 @@
 	fwrite (&bmfh, sizeof (bmfh), 1, fp);
 	gdip_bitmap_fill_info_header (bitmap, &bmi);
 	bmi.biHeight =3D -bmi.biHeight;
+
 	fwrite (&bmi, sizeof (bmi), 1, fp);
+
+	if (gdip_is_an_indexed_pixelformat (bitmap->data.PixelFormat)) {
+		int i;
+
+		int palette_entries =3D bitmap->image.palette->Count;
+		if (bitmap->data.PixelFormat =3D=3D Format4bppIndexed)
+			palette_entries =3D 16;
+
+		for (i=3D0; i < palette_entries; i++)
+		{
+			unsigned char entry[4];
+
+			unsigned int packed =3D bitmap->image.palette->Entries[i];
+
+			entry[0] =3D ((packed >> 16) & 0xFF); // B
+			entry[1] =3D ((packed >>  8) & 0xFF); // G
+			entry[2] =3D ( packed        & 0xFF); // R
+			entry[3] =3D ((packed >> 24) & 0xFF); // A
+
+			fwrite(entry, 4, 1, fp);
+		}
+	}
+
 	fwrite (bitmap->data.Scan0, bitmapLen, 1, fp);
 	fclose (fp);
 }
@@ -289,19 +316,34 @@
         img->image.width =3D bmi.biWidth;
         img->image.height =3D bmi.biHeight;

-        //img->data.PixelFormat =3D img->image.pixFormat;
-        img->data.PixelFormat =3D Format32bppArgb;
+        img->data.PixelFormat =3D img->image.pixFormat;
         img->data.Width =3D img->image.width;
         img->data.Height =3D img->image.height;

-	// We always assume 32 bit and translate into 32 bit from source format
-        img->data.Stride =3D (32 * img->image.width) / 8;
-        img->data.Stride =3D (img->data.Stride + 3) & ~3;
-
+	switch (img->data.PixelFormat)
+	{
+		case Format1bppIndexed: img->data.Stride =3D (img->image.width + 7) / 8;=
 break;
+		case Format4bppIndexed: img->data.Stride =3D (img->image.width + 1) / 2;=
 break;
+		case Format8bppIndexed: img->data.Stride =3D  img->image.width;         =
 break;
+		default:
+			/* For other types, we assume 32 bit and translate into 32 bit from sou=
rce format */
+			img->data.PixelFormat =3D Format32bppRgb;
+			img->data.Stride =3D img->image.width * 4;
+			break;
+	}
+
+	/* Ensure pixman_bits_t alignment */
+	img->data.Stride +=3D (sizeof(pixman_bits_t) - 1);
+	img->data.Stride &=3D ~(sizeof(pixman_bits_t) - 1);
+
         if (colours) {
-                img->image.palette =3D g_malloc (sizeof(ColorPalette) + si=
zeof(ARGB) * colours);
+		int palette_entries =3D colours;
+		if (img->data.PixelFormat =3D=3D Format4bppIndexed)
+			palette_entries =3D 256;
+
+                img->image.palette =3D g_malloc (sizeof(ColorPalette) + si=
zeof(ARGB) * palette_entries);
                 img->image.palette->Flags =3D 0;
-                img->image.palette->Count =3D colours;
+                img->image.palette->Count =3D palette_entries;

                 /* Read optional colour table*/
                 if (os2format) {  /* RGBTRIPLE */
@@ -314,9 +356,9 @@
 					return InvalidParameter;
 				}
 				img->image.palette->Entries[i] =3D
-					(((data_read[0]&0xff)<<16) | 	// R
+					(((data_read[2]&0xff)<<16) | 	// R
 					((data_read[1]&0xff)<<8) | 	// G
-					(data_read[2]&0xff));		// B
+					(data_read[0]&0xff));		// B
                         }
 			GdipFree(data_read);
                 }
@@ -330,9 +372,9 @@
 				}

                                 img->image.palette->Entries[i] =3D
-					(((data_read[0]&0xff)<<16)  | 	// R
+					(((data_read[2]&0xff)<<16)  | 	// R
 					((data_read[1]&0xff)<<8) | 	// G
-					((data_read[2]&0xff)) | 	// B
+					((data_read[0]&0xff)) | 	// B
 					((data_read[3]& 0xff)<<24));	// Alpha
                         }
 			GdipFree(data_read);
@@ -389,64 +431,12 @@
 		}

 		switch(bmi.biBitCount) {
-			case 1: {
-				int	c;
-				int	bit;
-
-				for (c =3D 0; c < loop; c++) {
-					for (bit =3D 0; bit < 8; bit++) {
-						index =3D (line * img->data.Stride) + (c*8 + bit) * 4;
-
-						if (((data_read[c] << bit) & 0x80) !=3D 0) {
-							set_pixel_bgra(pixels, index, 0xff, 0xff, 0xff, 0xff);
-						} else {
-							set_pixel_bgra(pixels, index, 0x00, 0x00, 0x00, 0xff);
-						}
-					}
-				}
-
-				for (bit =3D 0; bit < img->image.width % 8; bit++) {
-					index =3D (line * img->data.Stride) + (c*8 + bit) * 4;
-
-					if (((data_read[c] << bit) & 0x80) !=3D 0) {
-						set_pixel_bgra(pixels, index, 0xff, 0xff, 0xff, 0xff);
-					} else {
-						set_pixel_bgra(pixels, index, 0x00, 0x00, 0x00, 0xff);
-					}
-				}
+			case 1:
+			case 4:
+			case 8: memcpy(pixels + line * img->data.Stride,
+					data_read, size);
 				continue;
-			}

-			case 4: {
-				int c;
-
-				for (c =3D 0; c < loop; c++) {
-					pixel =3D palette_lookup((data_read[c] & 0xf0) >> 4);
-
-					index =3D (line * img->data.Stride) + c*8;
-
-					set_pixel_bgra(pixels, index, (pixel & 0xff0000) >> 16, (pixel & 0xff=
00) >> 8, pixel & 0xff, 0xff);
-
-					pixel =3D palette_lookup(data_read[c] & 0xf);
-
-					set_pixel_bgra(pixels, index+4, (pixel & 0xff0000) >> 16, (pixel & 0x=
ff00) >> 8, pixel & 0xff, 0xff);
-				}
-				continue;
-			}
-
-			case 8: {
-				int	c;
-
-				for (c =3D 0; c < loop; c++) {
-					pixel =3D palette_lookup(data_read[c]);
-
-					index =3D (line * img->data.Stride) + c*4;
-
-					set_pixel_bgra(pixels, index, (pixel & 0xff0000) >> 16, (pixel & 0xff=
00) >> 8, pixel & 0xff, 0xff);
-				}
-				continue;
-			}
-
 			case 24: {
 				int	src;
 				int	dest;
@@ -483,16 +473,18 @@
 	}

 	GdipFree(data_read);
-	g_free(img->image.palette);
-	img->image.palette =3D NULL;

 	img->data.Scan0 =3D pixels;
         img->data.Reserved =3D GBD_OWN_SCAN0;
-        img->image.surface =3D cairo_surface_create_for_image (pixels,
+
+	if (!gdip_is_an_indexed_pixelformat (img->data.PixelFormat)) {
+        	img->image.surface =3D cairo_surface_create_for_image (pixels,
                                                          img->cairo_format,
                                                          img->image.width,
                                                          img->image.height,
                                                          img->data.Stride);
+	}
+
         img->image.imageFlags =3D
                 ImageFlagsReadOnly |
                 ImageFlagsHasRealPixelSize |
@@ -562,9 +554,12 @@
 	gdip_write_bmp_data (pointer, (byte *)&bmi, sizeof (bmi), useFile);

         if (colours) {
+		int palette_entries =3D bitmap->image.palette->Count;
+		if (bitmap->data.PixelFormat =3D=3D Format4bppIndexed)
+			palette_entries =3D 16;

                 /* Write palette on disk on BGRA*/
-                for (i =3D 0; bitmap->image.palette->Count; i++) {
+                for (i =3D 0; i < palette_entries; i++) {
                         color =3D bitmap->image.palette->Entries[i];
 #ifdef WORDS_BIGENDIAN
                         b =3D color >> 24;
Index: src/image.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/image.c	(revision 41706)
+++ src/image.c	(working copy)
@@ -167,8 +167,24 @@

 	cairo_new_path(graphics->ct);

-	/* Create a surface for this bitmap if one doesn't exist */=20=20=20
-	gdip_bitmap_ensure_surface ((GpBitmap*) image);
+	if (gdip_is_an_indexed_pixelformat (((GpBitmap*) image)->data.PixelFormat=
)) {
+		/* Unable to create a surface for the bitmap; it is an indexed image.
+		 * Instead, it will first be converted to 32-bit RGB.
+		 */
+		GpStatus status =3D OutOfMemory;
+
+		GpBitmap *rgb_bitmap =3D gdip_convert_indexed_to_rgb ((GpBitmap *) image=
);
+
+		if (rgb_bitmap !=3D NULL) {
+			status =3D GdipDrawImageRect(graphics, (GpImage *)rgb_bitmap, x, y, wid=
th, height);
+			GdipDisposeImage((GpImage *)rgb_bitmap);
+		}
+
+		return status;
+	}
+
+	/* Create a surface for this bitmap if one doesn't exist */
+	gdip_bitmap_ensure_surface ((GpBitmap *) image);
 	cairo_surface_set_filter (((GpBitmap*) image)->image.surface, gdip_get_ca=
iro_filter (graphics->interpolation));

 	cairo_translate (graphics->ct, x, y);
@@ -257,6 +273,25 @@
 	g_return_val_if_fail (image !=3D NULL, InvalidParameter);
 	g_return_val_if_fail (image->type =3D=3D imageBitmap, InvalidParameter);

+	if (gdip_is_an_indexed_pixelformat (((GpBitmap *)image)->data.PixelFormat=
)) {
+                /* Unable to create a surface for the bitmap; it is an ind=
exed image.
+                 * Instead, it will first be converted to 32-bit RGB.
+                 */
+		GpStatus status =3D OutOfMemory;
+
+		GpBitmap *rgb_bitmap =3D gdip_convert_indexed_to_rgb ((GpBitmap *)image);
+
+		if (rgb_bitmap !=3D NULL) {
+			status =3D GdipDrawImageRectRect (graphics, (GpImage *)rgb_bitmap,
+				dstx, dsty, dstwidth, dstheight,
+				srcx, srcy, srcwidth, srcheight,
+				srcUnit, imageAttributes, callback, callbackData);
+			GdipDisposeImage ((GpImage *)rgb_bitmap);
+		}
+
+		return status;
+	}
+
 	if (srcUnit !=3D UnitPixel && srcUnit !=3D UnitWorld) {
 		gdip_unitConversion(srcUnit, UnitPixel, dstx, &dstx);
 		gdip_unitConversion(srcUnit, UnitPixel, dsty, &dsty);
@@ -1070,19 +1105,67 @@
 GpStatus
 GdipGetImagePalette (GpImage *image, ColorPalette *palette, int size)
 {
-	return NotImplemented;
+	int palette_entries;
+	int bytes_needed;
+
+	if ((image =3D=3D NULL) || (palette =3D=3D NULL))
+		return InvalidParameter;
+
+	if (image->palette =3D=3D NULL)
+		return InvalidParameter;
+
+	palette_entries =3D image->palette->Count;
+
+	if ((image->type =3D=3D imageBitmap) && (((GpBitmap *)image)->data.PixelF=
ormat =3D=3D Format4bppIndexed))
+		palette_entries =3D 16;
+
+	bytes_needed =3D palette_entries * sizeof(ARGB) + sizeof(ColorPalette) - =
sizeof(ARGB);
+
+	if (bytes_needed > size)
+		return InvalidParameter;
+
+	memcpy(palette, image->palette, bytes_needed);
+	return Ok;
 }

 GpStatus
 GdipSetImagePalette (GpImage *image, GDIPCONST ColorPalette *palette)
 {
+	int entries_to_copy;
+
+	if ((image =3D=3D NULL) || (palette =3D=3D NULL))
+		return InvalidParameter;
+
+	if (image->palette =3D=3D NULL)
+		return InvalidParameter;
+
+	entries_to_copy =3D image->palette->Count;
+	if (entries_to_copy > palette->Count)
+		entries_to_copy =3D palette->Count;
+
+	memcpy(image->palette->Entries, palette->Entries, entries_to_copy * sizeo=
f(ARGB));
 	return Ok;
 }

 GpStatus
 GdipGetImagePaletteSize (GpImage *image, int* size)
 {
-	return NotImplemented;
+        int palette_entries;
+        int bytes_needed;
+
+        if ((image =3D=3D NULL) || (size =3D=3D NULL))
+                return InvalidParameter;
+
+        if (image->palette =3D=3D NULL)
+                return InvalidParameter;
+
+        palette_entries =3D image->palette->Count;
+
+        if ((image->type =3D=3D imageBitmap) && (((GpBitmap *)image)->data=
.PixelFormat =3D=3D Format4bppIndexed))
+                palette_entries =3D 16;
+
+        *size =3D palette_entries * sizeof(ARGB) + sizeof(ColorPalette) - =
sizeof(ARGB);
+	return Ok;
 }

 GpStatus
Index: src/jpegcodec.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/jpegcodec.c	(revision 41706)
+++ src/jpegcodec.c	(working copy)
@@ -567,7 +567,10 @@
         case Format32bppPArgb:
         case Format32bppRgb:
         case Format24bppRgb:
-        case Format8bppIndexed: /* assume this is grayscale */
+	    break;
+        case Format8bppIndexed: /* check that this is grayscale */
+	    if ((image->palette->Flags & PaletteFlagsGrayScale) =3D=3D 0)
+		return InvalidParameter;
             break;
         default:
             return InvalidParameter;
Index: src/tiffcodec.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/tiffcodec.c	(revision 41706)
+++ src/tiffcodec.c	(working copy)
@@ -206,6 +206,9 @@
 	if (!tiff)
 		return InvalidParameter;

+	if (gdip_is_an_indexed_pixelformat (bitmap->data.PixelFormat))
+		return NotImplemented; /* for now */
+
 	dimensionCount =3D image->frameDimensionCount;
 	for (j =3D 0; j < dimensionCount; j++)
 		totalPages +=3D image->frameDimensionList [j].count;
Index: src/gifcodec.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/gifcodec.c	(revision 41706)
+++ src/gifcodec.c	(working copy)
@@ -208,11 +208,6 @@
 		img->image.frameDimensionList[0].frames =3D (BitmapData *) GdipAlloc (si=
zeof (BitmapData)*timeDimensionCount);
 	}

-	/* Note that Cairo/libpixman does not have support for indexed
-	* images, so we expand gifs out to 32bpp argb.
-	* This is unfortunate.
-	*/
-	#if 0
 	/* Copy the palette over, if there is one */
 	if (gif->SColorMap !=3D NULL) {
 		ColorPalette *pal =3D g_malloc (sizeof(ColorPalette) + sizeof(ARGB) * gi=
f->SColorMap->ColorCount);
@@ -226,14 +221,23 @@

 		img->image.palette =3D pal;
 	}
+	else {
+		/* Assume a grayscale image. */
+		img->image.palette =3D g_malloc (sizeof(ColorPalette) + 256 * sizeof(ARG=
B));
+
+		img->image.palette->Flags =3D PaletteFlagsGrayScale;
+		img->image.palette->Count =3D 256; /* FIXME: what about other bit depths=
? does GIF support them? does anybody use them? */
+
+		for (i=3D0; i < 256; i++) {
+			img->image.palette->Entries[i] =3D MAKE_ARGB_RGB(i, i, i);
+		}
+	}
+
 	img->image.pixFormat =3D Format8bppIndexed;
-	#endif

 	pal =3D gif->SColorMap;

-	img->image.pixFormat =3D Format32bppArgb;
-
-	img->cairo_format =3D CAIRO_FORMAT_ARGB32;
+	img->cairo_format =3D CAIRO_FORMAT_A8;

 	/*
 	 * Now populate the frames associated with each frame dimension
@@ -270,7 +274,7 @@
 		imgDesc =3D si.ImageDesc;
 		data.Width =3D imgDesc.Width;
 		data.Height =3D imgDesc.Height;
-		data.Stride =3D data.Width * 4;
+		data.Stride =3D (data.Width + sizeof(pixman_bits_t) - 1) & ~(sizeof(pixm=
an_bits_t) - 1);
 		data.Top =3D imgDesc.Top;
 		data.Left =3D imgDesc.Left;

@@ -280,19 +284,15 @@
 		writeptr =3D pixels;
 		pixelLength =3D data.Width * data.Height;
 		/*
-		 * While loading images, local color map if present takes precedence
-		 * over global color map.
+		 * FIXME: While loading images, local color map if present takes precede=
nce
+		 * over global color map. However, the palette is stored by the outer
+		 * GpImage, not BitmapData, so GDI+ apparently can't have a separate
+		 * palette for each frame. Convert files that would need one to ARGB 32-=
bit?
 		 */
-		for (j =3D 0; j < pixelLength; j++) {
-			guchar pix =3D *readptr++;
-			if (localPalObj) {
-				set_pixel_bgra(writeptr, 0, localPalObj->Colors[pix].Blue, localPalObj=
->Colors[pix].Green, localPalObj->Colors[pix].Red, 0xff);
-			} else if (pal) {
-				set_pixel_bgra(writeptr, 0, pal->Colors[pix].Blue, pal->Colors[pix].Gr=
een, pal->Colors[pix].Red, 0xff);
-			} else {
-				set_pixel_bgra(writeptr, 0, pix, pix, pix, 0xff);
-			}
-			writeptr +=3D 4;
+		for (j =3D 0; j < data.Height; j++) {
+			memcpy(writeptr, readptr, data.Width);
+			readptr +=3D data.Width;
+			writeptr +=3D data.Stride;
 		}

 		data.Scan0 =3D pixels;
@@ -311,15 +311,11 @@
 	}

 	img->data =3D img->image.frameDimensionList[0].frames[0];
-
-	img->image.surface =3D cairo_surface_create_for_image (img->data.Scan0, i=
mg->cairo_format,
-							img->image.width, img->image.height,
-							img->data.Stride);
+
 	img->image.imageFlags =3D ImageFlagsReadOnly | ImageFlagsHasRealPixelSize=
 | ImageFlagsColorSpaceRGB;
 	img->image.horizontalResolution =3D 0;
 	img->image.verticalResolution =3D 0;
 	img->image.propItems =3D NULL;
-	img->image.palette =3D NULL;

 	*image =3D (GpImage *) img;
 	return Ok;
@@ -366,6 +362,7 @@
 	GifFileType *fp;
 	int i, row, x, y, size;
 	GpBitmap *bitmap =3D (GpBitmap *) image;
+	ColorPalette *palette =3D image->palette;
 	GifByteType *red =3D NULL, *green =3D NULL, *blue =3D NULL, *pixels =3D N=
ULL;
 	GifByteType *ptr_red, *ptr_green, *ptr_blue, *ptr_pixels;
 	ARGB color =3D 0;
@@ -401,39 +398,134 @@
 			animationFlag =3D FALSE;

 		for (k =3D 0; k < frameCount; k++) {
-			cmap_size =3D 256;
-			cmap  =3D MakeMapObject (cmap_size, 0);
-
 			data =3D image->frameDimensionList [j].frames [k];
+
 			size =3D data.Height * data.Width;
 			sizeAlloc =3D sizeof (GifByteType)* size;
-			ptr_red  =3D red =3D GdipAlloc (sizeAlloc);
-			ptr_green =3D green =3D GdipAlloc (sizeAlloc);
-			ptr_blue =3D blue =3D GdipAlloc (sizeAlloc);
-			ptr_pixels =3D pixels =3D GdipAlloc (sizeAlloc);

+			if (gdip_is_an_indexed_pixelformat (data.PixelFormat)) {
+				unsigned char w;
+
+				switch (data.PixelFormat)
+				{
+					case Format1bppIndexed: cmap_size =3D   2; break;
+					case Format4bppIndexed: cmap_size =3D  16; break;
+					case Format8bppIndexed: cmap_size =3D 256; break;
+				}
+
+				cmap =3D MakeMapObject (cmap_size, 0);
+
+				ptr_pixels =3D pixels =3D GdipAlloc (sizeAlloc);
+
+				for (i =3D 0; (i < cmap_size) && (i < palette->Count); i++) {
+					v =3D (unsigned char *)&palette->Entries[i];
+
+#ifdef WORDS_BIGENDIAN
+					cmap->Colors[i].Red =3D   v[1];
+					cmap->Colors[i].Green =3D v[2];
+					cmap->Colors[i].Blue =3D  v[3];
+#else
+					cmap->Colors[i].Red =3D   v[2];
+					cmap->Colors[i].Green =3D v[1];
+					cmap->Colors[i].Blue =3D  v[0];
+#endif /* WORDS_BIGENDIAN */
+				}
+
+				switch (data.PixelFormat)
+				{
+					case Format1bppIndexed:
+						for (y =3D 0; y < data.Height; y++) {
+							v =3D ((unsigned char *)data.Scan0) + y * data.Stride;
+							for (x =3D 0; x + 7 < data.Width; x +=3D 8) {
+								w =3D *v;
+
+								*(ptr_pixels++) =3D ((w & 0x80) !=3D 0);
+								*(ptr_pixels++) =3D ((w & 0x40) !=3D 0);
+								*(ptr_pixels++) =3D ((w & 0x20) !=3D 0);
+								*(ptr_pixels++) =3D ((w & 0x10) !=3D 0);
+								*(ptr_pixels++) =3D ((w & 0x08) !=3D 0);
+								*(ptr_pixels++) =3D ((w & 0x04) !=3D 0);
+								*(ptr_pixels++) =3D ((w & 0x02) !=3D 0);
+								*(ptr_pixels++) =3D ((w & 0x01) !=3D 0);
+
+								v++;
+							}
+
+							w =3D *v;
+
+							switch (data.Width & 7) /* every 'case' here flows into the next */
+							{
+								case 7: ptr_pixels[6] =3D ((w & 0x02) !=3D 0);
+								case 6: ptr_pixels[5] =3D ((w & 0x04) !=3D 0);
+								case 5: ptr_pixels[4] =3D ((w & 0x08) !=3D 0);
+								case 4: ptr_pixels[3] =3D ((w & 0x10) !=3D 0);
+								case 3: ptr_pixels[2] =3D ((w & 0x20) !=3D 0);
+								case 2: ptr_pixels[1] =3D ((w & 0x40) !=3D 0);
+								case 1: ptr_pixels[0] =3D ((w & 0x80) !=3D 0);
+							}
+
+							ptr_pixels +=3D (data.Width & 7);
+						}
+						break;
+					case Format4bppIndexed:
+						for (y =3D 0; y < data.Height; y++) {
+							v =3D ((unsigned char *)data.Scan0) + y * data.Stride;
+							for (x =3D 0; x + 1 < data.Width; x +=3D 2) {
+								w =3D *v;
+
+								*(ptr_pixels++) =3D ((w >> 4) & 0xF);
+								*(ptr_pixels++) =3D ( w       & 0xF);
+
+								v++;
+							}
+
+							if ((data.Width & 1) !=3D 0) {
+								*(ptr_pixels++) =3D ((*v >> 4) & 0xF);
+							}
+						}
+						break;
+					case Format8bppIndexed:
+						for (y =3D 0; y < data.Height; y++) {
+							memcpy(pixels + y * data.Width,
+							       ((unsigned char *)data.Scan0) + y * data.Stride,
+							       data.Width);
+						}
+						break;
+				}
+
+				ptr_pixels =3D pixels;
+			}
+			else {
+				cmap_size =3D 256;
+				cmap  =3D MakeMapObject (cmap_size, 0);

-			for (y =3D 0; y < data.Height; y++) {
-				v =3D ((unsigned char *)data.Scan0) + y * data.Stride;
-				for (x =3D 0; x < data.Width; x++) {
-					v +=3D 4;
-					color =3D (v [0]) | (v [1] << 8) | (v [2] << 16) | (v [3] << 24);
-
+				ptr_red  =3D red =3D GdipAlloc (sizeAlloc);
+				ptr_green =3D green =3D GdipAlloc (sizeAlloc);
+				ptr_blue =3D blue =3D GdipAlloc (sizeAlloc);
+				ptr_pixels =3D pixels =3D GdipAlloc (sizeAlloc);
+
+
+				for (y =3D 0; y < data.Height; y++) {
+					v =3D ((unsigned char *)data.Scan0) + y * data.Stride;
+					for (x =3D 0; x < data.Width; x++) {
 #ifdef WORDS_BIGENDIAN
-					*ptr_red++ =3D (color & 0x0000ff00) >> 8;
-					*ptr_green++ =3D (color & 0x00ff0000) >> 16;
-					*ptr_blue++ =3D  (color & 0xff000000) >> 24;
+						*ptr_red++ =3D   v[1];
+						*ptr_green++ =3D v[2];
+						*ptr_blue++ =3D  v[3];
 #else
-					*ptr_red++ =3D (color & 0x00ff0000) >> 16;
-					*ptr_green++ =3D (color & 0x0000ff00) >> 8;
-					*ptr_blue++ =3D  (color & 0x000000ff);
+						*ptr_red++ =3D   v[2];
+						*ptr_green++ =3D v[1];
+						*ptr_blue++ =3D  v[0];
 #endif
+
+						v +=3D 4;
+					}
 				}
-			}

-			if (QuantizeBuffer (data.Width, data.Height, &cmap_size, red,
-					green, blue, pixels, cmap->Colors) =3D=3D GIF_ERROR)
-				error =3D TRUE;
+				if (QuantizeBuffer (data.Width, data.Height, &cmap_size, red,
+						green, blue, pixels, cmap->Colors) =3D=3D GIF_ERROR)
+					error =3D TRUE;
+			}

 			cmap->BitsPerPixel =3D BitSize (cmap_size);
 			cmap->ColorCount =3D 1 << cmap->BitsPerPixel;
@@ -478,10 +570,13 @@
 			}

 			FreeMapObject (cmap);
-			GdipFree (red);
-			GdipFree (green);
-			GdipFree (blue);
-			GdipFree (pixels);
+			if (red !=3D NULL)
+				GdipFree (red);
+			if (green !=3D NULL)
+				GdipFree (green);
+			if (blue !=3D NULL)
+				GdipFree (blue);
+			GdipFree (pixels);
 		}
 	}

Index: src/ChangeLog
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/ChangeLog	(revision 41706)
+++ src/ChangeLog	(working copy)
@@ -1,3 +1,86 @@
+2005-03-02  Jonathan Gilbert  <................>
+
+	* bitmap.c: Added indexed pixel formats to
+	  gdip_is_a_supported_pixelformat().
+	* bitmap.c: Added gdip_is_an_indexed_pixelformat(). Added its
+	  prototype to gdip.h; not sure if this is the correct place.
+	* bitmap.c: Added support for PixelFormat.Format4bppIndexed to
+	  GdipCreateBitmapFromScan0 (maps to CAIRO_FORMAT_A8, like
+	  PixelFormat.Format8bppIndexed). Palettes will be created
+	  as needed. Bitmaps with a 4bpp indexed pixel format will be
+	  given 256-entry ColorPalette structures, as the cairo_format
+	  indicates 8-bit data.
+	* bitmap.c: GdipCreateBitmapFromScan0 now computes stride for
+	  indexed pixel formats differently, and does not convert
+	  indexed pixel formats to 32-bit RGB. It also makes images with
+	  32-bit pixel formats initially black instead of initially
+	  transparent and fills the palette with the default values for
+	  1-, 4- and 8-bpp indexed images.
+	* bitmap.c: Added support for indexed images to
+	  gdip_bitmap_clone_data_rect().
+	* bitmap.c: Rewrote GdipBitmapLockBits () to be maintainable
+	  while supporting indexed pixel formats. Added
+	  gdip_can_window_without_copy (), gdip_is_a_32bit_pixelformat (),
+	  gdip_make_alpha_opaque () and gdip_is_an_alpha_pixelformat ().
+	* bitmap.c: Moved gdip_from_ARGB_to_RGB () and
+	  gdip_from_RGB_to_ARGB () above gdip_bitmap_change_rect_pixel_format (),
+	  so that gdip_bitmap_change_rect_pixel_format () can call them.
+	* bitmap.c: Added struct StreamingState and methods
+	  gdip_init_pixel_stream (), gdip_pixel_stream_has_next (),
+	  gdip_pixel_stream_get_next () and gdip_pixel_stream_set_next () to
+	  work with Bitmaps of various formats in an abstract way.
+	  gdip_pixel_stream_get_next () returns and
+	  gdip_pixel_stream_set_next () accepts 32-bit ARGB values for 15,
+	  16, 24, 32, 48 and 64 bit formats and palette indices for 1, 4 and
+	  8 bit formats. gdip_pixel_stream_get_next () and
+	  gdip_pixel_stream_set_next () cannot be mixed; call either one or
+	  the other on a given stream, but never both.
+	* bitmap.c: Rewrote gdip_bitmap_change_rect_pixel_format to use
+	  pixel streams, which adds support for indexed pixel formats and
+	  increases maintainability.
+	* bitmap.c: Added check to GdipBitmapSetPixel ensuring that
+	  the bitmap is not indexed (despite what MSDN says, in
+	  practice Microsoft's implementation rejects SetPixel on
+	  indexed Bitmaps).
+	* bitmap.c: Added gdip_convert_indexed_to_rgb (), which will
+	  be used by the functions implementing DrawImage, since
+	  gdip_bitmap_ensure_surface () is not compatible with indexed
+	  image data.
+	* image.c: Added support for indexed pixel formats in
+	  GdipDrawImageRect and GdipDrawImageRectRect. The support is
+	  for the image being drawn to be indexed, not the image
+	  being drawn on. :-)
+	* image.c: Implemented GdipGetImagePalette (),
+	  GdipSetImagePalette () and GdipGetImagePaletteSize ().
+	* bmpcodec.c: Corrected gdip_bitmap_fill_info_header ()'s
+	  interpretation of pixel bit widths.
+	* bmpcodec.c: Added include directive for gdipImage.h, for
+	  utility function gdip_get_pixel_format_bpp ().
+	* bmpcodec.c: Updated gdip_bitmap_save_bmp () to save the
+	  palette for indexed bitmaps.
+	* bmpcodec.c: Updated gdip_read_bmp_image_from_file_stream ()
+	  to maintain 1, 4 and 8 bpp indexed data instead of converting
+	  it on-the-fly to 32 bpp RGB data.
+	* bmpcodec.c: Updated gdip_get_pixelformat () to translate
+	  a bit width of 1 into Format1bppIndexed.
+	* gifcodec.c: Updated gdip_save_gif_image () to support saving
+	  indexed images. Also, an off-by-one error in the 32-bit ARGB
+	  side of the encoder was corrected (the image was translated
+	  left one pixel).
+	* jpegcodec.c: Updated gdip_save_jpeg_image_internal () to
+	  reject 8bpp indexed images that are not grayscale (the
+	  previous behaviour was to assume all 8bpp indexed images
+	  are grayscale).
+	* tiffcodec.c: Updated gdip_save_tiff_image () to reject
+	  indexed images as NotImplemented, for now at least.
+	* pngcodec.c: Updated gdip_load_png_image_from_file_or_stream ()
+	  to handle 1-, 4- and 8-bit PNG files separately, without
+	  upsampling the data to 32-bit RBG.
+	* gdip.h: Fixed the set_pixel_bgra () macro; a lack of
+	  parentheses and no cast down to 'unsigned char' was making
+	  expressions like set_pixel_bgra (&array[i], ...) fail to
+	  compile.
+
 2005-02-24  Jordi Mas i Hernandez  <jordi@ximian.com>

 	* region.c: Fixes IsVisible methods
Index: src/bitmap.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/bitmap.c	(revision 41706)
+++ src/bitmap.c	(working copy)
@@ -43,6 +43,9 @@
 {
 	switch (fmt) {

+	case Format1bppIndexed:
+	case Format4bppIndexed:
+	case Format8bppIndexed:
  	case Format24bppRgb:
 	case Format32bppArgb:
 	case Format32bppPArgb:
@@ -53,6 +56,15 @@
 	}
 }

+/*
+	Returns TRUE if the Bitmap contains indexed (palettized) data.
+*/
+BOOL
+gdip_is_an_indexed_pixelformat (PixelFormat fmt)
+{
+	return ((fmt & PixelFormatIndexed) !=3D 0);
+}
+
 void
 gdip_bitmap_init (GpBitmap *bitmap)
 {
@@ -131,7 +143,38 @@
 	}
 }

+/* The default indexed palettes. This code was generated by a tiny C# prog=
ram.
+ */

+static const unsigned int default_Format1bppIndexed_palette[2] =3D
+  {
+    0x000000, 0xFFFFFF
+  };
+static const unsigned int default_Format4bppIndexed_palette[16] =3D
+  {
+    0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, =
0x808080, 0xC0C0C0, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00F=
FFF, 0xFFFFFF
+  };
+static const unsigned int default_Format8bppIndexed_palette[256] =3D
+  {
+    0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, =
0x808080, 0xC0C0C0, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00F=
FFF, 0xFFFFFF,
+    0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, =
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000=
000, 0x000000,
+    0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, =
0x000000, 0x000000, 0x000033, 0x000066, 0x000099, 0x0000CC, 0x0000FF, 0x003=
300, 0x003333,
+    0x003366, 0x003399, 0x0033CC, 0x0033FF, 0x006600, 0x006633, 0x006666, =
0x006699, 0x0066CC, 0x0066FF, 0x009900, 0x009933, 0x009966, 0x009999, 0x009=
9CC, 0x0099FF,
+    0x00CC00, 0x00CC33, 0x00CC66, 0x00CC99, 0x00CCCC, 0x00CCFF, 0x00FF00, =
0x00FF33, 0x00FF66, 0x00FF99, 0x00FFCC, 0x00FFFF, 0x330000, 0x330033, 0x330=
066, 0x330099,
+    0x3300CC, 0x3300FF, 0x333300, 0x333333, 0x333366, 0x333399, 0x3333CC, =
0x3333FF, 0x336600, 0x336633, 0x336666, 0x336699, 0x3366CC, 0x3366FF, 0x339=
900, 0x339933,
+    0x339966, 0x339999, 0x3399CC, 0x3399FF, 0x33CC00, 0x33CC33, 0x33CC66, =
0x33CC99, 0x33CCCC, 0x33CCFF, 0x33FF00, 0x33FF33, 0x33FF66, 0x33FF99, 0x33F=
FCC, 0x33FFFF,
+    0x660000, 0x660033, 0x660066, 0x660099, 0x6600CC, 0x6600FF, 0x663300, =
0x663333, 0x663366, 0x663399, 0x6633CC, 0x6633FF, 0x666600, 0x666633, 0x666=
666, 0x666699,
+    0x6666CC, 0x6666FF, 0x669900, 0x669933, 0x669966, 0x669999, 0x6699CC, =
0x6699FF, 0x66CC00, 0x66CC33, 0x66CC66, 0x66CC99, 0x66CCCC, 0x66CCFF, 0x66F=
F00, 0x66FF33,
+    0x66FF66, 0x66FF99, 0x66FFCC, 0x66FFFF, 0x990000, 0x990033, 0x990066, =
0x990099, 0x9900CC, 0x9900FF, 0x993300, 0x993333, 0x993366, 0x993399, 0x993=
3CC, 0x9933FF,
+    0x996600, 0x996633, 0x996666, 0x996699, 0x9966CC, 0x9966FF, 0x999900, =
0x999933, 0x999966, 0x999999, 0x9999CC, 0x9999FF, 0x99CC00, 0x99CC33, 0x99C=
C66, 0x99CC99,
+    0x99CCCC, 0x99CCFF, 0x99FF00, 0x99FF33, 0x99FF66, 0x99FF99, 0x99FFCC, =
0x99FFFF, 0xCC0000, 0xCC0033, 0xCC0066, 0xCC0099, 0xCC00CC, 0xCC00FF, 0xCC3=
300, 0xCC3333,
+    0xCC3366, 0xCC3399, 0xCC33CC, 0xCC33FF, 0xCC6600, 0xCC6633, 0xCC6666, =
0xCC6699, 0xCC66CC, 0xCC66FF, 0xCC9900, 0xCC9933, 0xCC9966, 0xCC9999, 0xCC9=
9CC, 0xCC99FF,
+    0xCCCC00, 0xCCCC33, 0xCCCC66, 0xCCCC99, 0xCCCCCC, 0xCCCCFF, 0xCCFF00, =
0xCCFF33, 0xCCFF66, 0xCCFF99, 0xCCFFCC, 0xCCFFFF, 0xFF0000, 0xFF0033, 0xFF0=
066, 0xFF0099,
+    0xFF00CC, 0xFF00FF, 0xFF3300, 0xFF3333, 0xFF3366, 0xFF3399, 0xFF33CC, =
0xFF33FF, 0xFF6600, 0xFF6633, 0xFF6666, 0xFF6699, 0xFF66CC, 0xFF66FF, 0xFF9=
900, 0xFF9933,
+    0xFF9966, 0xFF9999, 0xFF99CC, 0xFF99FF, 0xFFCC00, 0xFFCC33, 0xFFCC66, =
0xFFCC99, 0xFFCCCC, 0xFFCCFF, 0xFFFF00, 0xFFFF33, 0xFFFF66, 0xFFFF99, 0xFFF=
FCC, 0xFFFFFF
+  };
+
+
 GpStatus
 GdipCreateBitmapFromScan0 (int width, int height, int stride, int format, =
void *scan0, GpBitmap **bitmap)
 {
@@ -149,6 +192,7 @@
 		cairo_format =3D CAIRO_FORMAT_ARGB32;
 		break;
 	case Format8bppIndexed:
+	case Format4bppIndexed:
 		cairo_format =3D CAIRO_FORMAT_A8;
 		break;
 	case Format1bppIndexed:
@@ -169,10 +213,19 @@
 	result->cairo_format =3D cairo_format;

 	if (stride =3D=3D 0) {
-		int bpp  =3D gdip_get_pixel_format_components (format);
-		bpp =3D bpp * gdip_get_pixel_format_depth (format);
-		stride =3D (bpp * width) / 8;
-		stride +=3D (stride + (sizeof(pixman_bits_t)-1));
+		if (gdip_is_an_indexed_pixelformat (format)) {
+			int bpp =3D gdip_get_pixel_format_depth(format);
+			int bits_per_row =3D bpp * width;
+			stride =3D (bits_per_row + 7) / 8;
+		}
+		else {
+			int bpp  =3D gdip_get_pixel_format_components (format);
+			bpp =3D bpp * gdip_get_pixel_format_depth (format);
+			stride =3D (bpp * width) / 8;
+		}
+
+		/* make sure the stride aligns the next row to a pixman_bits_t boundary =
*/
+		stride +=3D (sizeof(pixman_bits_t)-1);
 		stride &=3D ~(sizeof(pixman_bits_t)-1);
 	}

@@ -180,8 +233,21 @@
 		scan0 =3D GdipAlloc (stride * height);
 		if (scan0 =3D=3D NULL)
 			return OutOfMemory;
-
-		memset (scan0, 0, stride * height);
+
+		if (gdip_get_pixel_format_bpp (format) < 16) {
+			memset (scan0, 0, stride * height);
+		}
+		else {
+			/* The image should be initially black, not initially transparent. */
+			int x, y;
+
+			for (y=3D0; y < height; y++) {
+				ARGB *scan =3D (ARGB *)((char *)scan0 + y * stride);
+				for (x=3D0; x * 4 < stride; x++) {
+					scan[x] =3D 0xFF000000;
+				}
+			}
+		}
 		own_scan0 =3D TRUE;
 	}

@@ -201,6 +267,40 @@
 			result->image.frameDimensionList[0].frames =3D &(((GpBitmap *) result)-=
>data);
 		}

+	/* Make sure indexed images have a palette */
+	if (gdip_is_an_indexed_pixelformat (format)) {
+		int palette_entries =3D 1 << gdip_get_pixel_format_depth(format);
+		int header_size =3D sizeof(ColorPalette) - sizeof(ARGB);
+		int bytes_needed =3D header_size + palette_entries * sizeof(ARGB);
+
+		int i;
+
+		result->image.palette =3D malloc (bytes_needed);
+
+		if (result->image.palette =3D=3D NULL)
+			return OutOfMemory;
+
+		result->image.palette->Flags =3D 0;
+		result->image.palette->Count =3D palette_entries;
+
+		const unsigned int *default_palette;
+
+		switch (format)
+		{
+			case Format1bppIndexed: default_palette =3D default_Format1bppIndexed_p=
alette; break;
+			case Format4bppIndexed: default_palette =3D default_Format4bppIndexed_p=
alette; break;
+			case Format8bppIndexed: default_palette =3D default_Format8bppIndexed_p=
alette; break;
+		}
+
+		for (i=3D0; i < palette_entries; i++) {
+			set_pixel_bgra(result->image.palette, i * 4,
+				0xFF & (default_palette[i] >> 16),
+				0xFF & (default_palette[i] >>  8),
+				0xFF &  default_palette[i]       ,
+				0xFF /* alpha */);
+		}
+	}
+
 	*bitmap =3D result;

 	return Ok;
@@ -299,7 +399,7 @@

 	result->cairo_format =3D original->cairo_format;
 	memcpy (&result->data, &bd, sizeof (GdipBitmapData));
-	result->image.pixFormat =3D format;	/* this is only used by image codecs =
*/
+	result->image.pixFormat =3D format;
 	result->image.format =3D original->image.format;
 	result->image.height =3D result->data.Height;
 	result->image.width =3D result->data.Width;
@@ -329,8 +429,8 @@

 /*
  * Copy srcRect region in srcData to destRect region in destData.  No conv=
ersion is done.  Assumes
- * BitmapData is straight from a GpBitmap, i.e. its format is always Pixel=
Format32bppArgb.  src and
- * dest rects must be the same width/height.
+ * BitmapData is straight from a GpBitmap.  src and dest rects must be the=
 same width/height and
+ * bits must be of the same PixelFormat.
  */

 GpStatus
@@ -371,10 +471,75 @@
 		destData->Reserved =3D GBD_OWN_SCAN0;
 	}

-	gdip_copy_strides (destData->Scan0, destData->Stride,
-		srcData->Scan0 + (srcData->Stride * srcRect->Y) + (gdip_get_pixel_format=
_components (srcData->PixelFormat)
-		* srcRect->X), srcData->Stride,   destRect->Width * dest_components,  de=
stRect->Height);
+	if (!gdip_is_an_indexed_pixelformat (srcData->PixelFormat)) {
+		gdip_copy_strides (destData->Scan0, destData->Stride,
+			srcData->Scan0 + (srcData->Stride * srcRect->Y) + (gdip_get_pixel_forma=
t_components (srcData->PixelFormat)
+			* srcRect->X), srcData->Stride,   destRect->Width * dest_components,  d=
estRect->Height);
+	}
+	else {
+		int src_depth =3D gdip_get_pixel_format_depth (srcData->PixelFormat);

+		/* first, check if the bits are aligned onto a byte boundary */
+		int src_first_x_bit_index =3D srcRect->X * src_depth;
+		int width_bits =3D destRect->Width * src_depth;
+
+		int src_first_x_bit_offset_into_byte =3D src_first_x_bit_index & 7;
+		int width_bit_offset_into_byte =3D width_bits & 7;
+
+		if (src_first_x_bit_offset_into_byte =3D=3D 0) {
+			/* the fast path: no mid-byte bit mangling required :-)
+			 * this will always be the case for 8-bit images.
+			 * basically, the source bits are aligned to the destination
+			 * bytes, and it doesn't matter if the width isn't a multiple
+			 * of 8 bits, because the remainder is guaranteed to be
+			 * allocated by the stride, and will be ignored because the
+			 * width will indicate fewer pixels than actually end up being
+			 * copied.
+			 */
+			gdip_copy_strides (
+				destData->Scan0, destData->Stride,
+				srcData->Scan0 + (src_first_x_bit_index / 8) + (srcData->Stride * srcR=
ect->Y),
+				srcData->Stride, width_bits / 8, destRect->Height);
+		}
+		else {
+			/* the not-so-fast path: no bits are aligned, so the entire image requi=
res bit juggling. */
+
+			unsigned char *src_scan0 =3D srcData->Scan0;
+			unsigned char *dest_scan0 =3D destData->Scan0;
+
+			int left_shift =3D src_first_x_bit_offset_into_byte;
+
+			int left_edge_src_mask =3D 255 >> src_first_x_bit_offset_into_byte;
+
+			int num_whole_dest_bytes =3D (width_bits / 8);
+
+			int x, y;
+
+			/* move the src_scan0 up to the first byte with pixel data involved in =
the copy */
+			src_scan0 +=3D srcRect->Y * srcData->Stride;
+			src_scan0 +=3D (src_first_x_bit_offset_into_byte / 8);
+
+			for (y=3D0; y < destRect->Height; y++) {
+				unsigned char *src_scan =3D src_scan0 + y * srcData->Stride;
+				unsigned char *dest_scan =3D dest_scan0 + y * destData->Stride;
+
+				unsigned short buffer;
+
+				/* jump-start the packing function. it avoids double-sampling the sour=
ce bits by
+				 * using buffer as a shift register; bits 8-15 are the current packed =
dest pixel,
+				 * and some of bits 0-7 are not used, to permit alignment of the pixel=
 data.
+				 */
+				buffer =3D src_scan[0] << left_shift;
+
+				for (x=3D1; x < destRect->Width; x++) {
+					buffer <<=3D 8;
+					buffer |=3D src_scan[x] << left_shift;
+					dest_scan[0] =3D (buffer >> 8);
+				}
+			}
+		}
+	}
+
 	return Ok;
 }

@@ -404,7 +569,7 @@
 	if (!(src & PixelFormatGDI))
 		return 0;

-	if (src & PixelFormatIndexed)
+	if ((src & PixelFormatIndexed)      )//     || (dest & PixelFormatIndexed=
))
 		return 0;

 	/* These are the RGB formats */
@@ -421,162 +586,6 @@
 	return 0;
 }

-/**
- * srcData - input data
- * srcRect - rectangle of input data to place in destData
- * destData - where to place output; only the PixelFormat field is needed,
- *            which specifies the output type.
- * destRect - destination rectangle in output.
- */
-
-GpStatus
-gdip_bitmap_change_rect_pixel_format (GdipBitmapData *srcData, Rect *srcRe=
ct, GdipBitmapData *destData, Rect *destRect)
-{
-	gpointer outBuffer =3D NULL;
-	gint outStride =3D 0;
-	PixelFormat srcFormat, destFormat;
-
-	g_return_val_if_fail (srcData !=3D NULL, InvalidParameter);
-	g_return_val_if_fail (srcRect !=3D NULL, InvalidParameter);
-	g_return_val_if_fail (destData !=3D NULL, InvalidParameter);
-	g_return_val_if_fail (destRect !=3D NULL, InvalidParameter);
-
-	g_return_val_if_fail (srcRect->Width <=3D destRect->Width, InvalidParamet=
er);
-	g_return_val_if_fail (srcRect->Height <=3D destRect->Height, InvalidParam=
eter);
-
-	srcFormat =3D srcData->PixelFormat;
-	destFormat =3D destData->PixelFormat;
-
-	if (!gdip_is_pixel_format_conversion_valid (srcFormat, destFormat))
-		return InvalidParameter;
-
-	/* If the pixel formats are the same, our job is easy. */
-	if (srcFormat =3D=3D destFormat) {
-		int bitsPerPixel =3D gdip_get_pixel_format_bpp (srcFormat);
-		int bytesPerPixel =3D bitsPerPixel / 8;
-
-		g_return_val_if_fail (bitsPerPixel =3D=3D 16 || bitsPerPixel =3D=3D 24 |=
| bitsPerPixel =3D=3D 32, InvalidParameter);
-
-		if (destData->Scan0 =3D=3D NULL) {
-			outStride =3D bytesPerPixel * destRect->Width;
-			while (outStride % sizeof(pixman_bits_t))
-				outStride++;		/* dword-align each row */
-
-			/* Allocate the output buffer */
-			outBuffer =3D GdipAlloc (outStride * destRect->Height);
-			if (outBuffer =3D=3D NULL)
-				return OutOfMemory;
-
-			destData->Width =3D destRect->Width;
-			destData->Height =3D destRect->Height;
-			destData->Stride =3D outStride;
-			destData->Scan0 =3D outBuffer;
-			destData->Reserved =3D GBD_OWN_SCAN0;
-		} else {
-			/* Don't touch the output data, just get the portion of the rect
-			 * that we're writing to
-			 */
-			outStride =3D destData->Stride;
-			outBuffer =3D destData->Scan0 + (destRect->Y * destData->Stride) + (des=
tRect->X * bytesPerPixel);
-		}
-
-		/* Then let gdip_copy_strides do our work for us */
-		gdip_copy_strides
-			(outBuffer, outStride,
-			 srcData->Scan0 + (srcRect->Y * srcData->Stride) + (srcRect->X * bytesP=
erPixel), srcData->Stride,
-			 bytesPerPixel * destRect->Width,
-			 destRect->Height);
-	} else {
-		/* We need to convert pixel formats */
-		gboolean convert_24_to_32 =3D 0;
-		gboolean convert_32_to_24 =3D 0;
-		gboolean add_alpha =3D 0;
-
-		int dest_skip =3D 0;
-		int src_skip =3D 0;
-
-		int srcBitsPerPixel =3D gdip_get_pixel_format_bpp (srcFormat);
-		int srcBytesPerPixel =3D srcBitsPerPixel / 8;
-		int destBitsPerPixel =3D gdip_get_pixel_format_bpp  (destFormat);
-		int destBytesPerPixel =3D destBitsPerPixel / 8;
-
-		if (destData->Scan0 =3D=3D NULL) {
-			outStride =3D destBytesPerPixel * destRect->Width;
-			while (outStride % sizeof(pixman_bits_t))
-				outStride++;		/* dword-align each row */
-
-			/* Allocate the output buffer */
-			outBuffer =3D GdipAlloc (outStride * destRect->Height);
-			if (outBuffer =3D=3D NULL)
-				return OutOfMemory;
-
-			destData->Width =3D destRect->Width;
-			destData->Height =3D destRect->Height;
-			destData->Stride =3D outStride;
-			destData->Scan0 =3D outBuffer;
-			destData->Reserved =3D GBD_OWN_SCAN0;
-		} else {
-			/* Don't touch the output data, just get the portion of the rect
-			 * that we're writing to
-			 */
-			outStride =3D destData->Stride;
-			outBuffer =3D destData->Scan0 + (destRect->Y * destData->Stride) + (des=
tRect->X * destBytesPerPixel);
-		}
-
-		/* First, figure out the conversion type */
-		if (gdip_get_pixel_format_bpp (srcFormat) =3D=3D 32 && gdip_get_pixel_fo=
rmat_bpp (destFormat) =3D=3D 24)
-			convert_32_to_24 =3D 1;
-		else if (gdip_get_pixel_format_bpp (srcFormat) =3D=3D 24 && gdip_get_pix=
el_format_bpp (destFormat) =3D=3D 32)
-			convert_24_to_32 =3D 1;
-
-		if (!(srcFormat & PixelFormatAlpha) && (destFormat & PixelFormatAlpha))
-			add_alpha =3D 1;
-
-		if (convert_32_to_24) src_skip =3D 1;
-		if (convert_24_to_32 && !add_alpha) dest_skip =3D 1;
-
-		if (!convert_32_to_24 && !convert_24_to_32) {
-			/* Okay, well.  The formats aren't identical, but they're the same size=
 --
-			 * i.e. we might be going 32bppRgb <-> 32bppArgb.  We can always copy s=
trides,
-			 * and then go through and add alpha...
-			 */
-			gdip_copy_strides
-				(outBuffer,
-				 outStride,
-				 srcData->Scan0 + (srcRect->Y * srcData->Stride) + (srcRect->X * srcBy=
tesPerPixel),
-				 srcData->Stride,
-				 destBytesPerPixel * destRect->Width,
-				 destRect->Height);
-			if (add_alpha) {
-				unsigned int *ptr =3D (unsigned int *) outBuffer;
-				int i;
-				for (i =3D 0; i < destRect->Height * (outStride / sizeof(unsigned int)=
); i++)
-					*ptr++ |=3D 0xff000000; /* XXX TODO: check what value windows sets al=
pha to */
-			}
-		} else {
-			/* We need to do 24->32 or 32->24 conversion */
-			unsigned char *srcPtr, *destPtr;
-			int i, j;
-
-			for (j =3D 0; j < destRect->Height; j++) {
-				srcPtr =3D srcData->Scan0 + ((srcRect->Y + j) * srcData->Stride) + (sr=
cRect->X * srcBytesPerPixel);
-				destPtr =3D outBuffer + (j * outStride);
-				for (i =3D 0; i < destRect->Width; i++) {
-					*destPtr++ =3D *srcPtr++;
-					*destPtr++ =3D *srcPtr++;
-					*destPtr++ =3D *srcPtr++;
-					srcPtr +=3D src_skip;
-					if (add_alpha) *destPtr++ =3D 0xff;
-					else destPtr +=3D dest_skip;
-				}
-			}
-		}
-	}
-
-	return Ok;
-}
-
-
 /* Format24bppRgb is internally stored by Cairo as a four bytes. Convert i=
t to 3-byte (RGB) */
 int
 gdip_from_ARGB_to_RGB (BYTE *src, int width, int height, int stride, BYTE =
**dest, int* dest_stride)
@@ -610,7 +619,7 @@
 }


-/* Format24bppRgb is internally stored by Cairo as a four bytes. Convert i=
t to 3-byte (RGB) */
+/* Format24bppRgb is internally stored by Cairo as a three bytes. Convert =
it to 4-byte (ARGB) */
 int
 gdip_from_RGB_to_ARGB (BYTE *src, int width, int height, int stride, BYTE =
**dest, int* dest_stride)
 {
@@ -643,7 +652,653 @@
 	return Ok;
 }

+typedef struct
+{
+	Rect region;
+	int x, y;               /* the offset of the next byte that will be loade=
d, once the buffer is depleted */
+	unsigned short buffer;
+	int p;                  /* index of pixel within 'buffer' that was return=
ed by the last call to gdip_pixel_stream_get_next () */
+	int one_pixel_mask, one_pixel_shift, pixels_per_byte;

+	BitmapData *data;
+	unsigned char *scan;
+} StreamingState;
+
+GpStatus
+gdip_init_pixel_stream (StreamingState *state, BitmapData *data, int x, in=
t y, int w, int h)
+{
+	if ((state =3D=3D NULL) || (data =3D=3D NULL) || (data->Scan0 =3D=3D NULL=
))
+		return InvalidParameter;
+
+	/* Ensure that the rectangle requested is sensible. */
+	if ((x < 0) || (y < 0) || (x >=3D data->Width) || (y >=3D data->Height))
+		return InvalidParameter;
+
+	if ((x + w > data->Width) || (y + h > data->Height))
+		return InvalidParameter;
+
+	/* Initialize the StreamingState structure to point at the first pixel. */
+	state->region.X =3D x;
+	state->region.Y =3D y;
+	state->region.Width =3D w;
+	state->region.Height =3D h;
+
+	state->x =3D x;
+	state->y =3D y;
+
+	state->p =3D -1; /* ensure that the buffer will be preloaded on the first=
 call, for indexed formats */
+
+	switch (data->PixelFormat)
+	{
+		case Format1bppIndexed: state->one_pixel_mask =3D 0x01; state->one_pixel=
_shift =3D 1; state->pixels_per_byte =3D 8; break;
+		case Format4bppIndexed: state->one_pixel_mask =3D 0x0F; state->one_pixel=
_shift =3D 4; state->pixels_per_byte =3D 2; break;
+		case Format8bppIndexed: state->one_pixel_mask =3D 0xFF; state->one_pixel=
_shift =3D 8; state->pixels_per_byte =3D 1; break;
+		default:
+			state->pixels_per_byte =3D 0; /* indicate full RGB processing */
+			break;
+	}
+
+	state->data =3D data;
+
+	/* The following computation will compute the byte pointer that _contains=
_ the first
+	 * pixel; this doesn't necessarily mean that the pixel is aligned to the =
byte. This
+	 * will be handled in gdip_pixel_stream_get_next () each time it starts a=
 new row.
+	 */
+	state->scan =3D (unsigned char *)(data->Scan0)
+	            + y * data->Stride
+	            + x * gdip_get_pixel_format_bpp (data->PixelFormat) / 8;
+
+	return Ok;
+}
+
+BOOL
+gdip_pixel_stream_has_next (StreamingState *state)
+{
+	if (state !=3D NULL)
+		return (state->p >=3D 0)
+		    || ((state->y < (state->region.Y + state->region.Height))
+		     && (state->x < (state->region.X + state->region.Width)));
+	else
+		return FALSE;
+}
+
+unsigned int /* <-- can be an ARGB or a palette index */
+gdip_pixel_stream_get_next (StreamingState *state)
+{
+	unsigned int ret;
+
+	if (state =3D=3D NULL)
+		return 0xFFFF00FF; /* bright pink; hopefully this will get somebody's at=
tention :-) */
+
+	/* Note: This function does not check whether the end of the region has b=
een hit. This function can
+	 * potentially overrun memory buffers! gdip_pixel_stream_has_next () must=
 be used in conjunction
+	 * with this function.
+	 */
+
+	if (state->pixels_per_byte =3D=3D 1) {
+		/* A fast path for 8-bit indexed data: pixels are byte-aligned, so no sp=
ecial unpacking is required. */
+		ret =3D *state->scan;
+
+		state->scan++;
+		state->x++;
+
+		if (state->x >=3D (state->region.X + state->region.Width)) {
+			state->x =3D state->region.X;
+			state->y++;
+
+			state->scan =3D (unsigned char *)(state->data->Scan0)
+			            + state->y * state->data->Stride
+			            + state->x;
+		}
+	}
+	else if (state->pixels_per_byte > 0) {
+		/* We have an indexed format (the RGB formats can't fit a whole pixel in=
to a single byte). */
+		if (state->p < 0) {
+			state->buffer =3D *state->scan;
+			state->scan++;
+			state->p =3D 0;
+
+			if (state->x =3D=3D state->region.X) {
+				/* First pixel of the row; check whether it is aligned to the byte or =
not. */
+				int index_into_byte =3D state->x & (state->pixels_per_byte - 1);
+
+				if (index_into_byte !=3D 0) {
+					/* Not aligned; need to advance the buffer to the
+					 * first pixel in the stream region.
+					 */
+					state->buffer <<=3D (index_into_byte * state->one_pixel_shift);
+					state->p =3D index_into_byte;
+				}
+			}
+		}
+
+		state->buffer <<=3D state->one_pixel_shift;
+
+		ret =3D (state->buffer >> 8) & state->one_pixel_mask;
+
+		state->x++;
+		state->p++;
+
+		/* Have we hit the end of the buffer? */
+		if (state->p >=3D state->pixels_per_byte)
+			state->p =3D -1;
+
+		if (state->x >=3D (state->region.X + state->region.Width)) {
+			state->x =3D state->region.X;
+			state->y++;
+
+			state->scan =3D (unsigned char *)(state->data->Scan0)
+			            + state->y * state->data->Stride
+			            + state->x * gdip_get_pixel_format_bpp (state->data->PixelF=
ormat) / 8;
+
+			state->p =3D -1;
+		}
+	}
+	else {
+		/* We have an RGB format. In the current implementation, these are alway=
s stored as
+		 * CAIRO_FORMAT_ARGB. This makes this section very easy to implement. If=
 native
+		 * support for 15- and 16-bit pixel formats needs to be added in the fut=
ure, though,
+		 * then this is where it needs to be done.
+		 */
+		ret =3D *(unsigned int *)state->scan;
+
+		/* Special case: 24-bit data needs to have the cairo format alpha compon=
ent forced
+		 * to 0xFF, or many operations will do nothing (or do strange things if =
the alpha
+		 * channel contains garbage).
+		 */
+		if (state->data->PixelFormat =3D=3D Format24bppRgb)
+			ret |=3D 0xFF000000;
+
+		state->scan +=3D 4;
+		state->x++;
+
+		if (state->x >=3D (state->region.X + state->region.Width)) {
+			state->x =3D state->region.X;
+			state->y++;
+
+			state->scan =3D (unsigned char *)(state->data->Scan0)
+			            + state->y * state->data->Stride
+			            + state->x * 4;
+		}
+	}
+
+	return ret;
+}
+
+void
+gdip_pixel_stream_set_next (StreamingState *state, unsigned int pixel_valu=
e)
+{
+	if (state =3D=3D NULL)
+		return;
+
+	/* Note: This function does not check whether the end of the region has b=
een hit. This function can
+	 * potentially overrun memory buffers! gdip_pixel_stream_has_next () must=
 be used in conjunction
+	 * with this function.
+	 */
+
+	if (state->pixels_per_byte =3D=3D 1) {
+		/* A fast path for 8-bit indexed data: pixels are byte-aligned, so no sp=
ecial packing is required. */
+		*state->scan =3D pixel_value & 0xFF;
+
+		state->scan++;
+		state->x++;
+
+		if (state->x >=3D (state->region.X + state->region.Width)) {
+			state->x =3D state->region.X;
+			state->y++;
+
+			state->scan =3D (unsigned char *)(state->data->Scan0)
+			            + state->y * state->data->Stride
+			            + state->x;
+		}
+	}
+	else if (state->pixels_per_byte > 0) {
+		/* We have an indexed format (the RGB formats can't fit a whole pixel in=
to a single byte). */
+		if (state->p < 0) {
+			state->p =3D 0;
+
+			if (state->x =3D=3D state->region.X) {
+				/* First pixel of the row; check whether it is aligned to the byte or =
not. */
+				int index_into_byte =3D state->x & (state->pixels_per_byte - 1);
+
+				if (index_into_byte =3D=3D 0) {
+					/* It is aligned; all we need to do is clear the buffer. */
+					state->buffer =3D 0;
+				}
+				else {
+					/* It is not aligned; the buffer needs to be pre-loaded with those
+					 * pixels that are to the left of the first pixel to be set.
+					 */
+					state->buffer =3D (*state->scan << (index_into_byte * state->one_pixe=
l_shift));
+					state->p =3D index_into_byte;
+				}
+			}
+		}
+
+		state->buffer <<=3D state->one_pixel_shift;
+		state->buffer |=3D ((pixel_value & state->one_pixel_mask) << 8);
+
+		state->x++;
+		state->p++;
+
+		/* Have we hit the end of the buffer? */
+		if (state->p >=3D state->pixels_per_byte)	{
+			*state->scan =3D (state->buffer >> 8);
+			state->scan++;
+			state->p =3D -1;
+		}
+
+		if (state->x >=3D (state->region.X + state->region.Width)) {
+			if (state->p >=3D 0) {
+				int existing_mask =3D 0;
+
+				while (state->p < state->pixels_per_byte) {
+					existing_mask <<=3D state->one_pixel_shift;
+					existing_mask |=3D state->one_pixel_mask;
+
+					state->buffer <<=3D state->one_pixel_shift;
+					state->p++;
+				}
+
+				*state->scan =3D (*state->scan & existing_mask) | (state->buffer >> 8);
+			}
+
+			state->x =3D state->region.X;
+			state->y++;
+
+			state->scan =3D (unsigned char *)(state->data->Scan0)
+			            + state->y * state->data->Stride
+			            + state->x * gdip_get_pixel_format_bpp (state->data->PixelF=
ormat) / 8;
+
+			state->p =3D -1;
+		}
+	}
+	else {
+		/* We have an RGB format. In the current implementation, these are alway=
s stored as
+		 * CAIRO_FORMAT_ARGB. This makes this section very easy to implement. If=
 native
+		 * support for 15- and 16-bit pixel formats needs to be added in the fut=
ure, though,
+		 * then this is where it needs to be done.
+		 */
+		*(unsigned int *)state->scan =3D pixel_value;
+
+		state->scan +=3D 4;
+		state->x++;
+
+		if (state->x >=3D (state->region.X + state->region.Width)) {
+			state->x =3D state->region.X;
+			state->y++;
+
+			state->scan =3D (unsigned char *)(state->data->Scan0)
+			            + state->y * state->data->Stride
+			            + state->x * 4;
+		}
+	}
+}
+
+/**
+ * srcData - input data
+ * srcRect - rectangle of input data to place in destData
+ * destData - where to place output; only the PixelFormat field is needed,
+ *            which specifies the output type.
+ * destRect - destination rectangle in output.
+ *
+ * assumes that the pixel format conversion has already been validated.
+ */
+
+GpStatus
+gdip_bitmap_change_rect_pixel_format (GdipBitmapData *srcData, Rect *srcRe=
ct, GdipBitmapData *destData, Rect *destRect)
+{
+	PixelFormat srcFormat, destFormat;
+	StreamingState srcStream, destStream;
+	Rect effectiveDestRect;
+
+	GpStatus status;
+
+	g_return_val_if_fail (srcData !=3D NULL, InvalidParameter);
+	g_return_val_if_fail (srcRect !=3D NULL, InvalidParameter);
+	g_return_val_if_fail (destData !=3D NULL, InvalidParameter);
+	g_return_val_if_fail (destRect !=3D NULL, InvalidParameter);
+
+	if ((srcRect->X < 0) || (srcRect->Y < 0) || (srcRect->X >=3D srcData->Wid=
th) || (srcRect->Y >=3D srcData->Height))
+		return InvalidParameter;
+	if ((srcRect->X + srcRect->Width > srcData->Width) || (srcRect->Y + srcRe=
ct->Height > srcData->Height))
+		return InvalidParameter;
+
+	if ((destRect->X < 0) || (destRect->Y < 0))
+		return InvalidParameter;
+
+	g_return_val_if_fail (srcRect->Width <=3D destRect->Width, InvalidParamet=
er);
+	g_return_val_if_fail (srcRect->Height <=3D destRect->Height, InvalidParam=
eter);
+
+	srcFormat =3D srcData->PixelFormat;
+	destFormat =3D destData->PixelFormat;
+
+	if (!gdip_is_pixel_format_conversion_valid (srcFormat, destFormat))
+		return InvalidParameter;
+
+	if (destData->Scan0 =3D=3D NULL) {
+		/* Allocate a buffer on behalf of the caller. */
+		int width =3D destRect->X + destRect->Width;
+		int scans =3D destRect->Y + destRect->Height;
+
+		int row_bits =3D destRect->Width * gdip_get_pixel_format_bpp (destFormat=
);
+		int row_bytes =3D (row_bits + 7) / 8;
+
+		int stride =3D (row_bytes + sizeof(pixman_bits_t) - 1) & ~(sizeof(pixman=
_bits_t) - 1);
+
+		void *dest_scan0 =3D malloc(stride * scans);
+
+		if (dest_scan0 =3D=3D NULL)
+			return OutOfMemory;
+
+		destData->Width =3D destRect->X + destRect->Width;
+		destData->Height =3D destRect->Y + destRect->Height;
+		destData->Stride =3D stride;
+		destData->Scan0 =3D dest_scan0;
+		destData->Reserved =3D GBD_OWN_SCAN0;
+	}
+	else {
+		/* Check that the destRect lies fully within the destData buffer. */
+		if ((destRect->X + destRect->Width > destData->Width) || (destRect->Y + =
destRect->Height > destData->Height))
+			return InvalidParameter;
+	}
+
+	effectiveDestRect =3D *destRect;
+
+	if (effectiveDestRect.Width > srcRect->Width)
+		effectiveDestRect.Width =3D srcRect->Width;
+	if (effectiveDestRect.Height > srcRect->Height)
+		effectiveDestRect.Height =3D srcRect->Height;
+
+	/* Fire up the pixel streams. */
+	status =3D gdip_init_pixel_stream (&srcStream, srcData, srcRect->X, srcRe=
ct->Y, srcRect->Width, srcRect->Height);
+
+	if (status !=3D Ok)
+		return status;
+
+	status =3D gdip_init_pixel_stream (&destStream, destData, effectiveDestRe=
ct.X, effectiveDestRect.Y, effectiveDestRect.Width, effectiveDestRect.Heigh=
t);
+
+	if (status !=3D Ok)
+		return status;
+
+	/* Move the data. */
+	while (gdip_pixel_stream_has_next (&srcStream))
+		gdip_pixel_stream_set_next (&destStream, gdip_pixel_stream_get_next (&sr=
cStream));
+
+	return Ok;
+}
+
+
+#define NEW_LOCKBITS_IMPL
+
+#ifdef NEW_LOCKBITS_IMPL
+BOOL
+gdip_is_a_32bit_pixelformat (int format)
+{
+	switch (format)
+	{
+		case Format32bppRgb:
+		case Format32bppArgb:
+		case Format32bppPArgb: /* all of these use CAIRO_FORMAT_ARGB, which is 4=
 bytes wide */
+			return TRUE;
+		default:
+			return FALSE;
+	}
+}
+
+BOOL
+gdip_is_an_alpha_pixelformat (int format)
+{
+	return ((format & PixelFormatAlpha) !=3D 0);
+}
+
+BOOL
+gdip_can_window_without_copy (BitmapData *data, Rect *rect, int format)
+{
+	int bpp =3D gdip_get_pixel_format_bpp (format);
+
+	if (format !=3D data->PixelFormat) {
+		/* can't possibly reinterpret bits from one indexed pixel
+		 * format as being of another indexed pixel format...
+		 */
+		if (gdip_is_an_indexed_pixelformat (format)
+		 || gdip_is_an_indexed_pixelformat (data->PixelFormat))
+			return FALSE;
+
+		/* ...but we can probably handle 24-bit<->32-bit and
+		 * 32-bit alpha<->32-bit opaque without copying data,
+		 * since these are all stored as CAIRO_FORMAT_ARGB
+		 * internally.
+		 */
+		if (!gdip_is_a_32bit_pixelformat (format)
+		 || !gdip_is_a_32bit_pixelformat (data->PixelFormat))
+			return FALSE;
+	}
+
+	/* okay, so the pixel formats are compatible. now, make sure
+	 * the rectangle lies on byte boundaries; if it doesn't, then
+	 * pixels will have to be shuffled. =3D/
+	 */
+
+	/* 8bpp and above are guaranteed to be byte-aligned */
+	if (bpp >=3D 8)
+		return TRUE;
+	else {
+		int left_bit_offset =3D rect->X * bpp;
+		int width_bit_count =3D rect->Width * bpp;
+
+		/* check whether the values are byte-aligned */
+		return ((left_bit_offset & 7) | (width_bit_count & 7)) =3D=3D 0;
+	}
+}
+
+void
+gdip_make_alpha_opaque (BitmapData *data)
+{
+	unsigned char *scan0 =3D (unsigned char *)data->Scan0;
+	int y, x, o, f;
+
+	/* sanity check; make sure we aren't mangling any image data */
+	if ((data->PixelFormat !=3D Format32bppArgb)
+	 && (data->PixelFormat !=3D Format32bppRgb))
+		return;
+
+	f =3D data->Stride - 4 * data->Width;
+	for (y=3D0, o=3D0; y < data->Height; y++, o +=3D f)
+		for (x=3D0; x < data->Width; x++, o +=3D 4)
+			scan0[o + 3] =3D 0xff; /* set alpha to fully-opaque */
+}
+
+GpStatus
+GdipBitmapLockBits (GpBitmap *bitmap, Rect *srcRect, int flags, int format=
, GdipBitmapData *locked_data)
+{
+	BitmapData *root_data =3D &bitmap->data;
+
+	g_return_val_if_fail (bitmap !=3D NULL, InvalidParameter);
+	g_return_val_if_fail (srcRect !=3D NULL, InvalidParameter);
+	g_return_val_if_fail (flags !=3D 0, InvalidParameter);
+	g_return_val_if_fail (locked_data !=3D NULL, InvalidParameter);
+
+	/* There is no way to set ImageLockModeUserInputBuf with S.D, so we don't
+	 * support it
+	 */
+	if (flags & ImageLockModeUserInputBuf)
+		return NotImplemented;
+
+	/* Is this bitmap already locked? */
+	if (root_data->Reserved & GBD_LOCKED)
+		return InvalidParameter;
+
+	if (!bitmap || !srcRect || !locked_data)
+		return InvalidParameter;
+
+	/* Make sure the srcRect makes sense */
+	if ((srcRect->X < 0) || (srcRect->Y < 0) || (srcRect->Width < 0) || (srcR=
ect->Height < 0))
+		return InvalidParameter;
+
+	if ((srcRect->X + srcRect->Width > root_data->Width) || (srcRect->Y + src=
Rect->Height > root_data->Height))
+		return InvalidParameter;
+
+	if (gdip_is_a_supported_pixelformat (format) =3D=3D FALSE)
+		return NotImplemented;
+
+	/* Common stuff */
+	if (flags =3D=3D ImageLockModeRead)
+		locked_data->Reserved |=3D GBD_READ_ONLY;
+	else
+		locked_data->Reserved &=3D ~GBD_READ_ONLY;
+
+	locked_data->Reserved |=3D GBD_LOCKED;
+	locked_data->Reserved |=3D GBD_OWN_SCAN0;
+	root_data->Reserved |=3D GBD_LOCKED;
+
+	if (gdip_can_window_without_copy (root_data, srcRect, format)) {
+		/* Compute the start of the window; it's guaranteed to be on
+		 * a byte boundary since the preceding function call
+		 * returned true
+		 */
+		locked_data->Scan0 =3D root_data->Scan0
+		                   + srcRect->Y * root_data->Stride
+		                   + srcRect->X * gdip_get_pixel_format_bpp(root_data->P=
ixelFormat) / 8;
+
+		/* Set up the window's dimensions */
+		locked_data->Width =3D srcRect->Width;
+		locked_data->Height =3D srcRect->Height;
+		locked_data->Stride =3D root_data->Stride; /* the stride hasn't changed =
*/
+		locked_data->PixelFormat =3D root_data->PixelFormat;
+
+		/* Make sure the bits don't get deallocated, since Scan0 doesn't
+		 * necessarily point at the start of a memory block, and
+		 * the bits are owned by the root bitmap anyway
+		 */
+		locked_data->Reserved &=3D ~GBD_OWN_SCAN0;
+
+		/* If the source pixel format doesn't have alpha and the dest pixel form=
at
+		 * wants it, then overwrite the alpha byte in the original bitmap. it is
+		 * unused anyway :-)
+		 */
+		if (!gdip_is_an_alpha_pixelformat (root_data->PixelFormat)
+                 && gdip_is_an_alpha_pixelformat (locked_data->PixelFormat=
)) {
+			gdip_make_alpha_opaque (locked_data);
+		}
+
+		return Ok;
+	}
+	else {
+		/* If we get here, then something more drastic is needed. either the use=
r's rectangle
+		 * doesn't line up on byte boundaries, or the pixel format needs to be c=
hanged.
+		 */
+		int dest_pixel_format_bpp =3D gdip_get_pixel_format_bpp (format);
+		int dest_stride =3D (srcRect->Width * dest_pixel_format_bpp + 7) / 8;
+		int dest_size =3D srcRect->Height * dest_stride;
+
+		unsigned char *dest_scan0 =3D malloc(dest_size);
+
+		Rect destRect =3D { 0, 0, srcRect->Width, srcRect->Height };
+
+		GpStatus status =3D Ok;
+
+		if (dest_scan0 =3D=3D NULL)
+			return OutOfMemory;
+
+		locked_data->Scan0 =3D dest_scan0;
+		locked_data->Width =3D srcRect->Width;
+		locked_data->Height =3D srcRect->Height;
+		locked_data->Stride =3D dest_stride;
+		locked_data->PixelFormat =3D format;
+
+		/* If the user wants the original data to be readable, then convert the =
bits. */
+		if ((flags & ImageLockModeRead) !=3D 0) {
+			status =3D gdip_bitmap_change_rect_pixel_format (root_data, srcRect, lo=
cked_data, &destRect);
+			if (status !=3D Ok)
+				free(dest_scan0);
+		}
+
+		return status;
+	}
+}
+
+GpStatus
+GdipBitmapUnlockBits (GpBitmap *bitmap, GdipBitmapData *locked_data)
+{
+	BitmapData *root_data =3D &bitmap->data;
+
+	g_return_val_if_fail (bitmap !=3D NULL, InvalidParameter);
+	g_return_val_if_fail (locked_data !=3D NULL, InvalidParameter);
+
+	/* Make sure the bitmap is locked when the unlock happens */
+	if (!(bitmap->data.Reserved & GBD_LOCKED))
+		return InvalidParameter;
+
+	/* It is not safe to assume that the correct BitmapData has been passed i=
n.
+	 * Sanity check: Make sure the locked data is in fact locked.
+	 */
+	if ((locked_data->Reserved & GBD_LOCKED) =3D=3D 0)
+		return InvalidParameter;
+
+	/* Sanity check: Make sure the locked data's size is consistent with havi=
ng
+	 * been returned from LockBits ().
+	 */
+	if ((locked_data->Width > root_data->Width) || (locked_data->Height > roo=
t_data->Height))
+		return InvalidParameter;
+
+	/* Check whether the locked data window was created without
+	 * duplicating the bits to be locked.
+	 */
+	if ((int)(((char *)locked_data->Scan0) - ((char *)root_data->Scan0)) < ro=
ot_data->Height * root_data->Stride) {
+		/* Since the locked data's Scan0 is inside the root data's Scan0, it is
+		 * likely that the data was locked with the fast path of LockBits. Howev=
er,
+		 * a couple more sanity checks are required: The locked data's stride mu=
st
+		 * be the same as the root data's stride, and the end of the locked data=
's
+		 * bits must also lie within the root data's bits.
+		 */
+		char *byte_after_last_byte =3D (char *)locked_data->Scan0
+		                           + (locked_data->Height - 1) * locked_data->St=
ride
+		                           + (locked_data->Width * gdip_get_pixel_format=
_bpp (locked_data->PixelFormat) + 7) / 8;
+
+		if ((locked_data->Stride !=3D root_data->Stride)
+		 || ((int)(byte_after_last_byte - (char *)root_data->Scan0) > root_data-=
>Height * root_data->Stride))
+			return InvalidParameter;
+
+		/* We can be reasonably sure by this point that the locked data is authe=
ntic,
+		 * so now the only thing that needs to be done is alpha fixup.
+		 */
+		if ((locked_data->Reserved & GBD_READ_ONLY) !=3D 0) {
+			if (!gdip_is_an_alpha_pixelformat (locked_data->PixelFormat)
+			 && gdip_is_an_alpha_pixelformat (root_data->PixelFormat)) {
+				gdip_make_alpha_opaque (locked_data);
+			}
+		}
+	}
+	else {
+		/* We need to copy the locked data back to the root data's Scan0
+		 * (but of course only if the ImageLockMode specified writability)
+		 */
+		if ((locked_data->Reserved & GBD_READ_ONLY) !=3D 0) {
+			/* FIXME: destRect isn't necessarily equal to srcRect. this is a bug (t=
he old implementation had it too). */
+			Rect srcRect =3D { 0, 0, locked_data->Width, locked_data->Height };
+			Rect destRect =3D srcRect;
+
+			GpStatus status =3D gdip_bitmap_change_rect_pixel_format (root_data, &s=
rcRect, locked_data, &destRect);
+			if (status !=3D Ok)
+				return status;
+		}
+	}
+
+	if ((locked_data->Reserved & GBD_OWN_SCAN0) !=3D 0) {
+		free(locked_data->Scan0);
+		locked_data->Scan0 =3D NULL;
+		locked_data->Reserved &=3D ~GBD_OWN_SCAN0;
+	}
+
+	locked_data->Reserved &=3D ~GBD_LOCKED;
+	root_data->Reserved &=3D ~GBD_LOCKED;
+
+	return Ok;
+}
+
+#else
+
 /* Microsoft GDI+ returns BitmapLock buffers in BGR (not RGB) */
 GpStatus
 GdipBitmapLockBits (GpBitmap *bitmap, Rect *srcRect, int flags, int format=
, GdipBitmapData *result)
@@ -810,6 +1465,7 @@

 	return Ok;
 }
+#endif // NEW_LOCKBITS_IMPL

 GpStatus
 GdipBitmapSetPixel (GpBitmap *bitmap, int x, int y, ARGB color)
@@ -825,7 +1481,10 @@

 	if (y < 0 || y > data->Height)
 		return InvalidParameter;
-
+
+	if (gdip_is_an_indexed_pixelformat (data->PixelFormat))
+		return InvalidParameter;
+
 	/* BMP Locked */
 	if (bitmap->data.Reserved & GBD_LOCKED)
 		return InvalidParameter;
@@ -880,6 +1539,7 @@
 		default:
 			return NotImplemented;
 	}
+
 	return Ok;
 }

@@ -972,3 +1632,93 @@
 	return bitmap->image.surface;
 }

+GpBitmap *
+gdip_convert_indexed_to_rgb (GpBitmap *indexed_bmp)
+{
+	BitmapData *data =3D &indexed_bmp->data;
+	ColorPalette *palette =3D indexed_bmp->image.palette;
+
+	int rgb_stride, rgb_bytes, force_alpha;
+	int one_pixel_mask, one_pixel_shift, pixels_per_byte;
+	int *rgb_scan0;
+	int p, x, y;
+
+	GpBitmap *ret;
+	GpStatus status;
+
+	if (!gdip_is_an_indexed_pixelformat (data->PixelFormat))
+		return NULL;
+
+	if (palette =3D=3D NULL)
+		return NULL;
+
+	switch (data->PixelFormat)
+	{
+		case Format1bppIndexed: one_pixel_mask =3D 0x01; one_pixel_shift =3D 1; =
pixels_per_byte =3D 8; break;
+		case Format4bppIndexed: one_pixel_mask =3D 0x0F; one_pixel_shift =3D 4; =
pixels_per_byte =3D 2; break;
+		case Format8bppIndexed: one_pixel_mask =3D 0xFF; one_pixel_shift =3D 8; =
pixels_per_byte =3D 1; break;
+		default: /* something is wrong!! */
+			return NULL;
+	}
+
+	if ((palette->Flags & PaletteFlagsHasAlpha) =3D=3D 0)
+		force_alpha =3D 0xff000000;
+	else
+		force_alpha =3D 0;
+
+	rgb_stride =3D data->Width * 4;
+
+	/* ensure pixman_bits_t alignment */
+	rgb_stride +=3D (sizeof(pixman_bits_t)-1);
+	rgb_stride &=3D ~(sizeof(pixman_bits_t)-1);
+
+	rgb_bytes =3D data->Height * rgb_stride;
+
+	/* allocate the RGB frame */
+	rgb_scan0 =3D malloc (rgb_bytes);
+
+	if (rgb_scan0 =3D=3D NULL) /* out of memory?? */
+		return NULL;
+
+	/* convert the indexed pixels into RGB values and store them into the RGB=
 frame */
+	for (y=3D0; y < data->Height; y++)
+	{
+		unsigned char *indexed_scan =3D (unsigned char *)(data->Scan0) + y * dat=
a->Stride;
+		int *rgb_scan =3D rgb_scan0 + (y * rgb_stride) / sizeof(int);
+
+		for (x=3D0; x < data->Width; x +=3D pixels_per_byte)
+		{
+			int pixels_this_byte =3D pixels_per_byte;
+			unsigned short sample =3D *indexed_scan;
+
+			indexed_scan++;
+
+			if (x + pixels_this_byte >=3D data->Width)
+				pixels_this_byte =3D data->Width - x;
+
+			for (p=3D0; p < pixels_this_byte; p++)
+			{
+				int index;
+
+				sample <<=3D one_pixel_shift;
+				index =3D (sample >> 8) & one_pixel_mask;
+
+				rgb_scan[x + p] =3D palette->Entries[index] | force_alpha;
+			}
+		}
+	}
+
+	/* try to get a GpBitmap out of it :-) */
+	status =3D GdipCreateBitmapFromScan0 (data->Width, data->Height, rgb_stri=
de, Format32bppRgb, rgb_scan0, &ret);
+
+	if ((status !=3D Ok) || (ret =3D=3D NULL)) {
+		free (ret);
+		free (rgb_scan0);
+		return NULL;
+	}
+	else {
+		ret->data.Reserved |=3D GBD_OWN_SCAN0;
+		return ret;
+	}
+}
+
Index: src/pngcodec.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/pngcodec.c	(revision 41706)
+++ src/pngcodec.c	(working copy)
@@ -147,9 +147,120 @@
         png_set_read_fn (png_ptr, pngsrc, _gdip_png_stream_read_data);
     }

-    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR | PNG_TRANSFORM_EXPA=
ND, NULL);
+    png_read_png(png_ptr, info_ptr, 0, NULL);

-    {
+    if ((png_get_bit_depth (png_ptr, info_ptr) <=3D 8)
+     && (png_get_channels (png_ptr, info_ptr) =3D=3D 1)
+     && (png_get_color_type (png_ptr, info_ptr) =3D=3D PNG_COLOR_TYPE_PALE=
TTE)) {
+	int width;
+	int height;
+	int bit_depth;
+	int source_stride, dest_stride;
+	png_bytep *row_pointers;
+	guchar *rawptr;
+	int num_colours;
+	int palette_entries;
+	ColorPalette *palette;
+	int i, j;
+
+	width =3D png_get_image_width (png_ptr, info_ptr);
+	height =3D png_get_image_height (png_ptr, info_ptr);
+	bit_depth =3D png_get_bit_depth (png_ptr, info_ptr);
+
+	source_stride =3D (width * bit_depth + 7) / 8;
+	dest_stride =3D (source_stride + sizeof(pixman_bits_t) - 1) & ~(sizeof(pi=
xman_bits_t) - 1);
+
+	/* Copy image data. */
+	row_pointers =3D png_get_rows (png_ptr, info_ptr);
+
+	if (bit_depth =3D=3D 2) { /* upsample to 4bpp */
+		dest_stride =3D ((width + 1) / 2 + sizeof(pixman_bits_t) - 1) & ~(sizeof=
(pixman_bits_t) - 1);
+
+		rawdata =3D GdipAlloc(dest_stride * height);
+		for (i=3D0; i < height; i++) {
+			png_bytep row =3D row_pointers[i];
+			rawptr =3D rawdata + i * dest_stride;
+
+			for (j=3D0; j < source_stride; j++) {
+				int four_pixels =3D row[j];
+
+				int first_two =3D 0x0F & (four_pixels >> 4);
+				int second_two =3D 0x0F & four_pixels;
+
+				first_two =3D (first_two & 0x03) | ((first_two & 0x0C) << 2);
+				second_two =3D (second_two & 0x03) | ((second_two & 0x0C) << 2);
+
+				rawptr[j * 2 + 0] =3D first_two;
+				rawptr[j * 2 + 1] =3D second_two;
+			}
+		}
+	}
+	else {
+		rawdata =3D GdipAlloc(dest_stride * height);
+		for (i=3D0; i < height; i++)
+			memcpy(rawdata + i * dest_stride, row_pointers[i], source_stride);
+	}
+
+	/* Copy palette. */
+	num_colours =3D 1 << bit_depth;
+	if (bit_depth =3D=3D 4)
+		num_colours =3D 256;
+
+	palette =3D GdipAlloc (sizeof(ColorPalette) + num_colours * sizeof(ARGB));
+
+	palette->Flags =3D 0;
+	palette->Count =3D num_colours;
+
+	palette_entries =3D num_colours;
+	if (palette_entries > info_ptr->num_palette)
+		palette_entries =3D info_ptr->num_palette;
+
+	for (i=3D0; i < palette_entries; i++)
+		set_pixel_bgra (&palette->Entries[i], 0,
+			info_ptr->palette[i].red,
+			info_ptr->palette[i].green,
+			info_ptr->palette[i].blue,
+			0xFF); /* alpha */
+
+	/* Make sure transparency is respected. */
+	for (i=3D0; i < info_ptr->num_trans; i++) {
+		int transparent_index =3D info_ptr->trans[i];
+
+		if (transparent_index < num_colours)
+			palette->Entries[i] =3D 0; /* 0 has an alpha value of 0x00 */
+	}
+
+        png_destroy_read_struct (&png_ptr, &info_ptr, &end_info_ptr);
+
+        img =3D gdip_bitmap_new ();
+        img->image.type =3D imageBitmap;
+        img->image.width =3D width;
+        img->image.height =3D height;
+
+        img->cairo_format =3D CAIRO_FORMAT_ARGB32;
+        img->data.Stride =3D dest_stride;
+        img->data.Width =3D width;
+        img->data.Height =3D height;
+        img->data.Scan0 =3D rawdata;
+        img->data.Reserved =3D GBD_OWN_SCAN0;
+
+	switch (bit_depth)
+	{
+		case 1: img->image.pixFormat =3D img->data.PixelFormat =3D Format1bppInd=
exed; img->cairo_format =3D CAIRO_FORMAT_A1; break;
+		case 4: img->image.pixFormat =3D img->data.PixelFormat =3D Format4bppInd=
exed; img->cairo_format =3D CAIRO_FORMAT_A8; break;
+		case 8: img->image.pixFormat =3D img->data.PixelFormat =3D Format8bppInd=
exed; img->cairo_format =3D CAIRO_FORMAT_A8; break;
+	}
+
+        img->image.imageFlags =3D ImageFlagsColorSpaceGRAY;
+        img->image.imageFlags |=3D
+            ImageFlagsReadOnly |
+            ImageFlagsHasRealPixelSize;
+        img->image.horizontalResolution =3D 0;
+        img->image.verticalResolution =3D 0;
+        img->image.propItems =3D NULL;
+        img->image.palette =3D palette;
+    }
+    else {
         int width;
         int height;
         guchar bit_depth;
@@ -168,6 +279,16 @@
         channels =3D png_get_channels (png_ptr, info_ptr);
         interlace =3D png_get_interlace_type (png_ptr, info_ptr);

+	/* According to the libpng manual, this sequence is equivalent to
+	 * using the PNG_TRANSFORM_EXPAND flag in png_read_png.
+	 */
+	if (color_type =3D=3D PNG_COLOR_TYPE_PALETTE)
+		png_set_palette_to_rgb (png_ptr);
+	if ((color_type =3D=3D PNG_COLOR_TYPE_GRAY) && (bit_depth < 8))
+		png_set_gray_1_2_4_to_8(png_ptr);
+	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+		png_set_tRNS_to_alpha(png_ptr);
+
         stride =3D width * 4;

         while (stride % sizeof(pixman_bits_t))
@@ -184,7 +305,7 @@
 		for (i =3D 0; i < height; i++) {
 			png_bytep rowp =3D row_pointers[i];
 			for (j =3D 0; j < width; j++) {
-				set_pixel_bgra (rawptr, 0, rowp[0], rowp[1], rowp[2], rowp[3]);
+				set_pixel_bgra (rawptr, 0, rowp[2], rowp[1], rowp[0], rowp[3]);
 				rowp +=3D 4;
 				rawptr +=3D 4;
 			}
@@ -195,7 +316,7 @@
 		for (i =3D 0; i < height; i++) {
 			png_bytep rowp =3D row_pointers[i];
 			for (j =3D 0; j < width; j++) {
-				set_pixel_bgra (rawptr, 0, rowp[0], rowp[1], rowp[2], 0xff);
+				set_pixel_bgra (rawptr, 0, rowp[2], rowp[1], rowp[0], 0xff);
 				rowp +=3D 3;
 				rawptr +=3D 4;
 			}
@@ -340,6 +461,12 @@
         case Format8bppIndexed:
             bit_depth =3D 8;
             break;
+	case Format4bppIndexed:
+	    bit_depth =3D 4;
+	    break;
+	case Format1bppIndexed:
+	    bit_depth =3D 1;
+	    break;
         /* We're not going to even try to save these images, for now */
         case Format64bppArgb:
         case Format64bppPArgb:
@@ -348,8 +475,6 @@
         case Format16bppGrayScale:
         case Format16bppRgb555:
         case Format16bppRgb565:
-        case Format4bppIndexed:
-        case Format1bppIndexed:
         default:
             bit_depth =3D -1;
             break;
@@ -366,9 +491,13 @@
             break;
         case Format32bppRgb:
         case Format24bppRgb:
-        case Format8bppIndexed:
             color_type =3D PNG_COLOR_TYPE_RGB; /* XXX - we should be able =
to write grayscale PNGs */
             break;
+        case Format8bppIndexed:
+        case Format4bppIndexed:
+        case Format1bppIndexed:
+ 	    color_type =3D PNG_COLOR_TYPE_PALETTE;
+	    break;
         case Format64bppArgb:
         case Format64bppPArgb:
         case Format48bppRgb:
@@ -376,8 +505,6 @@
         case Format16bppGrayScale:
         case Format16bppRgb555:
         case Format16bppRgb565:
-        case Format4bppIndexed:
-        case Format1bppIndexed:
         default:
             color_type =3D -1;
             break;
@@ -394,6 +521,24 @@
                   PNG_COMPRESSION_TYPE_DEFAULT,
                   PNG_FILTER_TYPE_DEFAULT);

+    if (gdip_is_an_indexed_pixelformat (bitmap->data.PixelFormat)) {
+	png_color palette[256];
+
+	int palette_entries =3D image->palette->Count;
+	if (bitmap->data.PixelFormat =3D=3D Format4bppIndexed)
+		palette_entries =3D 16;
+
+	for (i=3D0; i < palette_entries; i++) {
+		ARGB entry =3D image->palette->Entries[i];
+
+		palette[i].red   =3D  entry        & 0xFF;
+		palette[i].green =3D (entry >>  8) & 0xFF;
+		palette[i].blue  =3D (entry >> 16) & 0xFF;
+	}
+
+	png_set_PLTE (png_ptr, info_ptr, palette, palette_entries);
+    }
+
     png_write_info (png_ptr, info_ptr);

     if (image->pixFormat !=3D bitmap->data.PixelFormat) {
@@ -409,11 +554,16 @@

     png_set_bgr(png_ptr);

+    if (gdip_is_an_indexed_pixelformat (bitmap->data.PixelFormat)) {
+	for (i =3D 0; i < image->height; i++) {
+		png_write_row (png_ptr, bitmap->data.Scan0 + i * bitmap->data.Stride);
+	}
+    }
+    else {
 #ifdef WORDS_BIGENDIAN
-    {
-	    guchar *row_pointer =3D GdipAlloc (image->width * 4);
+	guchar *row_pointer =3D GdipAlloc (image->width * 4);

-	    for (i =3D 0; i < image->height; i++) {
+	for (i =3D 0; i < image->height; i++) {
 		for (j =3D 0; j < image->width; j++) {
 			row_pointer[j*4] =3D *((guchar *)bitmap->data.Scan0 + (bitmap->data.Str=
ide * i) + (j*4) + 3);
 			row_pointer[j*4+1] =3D *((guchar *)bitmap->data.Scan0 + (bitmap->data.S=
tride * i) + (j*4) + 2);
@@ -421,14 +571,14 @@
 			row_pointer[j*4+3] =3D *((guchar *)bitmap->data.Scan0 + (bitmap->data.S=
tride * i) + (j*4) + 0);
 		}
 		png_write_row (png_ptr, row_pointer);
-	    }
-	    GdipFree (row_pointer);
-    }
+	}
+	GdipFree (row_pointer);
 #else
-    for (i =3D 0; i < image->height; i++) {
-    	png_write_row (png_ptr, bitmap->data.Scan0 + (bitmap->data.Stride * i=
));
+	for (i =3D 0; i < image->height; i++) {
+		png_write_row (png_ptr, bitmap->data.Scan0 + (bitmap->data.Stride * i));
+	}
+#endif
     }
-#endif

     png_write_end (png_ptr, NULL);

Index: src/gdip.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/gdip.h	(revision 41706)
+++ src/gdip.h	(working copy)
@@ -45,17 +45,17 @@

 #ifdef WORDS_BIGENDIAN
 #define set_pixel_bgra(pixel,index,b,g,r,a) do {\
-                pixel[index+0] =3D a; \
-                pixel[index+1] =3D r; \
-                pixel[index+2] =3D g; \
-                pixel[index+3] =3D b; \
+                ((unsigned char *)(pixel))[index+0] =3D a; \
+                ((unsigned char *)(pixel))[index+1] =3D r; \
+                ((unsigned char *)(pixel))[index+2] =3D g; \
+                ((unsigned char *)(pixel))[index+3] =3D b; \
         } while (0);
 #else
 #define set_pixel_bgra(pixel,index,b,g,r,a) do {\
-                pixel[index+0] =3D b; \
-                pixel[index+1] =3D g; \
-                pixel[index+2] =3D r; \
-                pixel[index+3] =3D a; \
+                ((unsigned char *)(pixel))[index+0] =3D b; \
+                ((unsigned char *)(pixel))[index+1] =3D g; \
+                ((unsigned char *)(pixel))[index+2] =3D r; \
+                ((unsigned char *)(pixel))[index+3] =3D a; \
         } while (0);
 #endif

@@ -1248,6 +1248,8 @@
 void gdip_rect_expand_by (GpRectF *rect, GpPointF *point);

 cairo_surface_t * gdip_bitmap_ensure_surface (GpBitmap *bitmap);
+BOOL gdip_is_an_indexed_pixelformat (PixelFormat pixfmt);
+GpBitmap * gdip_convert_indexed_to_rgb (GpBitmap *bitmap);

 const EncoderParameter *gdip_find_encoder_parameter (GDIPCONST EncoderPara=
meters *eps, const GUID *guid);


--=====================_1110583342==_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="System.Drawing.diff"

Index: System.Drawing.Imaging/ColorPalette.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- System.Drawing.Imaging/ColorPalette.cs	(revision 41706)
+++ System.Drawing.Imaging/ColorPalette.cs	(working copy)
@@ -112,7 +112,16 @@

 		internal void setFromGDIPalette(IntPtr palette)
 		{
-
+			GdiColorPalette header =3D (GdiColorPalette)Marshal.PtrToStructure (pal=
ette, typeof(GdiColorPalette));
+
+			int[] values =3D new int[header.Count];
+
+			Marshal.Copy((IntPtr) (palette.ToInt32() + Marshal.SizeOf (palette)), v=
alues, 0, values.Length);
+
+			this.flags =3D header.Flags;
+			this.entries =3D new Color[values.Length];
+			for (int i=3D0; i < values.Length; i++)
+				this.entries[i] =3D Color.FromArgb(values[i]);
 		}
 	}
 }
Index: System.Drawing.Imaging/ChangeLog
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- System.Drawing.Imaging/ChangeLog	(revision 41706)
+++ System.Drawing.Imaging/ChangeLog	(working copy)
@@ -1,5 +1,10 @@
+2005-03-02 Jonathan Gilbert  <................>
+
+	* ColorPalette.cs: implemented the empty setFromGDIPalette
+	  method.
+
-2004-02-25 Jordi Mas i Hernadez <jordi@ximian.com>
+2005-02-25 Jordi Mas i Hernadez <jordi@ximian.com>

 	* ColorMatrix.cs: rewritten to be able to marshall it properly

 2004-12-27  Zoltan Varga  <vargaz@freemail.hu>
Index: System.Drawing/Bitmap.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- System.Drawing/Bitmap.cs	(revision 41706)
+++ System.Drawing/Bitmap.cs	(working copy)
@@ -66,7 +66,7 @@
 			IntPtr bmp;
 			Status s =3D GDIPlus.GdipCreateBitmapFromGraphics (width, height, g.nat=
iveObject, out bmp);
 			GDIPlus.CheckStatus (s);
-			nativeObject =3D (IntPtr)bmp;
+			nativeObject =3D (IntPtr)bmp;
 		}

 		public Bitmap (int width, int height, PixelFormat format)
@@ -75,7 +75,6 @@
 			Status s =3D GDIPlus.GdipCreateBitmapFromScan0 (width, height, 0, forma=
t, IntPtr.Zero, out bmp);
 			GDIPlus.CheckStatus (s);
 			nativeObject =3D (IntPtr) bmp;
-
 		}

 		public Bitmap (Image original) : this (original.Width, original.Height, =
PixelFormat.Format32bppArgb)
@@ -105,13 +104,12 @@

 		internal Bitmap (int width, int height, PixelFormat pixel, IntPtr bmp)
 		{
-			nativeObject =3D (IntPtr)bmp;
+			nativeObject =3D (IntPtr)bmp;
 		}

 		internal Bitmap (float width, float height, PixelFormat pixel, IntPtr bm=
p)
 		{
-			nativeObject =3D (IntPtr)bmp;
-
+			nativeObject =3D (IntPtr)bmp;
 		}

 		internal void BitmapFromImage(Image original, Size newSize){
@@ -127,7 +125,6 @@
 				Status s =3D GDIPlus.GdipCloneBitmapAreaI (0, 0, newSize.Width, newSiz=
e.Height, bmpOriginal.PixelFormat, bmpOriginal.nativeObject, out bmp);
 				GDIPlus.CheckStatus (s);
 				nativeObject =3D (IntPtr) bmp;
-
 			}
 			else {
 				throw new NotImplementedException ();
@@ -139,7 +136,7 @@
 			IntPtr imagePtr;
 			Status st =3D GDIPlus.GdipLoadImageFromFile (filename, out imagePtr);
 			GDIPlus.CheckStatus (st);
-			nativeObject =3D imagePtr;
+			nativeObject =3D imagePtr;
 		}

 		public Bitmap (Stream stream, bool useIcm)
@@ -177,7 +174,7 @@

 			Status status =3D GDIPlus.GdipCreateBitmapFromScan0 (width, height, str=
ide, format, scan0, out bmp);
 			GDIPlus.CheckStatus (status);
-			nativeObject =3D (IntPtr) bmp;
+			nativeObject =3D (IntPtr) bmp;
 		}

 		private Bitmap (SerializationInfo info, StreamingContext context)
Index: System.Drawing/gdipFunctions.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- System.Drawing/gdipFunctions.cs	(revision 41706)
+++ System.Drawing/gdipFunctions.cs	(working copy)
@@ -935,7 +935,7 @@
 		internal static extern Status GdipGetImagePaletteSize ( IntPtr image, ou=
t int size );

 		[DllImport("gdiplus.dll")]
-		internal static extern Status GdipGetImagePalette (IntPtr image, out Int=
Ptr palette, int size);
+		internal static extern Status GdipGetImagePalette (IntPtr image, IntPtr =
palette, int size);

 		[DllImport("gdiplus.dll")]
 		internal static extern Status GdipSetImagePalette (IntPtr image, IntPtr =
palette);
Index: System.Drawing/Image.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- System.Drawing/Image.cs	(revision 41706)
+++ System.Drawing/Image.cs	(working copy)
@@ -54,13 +54,11 @@
 	public delegate bool GetThumbnailImageAbort();

 	internal IntPtr nativeObject =3D IntPtr.Zero;
-	ColorPalette colorPalette;


 	// constructor
 	internal  Image()
 	{
-		colorPalette =3D new ColorPalette();
 	}

 	private Image (SerializationInfo info, StreamingContext context)
@@ -191,6 +189,11 @@
 		return ((pixfmt & PixelFormat.Extended) !=3D 0);
 	}

+	private static bool IsIndexedPixelFormat(PixelFormat pixfmt)
+	{
+		return ((pixfmt & PixelFormat.Indexed) !=3D 0);
+	}
+
 	internal void InitFromStream (Stream stream)
 	{
 		if (Environment.OSVersion.Platform =3D=3D (PlatformID) 128) {
@@ -497,14 +503,64 @@
 	[Browsable (false)]
 	public ColorPalette Palette {
 		get {
-
-			return colorPalette;
+			return retrieveGDIPalette();
 		}
 		set {
-			colorPalette =3D value;
+			storeGDIPalette(value);
 		}
 	}
-
+
+	internal ColorPalette retrieveGDIPalette()
+	{
+		ColorPalette ret =3D new ColorPalette();
+
+		if (!IsIndexedPixelFormat (PixelFormat))
+			return ret;
+
+		Status st;
+
+		int bytes;
+
+		st =3D GDIPlus.GdipGetImagePaletteSize (nativeObject, out bytes);
+		GDIPlus.CheckStatus (st);
+
+		IntPtr palette_data =3D Marshal.AllocHGlobal (bytes);
+
+		try
+		{
+			st =3D GDIPlus.GdipGetImagePalette (nativeObject, palette_data, bytes);
+			GDIPlus.CheckStatus (st);
+
+			ret.setFromGDIPalette (palette_data);
+			return ret;
+		}
+		finally
+		{
+			Marshal.FreeHGlobal (palette_data);
+		}
+	}
+
+	internal void storeGDIPalette(ColorPalette palette)
+	{
+		if (palette =3D=3D null)
+			throw new ArgumentNullException("palette");
+
+		IntPtr palette_data =3D palette.getGDIPalette();
+
+		if (palette_data =3D=3D IntPtr.Zero)
+			return;
+
+		try
+		{
+			Status st =3D GDIPlus.GdipSetImagePalette (nativeObject, palette_data);
+			GDIPlus.CheckStatus (st);
+		}
+		finally
+		{
+			Marshal.FreeHGlobal(palette_data);
+		}
+	}
+
 	public SizeF PhysicalDimension {
 		get {
 			float width,  height;
@@ -672,12 +728,7 @@
 			GDIPlus.CheckStatus (status);

 			if (this is Bitmap){
-				Bitmap b =3D new Bitmap (newimage);
-
-				if (colorPalette !=3D null)
-					b.colorPalette =3D colorPalette.Clone ();
-
-				return b;
+				return new Bitmap (newimage);
 			}

 			throw new NotImplementedException ();
Index: System.Drawing/ChangeLog
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- System.Drawing/ChangeLog	(revision 41706)
+++ System.Drawing/ChangeLog	(working copy)
@@ -1,3 +1,23 @@
+2050-03-02  Jonathan Gilbert  <................>
+
+	* Image.cs: Added retrieveGDIPalette () and storeGDIPalette ()
+	  and modified the Palette property to call them. This non-
+	  persistent behaviour was discovered by trial and error with
+	  Microsoft's implementation. In fact, the Palette property
+          does not behave like a property at all! It is the only way an
+	  instance of System.Drawing.Imaging.ColorPalette can be created,
+	  and it reflects a backing store that is only updated when the
+	  property 'set' method is called. Also updated Clone () since
+	  the palette is no longer cached at image load time.
+	* Image.cs: Added IsIndexedPixelFormat () in the same vein as
+	  Image::IsAlphaPixelFormat and Image::IsCanonicalPixelFormat.
+	  As such a function is not listed in MSDN nor given in
+	  Microsoft's implementation, I have made it a private function
+	  within the class that uses it.
+	* gdipFunctions.cs: Corrected the parameter list for
+	  GdiPlus::GdipGetImagePalette () (the palette should be a
+	  caller-allocated 'IntPtr', not an 'out IntPtr').
+
 2005-02-24  Geoff Norton  <gnorton@customerdna.com>

 	* gdipFunctions.cs: Cache the delegates in the GdiPlusStreamHelper

--=====================_1110583342==_--