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_realloc (State->buff, State->BufferSize);
252 State->Header.size = GUINT32_FROM_LE (* (guint32 *) &BIH[0]);
253 if (State->Header.size == 40) {
254 State->Header.width = GINT32_FROM_LE (* (gint32 *) &BIH[4]);
255 State->Header.height = GINT32_FROM_LE (* (gint32 *) &BIH[8]);
256 State->Header.depth = GUINT16_FROM_LE (* (guint16 *) &BIH[14]);
257 State->Compressed = GUINT32_FROM_LE (* (guint32 *) &BIH[16]);
258 } else if (State->Header.size == 12) {
259 State->Header.width = GUINT16_FROM_LE (* (guint16 *) &BIH[4]);
260 State->Header.height = GUINT16_FROM_LE (* (guint16 *) &BIH[6]);
261 State->Header.depth = GUINT16_FROM_LE (* (guint16 *) &BIH[10]);
262 State->Compressed = BI_RGB;
266 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
267 _("BMP image has unsupported header size"));
268 State->read_state = READ_STATE_ERROR;
272 State->Type = State->Header.depth; /* This may be less trivial someday */
274 /* Negative heights indicates bottom-down pixelorder */
275 if (State->Header.height < 0) {
276 State->Header.height = -State->Header.height;
277 State->Header.Negative = 1;
279 if (State->Header.width < 0) {
280 State->Header.width = -State->Header.width;
281 State->Header.Negative = 0;
284 if (State->Header.width == 0 || State->Header.height == 0 ||
285 (State->Compressed == BI_RLE4 && State->Type != 4) ||
286 (State->Compressed == BI_RLE8 && State->Type != 8) ||
287 (State->Compressed == BI_BITFIELDS && !(State->Type == 16 || State->Type == 32)) ||
288 State->Compressed > BI_BITFIELDS) {
291 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
292 _("BMP image has bogus header data"));
293 State->read_state = READ_STATE_ERROR;
297 if (State->Type == 32)
298 State->LineWidth = State->Header.width * 4;
299 else if (State->Type == 24)
300 State->LineWidth = State->Header.width * 3;
301 else if (State->Type == 16)
302 State->LineWidth = State->Header.width * 2;
303 else if (State->Type == 8)
304 State->LineWidth = State->Header.width * 1;
305 else if (State->Type == 4)
306 State->LineWidth = (State->Header.width + 1) / 2;
307 else if (State->Type == 1) {
308 State->LineWidth = State->Header.width / 8;
309 if ((State->Header.width & 7) != 0)
314 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
315 _("BMP image has bogus header data"));
316 State->read_state = READ_STATE_ERROR;
320 /* Pad to a 32 bit boundary */
321 if (((State->LineWidth % 4) > 0)
322 && (State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
323 State->LineWidth = (State->LineWidth / 4) * 4 + 4;
325 if (State->pixbuf == NULL) {
326 if (State->Type == 32)
328 gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
329 (gint) State->Header.width,
330 (gint) State->Header.height);
333 gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
334 (gint) State->Header.width,
335 (gint) State->Header.height);
337 if (State->pixbuf == NULL) {
340 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
341 _("Not enough memory to load bitmap image"));
342 State->read_state = READ_STATE_ERROR;
346 if (State->prepared_func != NULL)
347 /* Notify the client that we are ready to go */
348 (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
352 if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS)) {
353 State->compr.linebuffdone = 0;
354 State->compr.linebuffsize = State->Header.width;
355 if (State->Type == 8)
356 State->compr.linebuffsize *= 2;
357 State->compr.linebuff = g_malloc ((State->compr.linebuffsize + 1) / 2);
360 State->BufferDone = 0;
361 if (State->Type <= 8) {
362 State->read_state = READ_STATE_PALETTE;
363 State->BufferSize = GUINT32_FROM_LE (* (guint32 *) &BFH[10]) - 14 - State->Header.size;
364 } else if (State->Compressed == BI_RGB) {
365 State->read_state = READ_STATE_DATA;
366 State->BufferSize = State->LineWidth;
367 } else if (State->Compressed == BI_BITFIELDS) {
368 State->read_state = READ_STATE_BITMASKS;
369 State->BufferSize = 12;
371 g_assert_not_reached ();
373 State->buff = g_realloc (State->buff, State->BufferSize);
378 static void DecodeColormap (guchar *buff,
379 struct bmp_progressive_state *State,
384 g_assert (State->read_state == READ_STATE_PALETTE);
386 State->Colormap = g_malloc ((1 << State->Header.depth) * sizeof (*State->Colormap));
388 for (i = 0; i < (1 << State->Header.depth); i++)
390 State->Colormap[i][0] = buff[i * (State->Header.size == 12 ? 3 : 4)];
391 State->Colormap[i][1] = buff[i * (State->Header.size == 12 ? 3 : 4) + 1];
392 State->Colormap[i][2] = buff[i * (State->Header.size == 12 ? 3 : 4) + 2];
395 State->read_state = READ_STATE_DATA;
397 State->BufferDone = 0;
398 if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
399 State->BufferSize = 2;
401 State->BufferSize = State->LineWidth;
403 State->buff = g_realloc (State->buff, State->BufferSize);
406 /* Finds the lowest set bit and the number of set bits */
408 find_bits (int n, int *lowest, int *n_set)
414 for (i = 31; i >= 0; i--)
421 /* Decodes the 3 shorts that follow for the bitmasks for BI_BITFIELDS coding */
423 decode_bitmasks (struct bmp_progressive_state *State, guchar *buf)
425 State->r_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
428 State->g_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
431 State->b_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
433 find_bits (State->r_mask, &State->r_shift, &State->r_bits);
434 find_bits (State->g_mask, &State->g_shift, &State->g_bits);
435 find_bits (State->b_mask, &State->b_shift, &State->b_bits);
437 if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
438 State->r_mask = 0x7c00;
440 State->g_mask = 0x03e0;
442 State->b_mask = 0x001f;
445 State->r_bits = State->g_bits = State->b_bits = 5;
448 State->read_state = READ_STATE_DATA;
449 State->BufferDone = 0;
450 State->BufferSize = State->LineWidth;
451 State->buff = g_realloc (State->buff, State->BufferSize);
455 * func - called when we have pixmap created (but no image data)
456 * user_data - passed as arg 1 to func
457 * return context (opaque to user)
461 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
462 ModuleUpdatedNotifyFunc updated_func,
466 struct bmp_progressive_state *context;
468 context = g_new0(struct bmp_progressive_state, 1);
469 context->prepared_func = prepared_func;
470 context->updated_func = updated_func;
471 context->user_data = user_data;
473 context->read_state = READ_STATE_HEADERS;
475 context->BufferSize = 26;
476 context->buff = g_malloc(26);
477 context->BufferDone = 0;
478 /* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
480 context->Colormap = NULL;
486 memset(&context->Header, 0, sizeof(struct headerpair));
487 memset(&context->compr, 0, sizeof(struct bmp_compression_state));
490 context->pixbuf = NULL;
493 return (gpointer) context;
497 * context - returned from image_begin_load
499 * free context, unref gdk_pixbuf
501 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
503 struct bmp_progressive_state *context =
504 (struct bmp_progressive_state *) data;
506 /* FIXME this thing needs to report errors if
507 * we have unused image data
510 g_return_val_if_fail(context != NULL, TRUE);
512 if (context->compr.linebuff != NULL)
513 g_free(context->compr.linebuff);
515 if (context->Colormap != NULL)
516 g_free(context->Colormap);
519 g_object_unref(context->pixbuf);
521 g_free(context->buff);
529 The OneLineXX functions are called when 1 line worth of data is present.
530 OneLine24 is the 24 bpp-version.
532 static void OneLine32(struct bmp_progressive_state *context)
538 if (!context->Header.Negative)
539 pixels = (context->pixbuf->pixels +
540 context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
542 pixels = (context->pixbuf->pixels +
543 context->pixbuf->rowstride * context->Lines);
547 if (context->Compressed == BI_BITFIELDS) {
548 int r_lshift, r_rshift;
549 int g_lshift, g_rshift;
550 int b_lshift, b_rshift;
552 r_lshift = 8 - context->r_bits;
553 g_lshift = 8 - context->g_bits;
554 b_lshift = 8 - context->b_bits;
556 r_rshift = context->r_bits - r_lshift;
557 g_rshift = context->g_bits - g_lshift;
558 b_rshift = context->b_bits - b_lshift;
560 for (i = 0; i < context->Header.width; i++) {
563 v = src[0] | (src[1] << 8) | (src[2] << 16);
565 r = (v & context->r_mask) >> context->r_shift;
566 g = (v & context->g_mask) >> context->g_shift;
567 b = (v & context->b_mask) >> context->b_shift;
569 *pixels++ = (r << r_lshift) | (r >> r_rshift);
570 *pixels++ = (g << g_lshift) | (g >> g_rshift);
571 *pixels++ = (b << b_lshift) | (b >> b_rshift);
572 *pixels++ = src[3]; /* alpha */
577 for (i = 0; i < context->Header.width; i++) {
587 static void OneLine24(struct bmp_progressive_state *context)
593 if (context->Header.Negative == 0)
594 Pixels = (context->pixbuf->pixels +
595 context->pixbuf->rowstride *
596 (context->Header.height - context->Lines - 1));
598 Pixels = (context->pixbuf->pixels +
599 context->pixbuf->rowstride *
601 while (X < context->Header.width) {
602 Pixels[X * 3 + 0] = context->buff[X * 3 + 2];
603 Pixels[X * 3 + 1] = context->buff[X * 3 + 1];
604 Pixels[X * 3 + 2] = context->buff[X * 3 + 0];
610 static void OneLine16(struct bmp_progressive_state *context)
616 if (!context->Header.Negative)
617 pixels = (context->pixbuf->pixels +
618 context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
620 pixels = (context->pixbuf->pixels +
621 context->pixbuf->rowstride * context->Lines);
625 if (context->Compressed == BI_BITFIELDS) {
626 int r_lshift, r_rshift;
627 int g_lshift, g_rshift;
628 int b_lshift, b_rshift;
630 r_lshift = 8 - context->r_bits;
631 g_lshift = 8 - context->g_bits;
632 b_lshift = 8 - context->b_bits;
634 r_rshift = context->r_bits - r_lshift;
635 g_rshift = context->g_bits - g_lshift;
636 b_rshift = context->b_bits - b_lshift;
638 for (i = 0; i < context->Header.width; i++) {
641 v = (int) src[0] | ((int) src[1] << 8);
643 r = (v & context->r_mask) >> context->r_shift;
644 g = (v & context->g_mask) >> context->g_shift;
645 b = (v & context->b_mask) >> context->b_shift;
647 *pixels++ = (r << r_lshift) | (r >> r_rshift);
648 *pixels++ = (g << g_lshift) | (g >> g_rshift);
649 *pixels++ = (b << b_lshift) | (b >> b_rshift);
654 for (i = 0; i < context->Header.width; i++) {
657 v = src[0] | (src[1] << 8);
659 r = (v >> 10) & 0x1f;
663 *pixels++ = (r << 3) | (r >> 2);
664 *pixels++ = (g << 3) | (g >> 2);
665 *pixels++ = (b << 3) | (b >> 2);
669 static void OneLine8(struct bmp_progressive_state *context)
675 if (context->Header.Negative == 0)
676 Pixels = (context->pixbuf->pixels +
677 context->pixbuf->rowstride *
678 (context->Header.height - context->Lines - 1));
680 Pixels = (context->pixbuf->pixels +
681 context->pixbuf->rowstride *
683 while (X < context->Header.width) {
685 context->Colormap[context->buff[X]][2];
687 context->Colormap[context->buff[X]][1];
689 context->Colormap[context->buff[X]][0];
694 static void OneLine4(struct bmp_progressive_state *context)
700 if (context->Header.Negative == 0)
701 Pixels = (context->pixbuf->pixels +
702 context->pixbuf->rowstride *
703 (context->Header.height - context->Lines - 1));
705 Pixels = (context->pixbuf->pixels +
706 context->pixbuf->rowstride *
709 while (X < context->Header.width) {
712 Pix = context->buff[X / 2];
715 context->Colormap[Pix >> 4][2];
717 context->Colormap[Pix >> 4][1];
719 context->Colormap[Pix >> 4][0];
721 if (X < context->Header.width) {
722 /* Handle the other 4 bit pixel only when there is one */
724 context->Colormap[Pix & 15][2];
726 context->Colormap[Pix & 15][1];
728 context->Colormap[Pix & 15][0];
735 static void OneLine1(struct bmp_progressive_state *context)
741 if (context->Header.Negative == 0)
742 Pixels = (context->pixbuf->pixels +
743 context->pixbuf->rowstride *
744 (context->Header.height - context->Lines - 1));
746 Pixels = (context->pixbuf->pixels +
747 context->pixbuf->rowstride *
749 while (X < context->Header.width) {
752 Bit = (context->buff[X / 8]) >> (7 - (X & 7));
754 Pixels[X * 3 + 0] = context->Colormap[Bit][2];
755 Pixels[X * 3 + 1] = context->Colormap[Bit][1];
756 Pixels[X * 3 + 2] = context->Colormap[Bit][0];
762 static void OneLine(struct bmp_progressive_state *context)
764 context->BufferDone = 0;
765 if (context->Lines >= context->Header.height)
768 if (context->Type == 32)
770 else if (context->Type == 24)
772 else if (context->Type == 16)
774 else if (context->Type == 8)
776 else if (context->Type == 4)
778 else if (context->Type == 1)
781 g_assert_not_reached ();
785 if (context->updated_func != NULL) {
786 (*context->updated_func) (context->pixbuf,
789 context->Header.width,
797 DoCompressed(struct bmp_progressive_state *context)
800 switch (context->compr.phase) {
801 case 0: /* Neutral state */
802 if (context->buff[0] != 0) { /* run count */
803 context->compr.RunCount = context->buff[0];
804 if (context->Type == 8)
805 context->compr.RunCount *= 2;
806 while (context->compr.RunCount > 0) {
807 if (context->compr.linebuffdone & 1) {
808 guchar *ptr = context->compr.linebuff +
809 context->compr.linebuffdone / 2;
811 *ptr = (*ptr & 0xF0) | (context->buff[1] >> 4);
812 context->buff[1] = (context->buff[1] << 4) |
813 (context->buff[1] >> 4);
814 context->compr.linebuffdone++;
815 context->compr.RunCount--;
818 if (context->compr.RunCount) {
819 count = context->compr.linebuffsize -
820 context->compr.linebuffdone;
821 if (count > context->compr.RunCount)
822 count = context->compr.RunCount;
824 memset (context->compr.linebuff +
825 context->compr.linebuffdone / 2,
828 context->compr.RunCount -= count;
829 context->compr.linebuffdone += count;
831 if (context->compr.linebuffdone == context->compr.linebuffsize) {
832 guchar *tmp = context->buff;
833 context->buff = context->compr.linebuff;
837 if (context->compr.linebuffdone & 1)
838 context->buff[1] = (context->buff[1] << 4) |
839 (context->buff[1] >> 4);
840 context->compr.linebuffdone = 0;
843 } else { /* Escape */
844 if (context->buff[1] == 0) { /* End of line */
845 if (context->compr.linebuffdone) {
846 guchar *tmp = context->buff;
847 context->buff = context->compr.linebuff;
851 context->compr.linebuffdone = 0;
853 } else if (context->buff[1] == 1) { /* End of image */
854 if (context->compr.linebuffdone) {
855 guchar *tmp = context->buff;
856 context->buff = context->compr.linebuff;
861 context->compr.phase = 2;
862 } else if (context->buff[1] == 2) /* Cursor displacement */
863 ; /* not implemented */
865 context->compr.phase = 1;
866 context->compr.RunCount = context->buff[1];
867 if (context->Type == 8)
868 context->compr.RunCount *= 2;
869 context->BufferSize = (context->compr.RunCount + 3) / 4 * 2;
870 context->buff = g_realloc (context->buff, context->BufferSize);
873 context->BufferDone = 0;
877 while (pos < context->compr.RunCount) {
878 count = context->compr.linebuffsize - context->compr.linebuffdone;
879 if (count > context->compr.RunCount)
880 count = context->compr.RunCount;
882 if ((context->compr.linebuffdone & 1) || (pos & 1)) {
885 for (i = 0; i < count; i++) {
886 ptr = context->compr.linebuff + (i +
887 context->compr.linebuffdone) / 2;
888 newval = *(context->buff + (pos + i) / 2) & (0xf0 >> (((pos + i) % 2) * 4));
889 if (((pos + i) % 2) ^ ((context->compr.linebuffdone + i) % 2)) {
895 *ptr = (*ptr & (0xf << (((i + context->compr.linebuffdone) % 2) * 4))) | newval;
898 memmove (context->compr.linebuff +
899 context->compr.linebuffdone / 2,
900 context->buff + pos / 2,
904 context->compr.linebuffdone += count;
905 if (context->compr.linebuffdone == context->compr.linebuffsize) {
906 guchar *tmp = context->buff;
907 context->buff = context->compr.linebuff;
911 context->compr.linebuffdone = 0;
914 context->compr.phase = 0;
915 context->BufferSize = 2;
916 context->buff = g_realloc (context->buff, context->BufferSize);
917 context->BufferDone = 0;
920 context->BufferDone = 0;
926 * context - from image_begin_load
927 * buf - new image data
928 * size - length of new image data
930 * append image data onto inrecrementally built output image
933 gdk_pixbuf__bmp_image_load_increment(gpointer data,
938 struct bmp_progressive_state *context =
939 (struct bmp_progressive_state *) data;
943 if (context->read_state == READ_STATE_DONE)
945 else if (context->read_state == READ_STATE_ERROR)
949 if (context->BufferDone < context->BufferSize) { /* We still
950 have headerbytes to do */
952 context->BufferSize - context->BufferDone;
953 if (BytesToCopy > size)
956 memmove(context->buff + context->BufferDone,
961 context->BufferDone += BytesToCopy;
963 if (context->BufferDone != context->BufferSize)
967 switch (context->read_state) {
968 case READ_STATE_HEADERS:
969 if (!DecodeHeader (context->buff,
970 context->buff + 14, context,
976 case READ_STATE_PALETTE:
977 DecodeColormap (context->buff, context, error);
980 case READ_STATE_BITMASKS:
981 decode_bitmasks (context, context->buff);
984 case READ_STATE_DATA:
985 if (context->Compressed == BI_RGB || context->Compressed == BI_BITFIELDS)
988 DoCompressed (context);
993 g_assert_not_reached ();
1001 gdk_pixbuf__bmp_fill_vtable (GdkPixbufModule *module)
1003 module->load = gdk_pixbuf__bmp_image_load;
1004 module->begin_load = gdk_pixbuf__bmp_image_begin_load;
1005 module->stop_load = gdk_pixbuf__bmp_image_stop_load;
1006 module->load_increment = gdk_pixbuf__bmp_image_load_increment;