1 /* GdkPixbuf library - Windows Bitmap image loader
3 * Copyright (C) 1999 The Free Software Foundation
5 * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
6 * Federico Mena-Quintero <federico@gimp.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
32 #include "gdk-pixbuf-private.h"
33 #include "gdk-pixbuf-io.h"
38 /* If these structures were unpacked, they would define the two headers of the
39 * BMP file. After them comes the palette, and then the image data.
41 * We do not use these structures; we just keep them here for reference.
43 struct BitmapFileHeader {
50 struct BitmapInfoHeader {
61 guint32 n_important_colors;
65 /* Compression values */
70 #define BI_BITFIELDS 3
74 READ_STATE_HEADERS, /* Reading the bitmap file header and bitmap info header */
75 READ_STATE_PALETTE, /* Reading the palette */
76 READ_STATE_BITMASKS, /* Reading the bitmasks for BI_BITFIELDS */
77 READ_STATE_DATA, /* Reading the actual image data */
78 READ_STATE_ERROR, /* An error occurred; further data will be ignored */
79 READ_STATE_DONE /* Done reading the image; further data will be ignored */
84 DumpBIH printf's the values in a BitmapInfoHeader to the screen, for
89 static void DumpBIH(unsigned char *BIH)
91 printf("biSize = %i \n",
92 (int) (BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) +
94 printf("biWidth = %i \n",
95 (int) (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) +
97 printf("biHeight = %i \n",
98 (int) (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
100 printf("biPlanes = %i \n", (int) (BIH[13] << 8) + (BIH[12]));
101 printf("biBitCount = %i \n", (int) (BIH[15] << 8) + (BIH[14]));
102 printf("biCompress = %i \n",
103 (int) (BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
105 printf("biSizeImage = %i \n",
106 (int) (BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
108 printf("biXPels = %i \n",
109 (int) (BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
111 printf("biYPels = %i \n",
112 (int) (BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
114 printf("biClrUsed = %i \n",
115 (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
117 printf("biClrImprtnt= %i \n",
118 (int) (BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
122 /* struct headerpair contains the decoded width/height/depth info for
123 the current bitmap */
130 guint Negative; /* Negative = 1 -> top down BMP,
131 Negative = 0 -> bottom up BMP */
134 /* Data needed for the "state" during decompression */
135 struct bmp_compression_state {
140 gint linebuffsize; /* these two counts in nibbles */
144 /* Progressive loading */
146 struct bmp_progressive_state {
147 ModulePreparedNotifyFunc prepared_func;
148 ModuleUpdatedNotifyFunc updated_func;
151 ReadState read_state;
154 guint Lines; /* # of finished lines */
160 guchar (*Colormap)[3];
166 4 = 4 bpp colormapped
167 8 = 8 bpp colormapped
171 struct bmp_compression_state compr;
174 struct headerpair Header; /* Decoded (BE->CPU) header */
176 /* Bit masks, shift amounts, and significant bits for BI_BITFIELDS coding */
177 int r_mask, r_shift, r_bits;
178 int g_mask, g_shift, g_bits;
179 int b_mask, b_shift, b_bits;
181 GdkPixbuf *pixbuf; /* Our "target" */
185 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
186 ModuleUpdatedNotifyFunc updated_func,
190 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
191 static gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data,
198 /* Shared library entry point --> This should be removed when
199 generic_image_load enters gdk-pixbuf-io. */
200 static GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f, GError **error)
204 struct bmp_progressive_state *State;
209 gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL,
215 while (feof(f) == 0) {
216 length = fread(membuf, 1, sizeof (membuf), f);
218 if (!gdk_pixbuf__bmp_image_load_increment(State,
222 gdk_pixbuf__bmp_image_stop_load (State, NULL);
227 if (State->pixbuf != NULL)
228 g_object_ref(State->pixbuf);
232 gdk_pixbuf__bmp_image_stop_load(State, NULL);
236 static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
237 struct bmp_progressive_state *State,
240 /* FIXME this is totally unrobust against bogus image data. */
242 if (State->BufferSize < GUINT32_FROM_LE (* (guint32 *) &BIH[0]) + 14) {
243 State->BufferSize = GUINT32_FROM_LE (* (guint32 *) &BIH[0]) + 14;
244 State->buff = g_try_realloc (State->buff, State->BufferSize);
245 if (State->buff == NULL) {
248 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
249 _("Not enough memory to load bitmap image"));
250 State->read_state = READ_STATE_ERROR;
260 State->Header.size = GUINT32_FROM_LE (* (guint32 *) &BIH[0]);
261 if (State->Header.size == 40) {
262 State->Header.width = GINT32_FROM_LE (* (gint32 *) &BIH[4]);
263 State->Header.height = GINT32_FROM_LE (* (gint32 *) &BIH[8]);
264 State->Header.depth = GUINT16_FROM_LE (* (guint16 *) &BIH[14]);
265 State->Compressed = GUINT32_FROM_LE (* (guint32 *) &BIH[16]);
266 } else if (State->Header.size == 12) {
267 State->Header.width = GUINT16_FROM_LE (* (guint16 *) &BIH[4]);
268 State->Header.height = GUINT16_FROM_LE (* (guint16 *) &BIH[6]);
269 State->Header.depth = GUINT16_FROM_LE (* (guint16 *) &BIH[10]);
270 State->Compressed = BI_RGB;
274 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
275 _("BMP image has unsupported header size"));
276 State->read_state = READ_STATE_ERROR;
280 State->Type = State->Header.depth; /* This may be less trivial someday */
282 /* Negative heights indicates bottom-down pixelorder */
283 if (State->Header.height < 0) {
284 State->Header.height = -State->Header.height;
285 State->Header.Negative = 1;
287 if (State->Header.width < 0) {
288 State->Header.width = -State->Header.width;
289 State->Header.Negative = 0;
292 if (State->Header.width == 0 || State->Header.height == 0 ||
293 (State->Compressed == BI_RLE4 && State->Type != 4) ||
294 (State->Compressed == BI_RLE8 && State->Type != 8) ||
295 (State->Compressed == BI_BITFIELDS && !(State->Type == 16 || State->Type == 32)) ||
296 State->Compressed > BI_BITFIELDS) {
299 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
300 _("BMP image has bogus header data"));
301 State->read_state = READ_STATE_ERROR;
305 if (State->Type == 32)
306 State->LineWidth = State->Header.width * 4;
307 else if (State->Type == 24)
308 State->LineWidth = State->Header.width * 3;
309 else if (State->Type == 16)
310 State->LineWidth = State->Header.width * 2;
311 else if (State->Type == 8)
312 State->LineWidth = State->Header.width * 1;
313 else if (State->Type == 4)
314 State->LineWidth = (State->Header.width + 1) / 2;
315 else if (State->Type == 1) {
316 State->LineWidth = State->Header.width / 8;
317 if ((State->Header.width & 7) != 0)
322 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
323 _("BMP image has bogus header data"));
324 State->read_state = READ_STATE_ERROR;
328 /* Pad to a 32 bit boundary */
329 if (((State->LineWidth % 4) > 0)
330 && (State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
331 State->LineWidth = (State->LineWidth / 4) * 4 + 4;
333 if (State->pixbuf == NULL) {
334 if (State->Type == 32)
336 gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
337 (gint) State->Header.width,
338 (gint) State->Header.height);
341 gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
342 (gint) State->Header.width,
343 (gint) State->Header.height);
345 if (State->pixbuf == NULL) {
348 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
349 _("Not enough memory to load bitmap image"));
350 State->read_state = READ_STATE_ERROR;
354 if (State->prepared_func != NULL)
355 /* Notify the client that we are ready to go */
356 (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
360 if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS)) {
361 State->compr.linebuffdone = 0;
362 State->compr.linebuffsize = State->Header.width;
363 if (State->Type == 8)
364 State->compr.linebuffsize *= 2;
365 State->compr.linebuff = g_malloc ((State->compr.linebuffsize + 1) / 2);
368 State->BufferDone = 0;
369 if (State->Type <= 8) {
370 State->read_state = READ_STATE_PALETTE;
371 State->BufferSize = GUINT32_FROM_LE (* (guint32 *) &BFH[10]) - 14 - State->Header.size;
372 } else if (State->Compressed == BI_RGB) {
373 State->read_state = READ_STATE_DATA;
374 State->BufferSize = State->LineWidth;
375 } else if (State->Compressed == BI_BITFIELDS) {
376 State->read_state = READ_STATE_BITMASKS;
377 State->BufferSize = 12;
379 g_assert_not_reached ();
381 State->buff = g_realloc (State->buff, State->BufferSize);
386 static void DecodeColormap (guchar *buff,
387 struct bmp_progressive_state *State,
392 g_assert (State->read_state == READ_STATE_PALETTE);
394 State->Colormap = g_malloc ((1 << State->Header.depth) * sizeof (*State->Colormap));
396 for (i = 0; i < (1 << State->Header.depth); i++)
398 State->Colormap[i][0] = buff[i * (State->Header.size == 12 ? 3 : 4)];
399 State->Colormap[i][1] = buff[i * (State->Header.size == 12 ? 3 : 4) + 1];
400 State->Colormap[i][2] = buff[i * (State->Header.size == 12 ? 3 : 4) + 2];
403 State->read_state = READ_STATE_DATA;
405 State->BufferDone = 0;
406 if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
407 State->BufferSize = 2;
409 State->BufferSize = State->LineWidth;
411 State->buff = g_realloc (State->buff, State->BufferSize);
414 /* Finds the lowest set bit and the number of set bits */
416 find_bits (int n, int *lowest, int *n_set)
422 for (i = 31; i >= 0; i--)
429 /* Decodes the 3 shorts that follow for the bitmasks for BI_BITFIELDS coding */
431 decode_bitmasks (struct bmp_progressive_state *State, guchar *buf)
433 State->r_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
436 State->g_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
439 State->b_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
441 find_bits (State->r_mask, &State->r_shift, &State->r_bits);
442 find_bits (State->g_mask, &State->g_shift, &State->g_bits);
443 find_bits (State->b_mask, &State->b_shift, &State->b_bits);
445 if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
446 State->r_mask = 0x7c00;
448 State->g_mask = 0x03e0;
450 State->b_mask = 0x001f;
453 State->r_bits = State->g_bits = State->b_bits = 5;
456 State->read_state = READ_STATE_DATA;
457 State->BufferDone = 0;
458 State->BufferSize = State->LineWidth;
459 State->buff = g_realloc (State->buff, State->BufferSize);
463 * func - called when we have pixmap created (but no image data)
464 * user_data - passed as arg 1 to func
465 * return context (opaque to user)
469 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
470 ModuleUpdatedNotifyFunc updated_func,
474 struct bmp_progressive_state *context;
476 context = g_new0(struct bmp_progressive_state, 1);
477 context->prepared_func = prepared_func;
478 context->updated_func = updated_func;
479 context->user_data = user_data;
481 context->read_state = READ_STATE_HEADERS;
483 context->BufferSize = 26;
484 context->buff = g_malloc(26);
485 context->BufferDone = 0;
486 /* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
488 context->Colormap = NULL;
494 memset(&context->Header, 0, sizeof(struct headerpair));
495 memset(&context->compr, 0, sizeof(struct bmp_compression_state));
498 context->pixbuf = NULL;
501 return (gpointer) context;
505 * context - returned from image_begin_load
507 * free context, unref gdk_pixbuf
509 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
511 struct bmp_progressive_state *context =
512 (struct bmp_progressive_state *) data;
514 /* FIXME this thing needs to report errors if
515 * we have unused image data
518 g_return_val_if_fail(context != NULL, TRUE);
520 if (context->compr.linebuff != NULL)
521 g_free(context->compr.linebuff);
523 if (context->Colormap != NULL)
524 g_free(context->Colormap);
527 g_object_unref(context->pixbuf);
529 g_free(context->buff);
537 The OneLineXX functions are called when 1 line worth of data is present.
538 OneLine24 is the 24 bpp-version.
540 static void OneLine32(struct bmp_progressive_state *context)
546 if (!context->Header.Negative)
547 pixels = (context->pixbuf->pixels +
548 context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
550 pixels = (context->pixbuf->pixels +
551 context->pixbuf->rowstride * context->Lines);
555 if (context->Compressed == BI_BITFIELDS) {
556 int r_lshift, r_rshift;
557 int g_lshift, g_rshift;
558 int b_lshift, b_rshift;
560 r_lshift = 8 - context->r_bits;
561 g_lshift = 8 - context->g_bits;
562 b_lshift = 8 - context->b_bits;
564 r_rshift = context->r_bits - r_lshift;
565 g_rshift = context->g_bits - g_lshift;
566 b_rshift = context->b_bits - b_lshift;
568 for (i = 0; i < context->Header.width; i++) {
571 v = src[0] | (src[1] << 8) | (src[2] << 16);
573 r = (v & context->r_mask) >> context->r_shift;
574 g = (v & context->g_mask) >> context->g_shift;
575 b = (v & context->b_mask) >> context->b_shift;
577 *pixels++ = (r << r_lshift) | (r >> r_rshift);
578 *pixels++ = (g << g_lshift) | (g >> g_rshift);
579 *pixels++ = (b << b_lshift) | (b >> b_rshift);
580 *pixels++ = src[3]; /* alpha */
585 for (i = 0; i < context->Header.width; i++) {
595 static void OneLine24(struct bmp_progressive_state *context)
601 if (context->Header.Negative == 0)
602 Pixels = (context->pixbuf->pixels +
603 context->pixbuf->rowstride *
604 (context->Header.height - context->Lines - 1));
606 Pixels = (context->pixbuf->pixels +
607 context->pixbuf->rowstride *
609 while (X < context->Header.width) {
610 Pixels[X * 3 + 0] = context->buff[X * 3 + 2];
611 Pixels[X * 3 + 1] = context->buff[X * 3 + 1];
612 Pixels[X * 3 + 2] = context->buff[X * 3 + 0];
618 static void OneLine16(struct bmp_progressive_state *context)
624 if (!context->Header.Negative)
625 pixels = (context->pixbuf->pixels +
626 context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
628 pixels = (context->pixbuf->pixels +
629 context->pixbuf->rowstride * context->Lines);
633 if (context->Compressed == BI_BITFIELDS) {
634 int r_lshift, r_rshift;
635 int g_lshift, g_rshift;
636 int b_lshift, b_rshift;
638 r_lshift = 8 - context->r_bits;
639 g_lshift = 8 - context->g_bits;
640 b_lshift = 8 - context->b_bits;
642 r_rshift = context->r_bits - r_lshift;
643 g_rshift = context->g_bits - g_lshift;
644 b_rshift = context->b_bits - b_lshift;
646 for (i = 0; i < context->Header.width; i++) {
649 v = (int) src[0] | ((int) src[1] << 8);
651 r = (v & context->r_mask) >> context->r_shift;
652 g = (v & context->g_mask) >> context->g_shift;
653 b = (v & context->b_mask) >> context->b_shift;
655 *pixels++ = (r << r_lshift) | (r >> r_rshift);
656 *pixels++ = (g << g_lshift) | (g >> g_rshift);
657 *pixels++ = (b << b_lshift) | (b >> b_rshift);
662 for (i = 0; i < context->Header.width; i++) {
665 v = src[0] | (src[1] << 8);
667 r = (v >> 10) & 0x1f;
671 *pixels++ = (r << 3) | (r >> 2);
672 *pixels++ = (g << 3) | (g >> 2);
673 *pixels++ = (b << 3) | (b >> 2);
677 static void OneLine8(struct bmp_progressive_state *context)
683 if (context->Header.Negative == 0)
684 Pixels = (context->pixbuf->pixels +
685 context->pixbuf->rowstride *
686 (context->Header.height - context->Lines - 1));
688 Pixels = (context->pixbuf->pixels +
689 context->pixbuf->rowstride *
691 while (X < context->Header.width) {
693 context->Colormap[context->buff[X]][2];
695 context->Colormap[context->buff[X]][1];
697 context->Colormap[context->buff[X]][0];
702 static void OneLine4(struct bmp_progressive_state *context)
708 if (context->Header.Negative == 0)
709 Pixels = (context->pixbuf->pixels +
710 context->pixbuf->rowstride *
711 (context->Header.height - context->Lines - 1));
713 Pixels = (context->pixbuf->pixels +
714 context->pixbuf->rowstride *
717 while (X < context->Header.width) {
720 Pix = context->buff[X / 2];
723 context->Colormap[Pix >> 4][2];
725 context->Colormap[Pix >> 4][1];
727 context->Colormap[Pix >> 4][0];
729 if (X < context->Header.width) {
730 /* Handle the other 4 bit pixel only when there is one */
732 context->Colormap[Pix & 15][2];
734 context->Colormap[Pix & 15][1];
736 context->Colormap[Pix & 15][0];
743 static void OneLine1(struct bmp_progressive_state *context)
749 if (context->Header.Negative == 0)
750 Pixels = (context->pixbuf->pixels +
751 context->pixbuf->rowstride *
752 (context->Header.height - context->Lines - 1));
754 Pixels = (context->pixbuf->pixels +
755 context->pixbuf->rowstride *
757 while (X < context->Header.width) {
760 Bit = (context->buff[X / 8]) >> (7 - (X & 7));
762 Pixels[X * 3 + 0] = context->Colormap[Bit][2];
763 Pixels[X * 3 + 1] = context->Colormap[Bit][1];
764 Pixels[X * 3 + 2] = context->Colormap[Bit][0];
770 static void OneLine(struct bmp_progressive_state *context)
772 context->BufferDone = 0;
773 if (context->Lines >= context->Header.height)
776 if (context->Type == 32)
778 else if (context->Type == 24)
780 else if (context->Type == 16)
782 else if (context->Type == 8)
784 else if (context->Type == 4)
786 else if (context->Type == 1)
789 g_assert_not_reached ();
793 if (context->updated_func != NULL) {
794 (*context->updated_func) (context->pixbuf,
797 context->Header.width,
805 DoCompressed(struct bmp_progressive_state *context)
808 switch (context->compr.phase) {
809 case 0: /* Neutral state */
810 if (context->buff[0] != 0) { /* run count */
811 context->compr.RunCount = context->buff[0];
812 if (context->Type == 8)
813 context->compr.RunCount *= 2;
814 while (context->compr.RunCount > 0) {
815 if (context->compr.linebuffdone & 1) {
816 guchar *ptr = context->compr.linebuff +
817 context->compr.linebuffdone / 2;
819 *ptr = (*ptr & 0xF0) | (context->buff[1] >> 4);
820 context->buff[1] = (context->buff[1] << 4) |
821 (context->buff[1] >> 4);
822 context->compr.linebuffdone++;
823 context->compr.RunCount--;
826 if (context->compr.RunCount) {
827 count = context->compr.linebuffsize -
828 context->compr.linebuffdone;
829 if (count > context->compr.RunCount)
830 count = context->compr.RunCount;
832 memset (context->compr.linebuff +
833 context->compr.linebuffdone / 2,
836 context->compr.RunCount -= count;
837 context->compr.linebuffdone += count;
839 if (context->compr.linebuffdone == context->compr.linebuffsize) {
840 guchar *tmp = context->buff;
841 context->buff = context->compr.linebuff;
845 if (context->compr.linebuffdone & 1)
846 context->buff[1] = (context->buff[1] << 4) |
847 (context->buff[1] >> 4);
848 context->compr.linebuffdone = 0;
851 } else { /* Escape */
852 if (context->buff[1] == 0) { /* End of line */
853 if (context->compr.linebuffdone) {
854 guchar *tmp = context->buff;
855 context->buff = context->compr.linebuff;
859 context->compr.linebuffdone = 0;
861 } else if (context->buff[1] == 1) { /* End of image */
862 if (context->compr.linebuffdone) {
863 guchar *tmp = context->buff;
864 context->buff = context->compr.linebuff;
869 context->compr.phase = 2;
870 } else if (context->buff[1] == 2) /* Cursor displacement */
871 ; /* not implemented */
873 context->compr.phase = 1;
874 context->compr.RunCount = context->buff[1];
875 if (context->Type == 8)
876 context->compr.RunCount *= 2;
877 context->BufferSize = (context->compr.RunCount + 3) / 4 * 2;
878 context->buff = g_realloc (context->buff, context->BufferSize);
881 context->BufferDone = 0;
885 while (pos < context->compr.RunCount) {
886 count = context->compr.linebuffsize - context->compr.linebuffdone;
887 if (count > context->compr.RunCount)
888 count = context->compr.RunCount;
890 if ((context->compr.linebuffdone & 1) || (pos & 1)) {
893 for (i = 0; i < count; i++) {
894 ptr = context->compr.linebuff + (i +
895 context->compr.linebuffdone) / 2;
896 newval = *(context->buff + (pos + i) / 2) & (0xf0 >> (((pos + i) % 2) * 4));
897 if (((pos + i) % 2) ^ ((context->compr.linebuffdone + i) % 2)) {
903 *ptr = (*ptr & (0xf << (((i + context->compr.linebuffdone) % 2) * 4))) | newval;
906 memmove (context->compr.linebuff +
907 context->compr.linebuffdone / 2,
908 context->buff + pos / 2,
912 context->compr.linebuffdone += count;
913 if (context->compr.linebuffdone == context->compr.linebuffsize) {
914 guchar *tmp = context->buff;
915 context->buff = context->compr.linebuff;
919 context->compr.linebuffdone = 0;
922 context->compr.phase = 0;
923 context->BufferSize = 2;
924 context->buff = g_realloc (context->buff, context->BufferSize);
925 context->BufferDone = 0;
928 context->BufferDone = 0;
934 * context - from image_begin_load
935 * buf - new image data
936 * size - length of new image data
938 * append image data onto inrecrementally built output image
941 gdk_pixbuf__bmp_image_load_increment(gpointer data,
946 struct bmp_progressive_state *context =
947 (struct bmp_progressive_state *) data;
951 if (context->read_state == READ_STATE_DONE)
953 else if (context->read_state == READ_STATE_ERROR)
957 if (context->BufferDone < context->BufferSize) { /* We still
958 have headerbytes to do */
960 context->BufferSize - context->BufferDone;
961 if (BytesToCopy > size)
964 memmove(context->buff + context->BufferDone,
969 context->BufferDone += BytesToCopy;
971 if (context->BufferDone != context->BufferSize)
975 switch (context->read_state) {
976 case READ_STATE_HEADERS:
977 if (!DecodeHeader (context->buff,
978 context->buff + 14, context,
984 case READ_STATE_PALETTE:
985 DecodeColormap (context->buff, context, error);
988 case READ_STATE_BITMASKS:
989 decode_bitmasks (context, context->buff);
992 case READ_STATE_DATA:
993 if (context->Compressed == BI_RGB || context->Compressed == BI_BITFIELDS)
996 DoCompressed (context);
1001 g_assert_not_reached ();
1009 gdk_pixbuf__bmp_fill_vtable (GdkPixbufModule *module)
1011 module->load = gdk_pixbuf__bmp_image_load;
1012 module->begin_load = gdk_pixbuf__bmp_image_begin_load;
1013 module->stop_load = gdk_pixbuf__bmp_image_stop_load;
1014 module->load_increment = gdk_pixbuf__bmp_image_load_increment;