]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-bmp.c
Fix docs.
[~andy/gtk] / gdk-pixbuf / io-bmp.c
1 /* GdkPixbuf library - Windows Bitmap image loader
2  *
3  * Copyright (C) 1999 The Free Software Foundation
4  *
5  * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
6  *          Federico Mena-Quintero <federico@gimp.org>
7  *
8  * Based on io-ras.c
9  *
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.
14  *
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.
19  *
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.
24  */
25
26 #include <config.h>
27 #include <stdio.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <string.h>
32 #include "gdk-pixbuf-private.h"
33 #include "gdk-pixbuf-io.h"
34
35 \f
36
37 #if 0
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.
40  *
41  * We do not use these structures; we just keep them here for reference.
42  */
43 struct BitmapFileHeader {
44         guint16 magic;
45         guint32 file_size;
46         guint32 reserved;
47         guint32 data_offset;
48 };
49
50 struct BitmapInfoHeader {
51         guint32 header_size;
52         guint32 width;
53         guint32 height;
54         guint16 planes;
55         guint16 bpp;
56         guint32 compression;
57         guint32 data_size;
58         guint32 x_ppm;
59         guint32 y_ppm;
60         guint32 n_colors;
61         guint32 n_important_colors;
62 };
63 #endif
64
65 /* Compression values */
66
67 #define BI_RGB 0
68 #define BI_RLE8 1
69 #define BI_RLE4 2
70 #define BI_BITFIELDS 3
71
72 /* State machine */
73 typedef enum {
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 */
80 } ReadState;
81
82 /*
83
84 DumpBIH printf's the values in a BitmapInfoHeader to the screen, for
85 debugging purposes.
86
87 */
88 #if DUMPBIH
89 static void DumpBIH(unsigned char *BIH)
90 {
91         printf("biSize      = %i \n",
92                (int) (BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) +
93                (BIH[0]));
94         printf("biWidth     = %i \n",
95                (int) (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) +
96                (BIH[4]));
97         printf("biHeight    = %i \n",
98                (int) (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
99                (BIH[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) +
104                (BIH[16]));
105         printf("biSizeImage = %i \n",
106                (int) (BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
107                (BIH[20]));
108         printf("biXPels     = %i \n",
109                (int) (BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
110                (BIH[24]));
111         printf("biYPels     = %i \n",
112                (int) (BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
113                (BIH[28]));
114         printf("biClrUsed   = %i \n",
115                (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
116                (BIH[32]));
117         printf("biClrImprtnt= %i \n",
118                (int) (BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
119                (BIH[36]));
120 }
121 #endif
122 /* struct headerpair contains the decoded width/height/depth info for
123    the current bitmap */
124
125 struct headerpair {
126         guint32 size;
127         gint32 width;
128         gint32 height;
129         guint depth;
130         guint Negative;         /* Negative = 1 -> top down BMP,
131                                    Negative = 0 -> bottom up BMP */
132 };
133
134 /* Data needed for the "state" during decompression */
135 struct bmp_compression_state {
136         gint phase;
137         gint RunCount;
138
139         guchar *linebuff;
140         gint linebuffsize;      /* these two counts in nibbles */
141         gint linebuffdone;
142 };
143
144 /* Progressive loading */
145
146 struct bmp_progressive_state {
147         ModulePreparedNotifyFunc prepared_func;
148         ModuleUpdatedNotifyFunc updated_func;
149         gpointer user_data;
150
151         ReadState read_state;
152
153         guint LineWidth;
154         guint Lines;            /* # of finished lines */
155
156         guchar *buff;
157         gint BufferSize;
158         gint BufferDone;
159
160         guchar (*Colormap)[3];
161
162         gint Type;              /*
163                                    32 = RGB + alpha
164                                    24 = RGB
165                                    16 = RGB
166                                    4  = 4 bpp colormapped
167                                    8  = 8 bpp colormapped
168                                    1  = 1 bit bitonal
169                                  */
170         gint Compressed;
171         struct bmp_compression_state compr;
172
173
174         struct headerpair Header;       /* Decoded (BE->CPU) header */
175
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;
180
181         GdkPixbuf *pixbuf;      /* Our "target" */
182 };
183
184 static gpointer
185 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
186                                  ModuleUpdatedNotifyFunc updated_func,
187                                  gpointer user_data,
188                                  GError **error);
189
190 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
191 static gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data,
192                                                      const guchar * buf,
193                                                      guint size,
194                                                      GError **error);
195
196
197
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)
201 {
202         guchar membuf[4096];
203         size_t length;
204         struct bmp_progressive_state *State;
205
206         GdkPixbuf *pb;
207
208         State =
209             gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL,
210                                              error);
211
212         if (State == NULL)
213           return NULL;
214
215         while (feof(f) == 0) {
216                 length = fread(membuf, 1, sizeof (membuf), f);
217                 if (length > 0)
218                   if (!gdk_pixbuf__bmp_image_load_increment(State,
219                                                             membuf,
220                                                             length,
221                                                             error)) {
222                           gdk_pixbuf__bmp_image_stop_load (State, NULL);
223                           return NULL;
224                   }
225
226         }
227         if (State->pixbuf != NULL)
228                 g_object_ref(State->pixbuf);
229
230         pb = State->pixbuf;
231
232         gdk_pixbuf__bmp_image_stop_load(State, NULL);
233         return pb;
234 }
235
236 static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
237                              struct bmp_progressive_state *State,
238                              GError **error)
239 {
240         /* FIXME this is totally unrobust against bogus image data. */
241
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) {
246                         g_set_error (error,
247                                      GDK_PIXBUF_ERROR,
248                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
249                                      _("Not enough memory to load bitmap image"));
250                         State->read_state = READ_STATE_ERROR;
251                         return FALSE;
252                 }
253                 return TRUE;
254         }
255
256 #if DUMPBIH
257         DumpBIH(BIH);
258 #endif
259
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;
271         } else {
272                 g_set_error (error,
273                              GDK_PIXBUF_ERROR,
274                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
275                              _("BMP image has unsupported header size"));
276                 State->read_state = READ_STATE_ERROR;
277                 return FALSE;
278         }
279
280         State->Type = State->Header.depth;      /* This may be less trivial someday */
281
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;
286         }
287         if (State->Header.width < 0) {
288                 State->Header.width = -State->Header.width;
289                 State->Header.Negative = 0;
290         }
291
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) {
297                 g_set_error (error,
298                              GDK_PIXBUF_ERROR,
299                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
300                              _("BMP image has bogus header data"));
301                 State->read_state = READ_STATE_ERROR;
302                 return FALSE;
303         }
304
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)
318                         State->LineWidth++;
319         } else {
320                 g_set_error (error,
321                              GDK_PIXBUF_ERROR,
322                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
323                              _("BMP image has bogus header data"));
324                 State->read_state = READ_STATE_ERROR;
325                 return FALSE;
326         }
327
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;
332
333         if (State->pixbuf == NULL) {
334                 if (State->Type == 32)
335                         State->pixbuf =
336                             gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
337                                            (gint) State->Header.width,
338                                            (gint) State->Header.height);
339                 else
340                         State->pixbuf =
341                             gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
342                                            (gint) State->Header.width,
343                                            (gint) State->Header.height);
344
345                 if (State->pixbuf == NULL) {
346                         g_set_error (error,
347                                      GDK_PIXBUF_ERROR,
348                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
349                                      _("Not enough memory to load bitmap image"));
350                         State->read_state = READ_STATE_ERROR;
351                         return FALSE;
352                 }
353
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);
357
358         }
359
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);
366         }
367
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;
378         } else
379                 g_assert_not_reached ();
380
381         State->buff = g_realloc (State->buff, State->BufferSize);
382
383         return TRUE;
384 }
385
386 static void DecodeColormap (guchar *buff,
387                             struct bmp_progressive_state *State,
388                             GError **error)
389 {
390         gint i;
391
392         g_assert (State->read_state == READ_STATE_PALETTE);
393
394         State->Colormap = g_malloc ((1 << State->Header.depth) * sizeof (*State->Colormap));
395
396         for (i = 0; i < (1 << State->Header.depth); i++)
397         {
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];
401         }
402
403         State->read_state = READ_STATE_DATA;
404
405         State->BufferDone = 0;
406         if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
407                 State->BufferSize = 2;
408         else
409                 State->BufferSize = State->LineWidth;
410
411         State->buff = g_realloc (State->buff, State->BufferSize);
412 }
413
414 /* Finds the lowest set bit and the number of set bits */
415 static void
416 find_bits (int n, int *lowest, int *n_set)
417 {
418         int i;
419
420         *n_set = 0;
421
422         for (i = 31; i >= 0; i--)
423                 if (n & (1 << i)) {
424                         *lowest = i;
425                         (*n_set)++;
426                 }
427 }
428
429 /* Decodes the 3 shorts that follow for the bitmasks for BI_BITFIELDS coding */
430 static void
431 decode_bitmasks (struct bmp_progressive_state *State, guchar *buf)
432 {
433         State->r_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
434         buf += 4;
435
436         State->g_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
437         buf += 4;
438
439         State->b_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
440
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);
444
445         if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
446                 State->r_mask = 0x7c00;
447                 State->r_shift = 10;
448                 State->g_mask = 0x03e0;
449                 State->g_shift = 5;
450                 State->b_mask = 0x001f;
451                 State->b_shift = 0;
452
453                 State->r_bits = State->g_bits = State->b_bits = 5;
454         }
455
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);
460 }
461
462 /*
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)
466  */
467
468 static gpointer
469 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
470                                  ModuleUpdatedNotifyFunc updated_func,
471                                  gpointer user_data,
472                                  GError **error)
473 {
474         struct bmp_progressive_state *context;
475
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;
480
481         context->read_state = READ_STATE_HEADERS;
482
483         context->BufferSize = 26;
484         context->buff = g_malloc(26);
485         context->BufferDone = 0;
486         /* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
487
488         context->Colormap = NULL;
489
490         context->Lines = 0;
491
492         context->Type = 0;
493
494         memset(&context->Header, 0, sizeof(struct headerpair));
495         memset(&context->compr, 0, sizeof(struct bmp_compression_state));
496
497
498         context->pixbuf = NULL;
499
500
501         return (gpointer) context;
502 }
503
504 /*
505  * context - returned from image_begin_load
506  *
507  * free context, unref gdk_pixbuf
508  */
509 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
510 {
511         struct bmp_progressive_state *context =
512             (struct bmp_progressive_state *) data;
513
514         /* FIXME this thing needs to report errors if
515          * we have unused image data
516          */
517
518         g_return_val_if_fail(context != NULL, TRUE);
519
520         if (context->compr.linebuff != NULL)
521                 g_free(context->compr.linebuff);
522
523         if (context->Colormap != NULL)
524                 g_free(context->Colormap);
525
526         if (context->pixbuf)
527                 g_object_unref(context->pixbuf);
528
529         g_free(context->buff);
530         g_free(context);
531
532         return TRUE;
533 }
534
535
536 /*
537 The OneLineXX functions are called when 1 line worth of data is present.
538 OneLine24 is the 24 bpp-version.
539 */
540 static void OneLine32(struct bmp_progressive_state *context)
541 {
542         int i;
543         guchar *pixels;
544         guchar *src;
545
546         if (!context->Header.Negative)
547                 pixels = (context->pixbuf->pixels +
548                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
549         else
550                 pixels = (context->pixbuf->pixels +
551                           context->pixbuf->rowstride * context->Lines);
552
553         src = context->buff;
554
555         if (context->Compressed == BI_BITFIELDS) {
556                 int r_lshift, r_rshift;
557                 int g_lshift, g_rshift;
558                 int b_lshift, b_rshift;
559
560                 r_lshift = 8 - context->r_bits;
561                 g_lshift = 8 - context->g_bits;
562                 b_lshift = 8 - context->b_bits;
563
564                 r_rshift = context->r_bits - r_lshift;
565                 g_rshift = context->g_bits - g_lshift;
566                 b_rshift = context->b_bits - b_lshift;
567
568                 for (i = 0; i < context->Header.width; i++) {
569                         int v, r, g, b;
570
571                         v = src[0] | (src[1] << 8) | (src[2] << 16);
572
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;
576
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 */
581
582                         src += 4;
583                 }
584         } else
585                 for (i = 0; i < context->Header.width; i++) {
586                         *pixels++ = src[2];
587                         *pixels++ = src[1];
588                         *pixels++ = src[0];
589                         *pixels++ = src[3];
590
591                         src += 4;
592                 }
593 }
594
595 static void OneLine24(struct bmp_progressive_state *context)
596 {
597         gint X;
598         guchar *Pixels;
599
600         X = 0;
601         if (context->Header.Negative == 0)
602                 Pixels = (context->pixbuf->pixels +
603                           context->pixbuf->rowstride *
604                           (context->Header.height - context->Lines - 1));
605         else
606                 Pixels = (context->pixbuf->pixels +
607                           context->pixbuf->rowstride *
608                           context->Lines);
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];
613                 X++;
614         }
615
616 }
617
618 static void OneLine16(struct bmp_progressive_state *context)
619 {
620         int i;
621         guchar *pixels;
622         guchar *src;
623
624         if (!context->Header.Negative)
625                 pixels = (context->pixbuf->pixels +
626                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
627         else
628                 pixels = (context->pixbuf->pixels +
629                           context->pixbuf->rowstride * context->Lines);
630
631         src = context->buff;
632
633         if (context->Compressed == BI_BITFIELDS) {
634                 int r_lshift, r_rshift;
635                 int g_lshift, g_rshift;
636                 int b_lshift, b_rshift;
637
638                 r_lshift = 8 - context->r_bits;
639                 g_lshift = 8 - context->g_bits;
640                 b_lshift = 8 - context->b_bits;
641
642                 r_rshift = context->r_bits - r_lshift;
643                 g_rshift = context->g_bits - g_lshift;
644                 b_rshift = context->b_bits - b_lshift;
645
646                 for (i = 0; i < context->Header.width; i++) {
647                         int v, r, g, b;
648
649                         v = (int) src[0] | ((int) src[1] << 8);
650
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;
654
655                         *pixels++ = (r << r_lshift) | (r >> r_rshift);
656                         *pixels++ = (g << g_lshift) | (g >> g_rshift);
657                         *pixels++ = (b << b_lshift) | (b >> b_rshift);
658
659                         src += 2;
660                 }
661         } else
662                 for (i = 0; i < context->Header.width; i++) {
663                         int v, r, g, b;
664
665                         v = src[0] | (src[1] << 8);
666
667                         r = (v >> 10) & 0x1f;
668                         g = (v >> 5) & 0x1f;
669                         b = v & 0x1f;
670
671                         *pixels++ = (r << 3) | (r >> 2);
672                         *pixels++ = (g << 3) | (g >> 2);
673                         *pixels++ = (b << 3) | (b >> 2);
674                 }
675 }
676
677 static void OneLine8(struct bmp_progressive_state *context)
678 {
679         gint X;
680         guchar *Pixels;
681
682         X = 0;
683         if (context->Header.Negative == 0)
684                 Pixels = (context->pixbuf->pixels +
685                           context->pixbuf->rowstride *
686                           (context->Header.height - context->Lines - 1));
687         else
688                 Pixels = (context->pixbuf->pixels +
689                           context->pixbuf->rowstride *
690                           context->Lines);
691         while (X < context->Header.width) {
692                 Pixels[X * 3 + 0] =
693                     context->Colormap[context->buff[X]][2];
694                 Pixels[X * 3 + 1] =
695                     context->Colormap[context->buff[X]][1];
696                 Pixels[X * 3 + 2] =
697                     context->Colormap[context->buff[X]][0];
698                 X++;
699         }
700 }
701
702 static void OneLine4(struct bmp_progressive_state *context)
703 {
704         gint X;
705         guchar *Pixels;
706
707         X = 0;
708         if (context->Header.Negative == 0)
709                 Pixels = (context->pixbuf->pixels +
710                           context->pixbuf->rowstride *
711                           (context->Header.height - context->Lines - 1));
712         else
713                 Pixels = (context->pixbuf->pixels +
714                           context->pixbuf->rowstride *
715                           context->Lines);
716
717         while (X < context->Header.width) {
718                 guchar Pix;
719
720                 Pix = context->buff[X / 2];
721
722                 Pixels[X * 3 + 0] =
723                     context->Colormap[Pix >> 4][2];
724                 Pixels[X * 3 + 1] =
725                     context->Colormap[Pix >> 4][1];
726                 Pixels[X * 3 + 2] =
727                     context->Colormap[Pix >> 4][0];
728                 X++;
729                 if (X < context->Header.width) {
730                         /* Handle the other 4 bit pixel only when there is one */
731                         Pixels[X * 3 + 0] =
732                             context->Colormap[Pix & 15][2];
733                         Pixels[X * 3 + 1] =
734                             context->Colormap[Pix & 15][1];
735                         Pixels[X * 3 + 2] =
736                             context->Colormap[Pix & 15][0];
737                         X++;
738                 }
739         }
740
741 }
742
743 static void OneLine1(struct bmp_progressive_state *context)
744 {
745         gint X;
746         guchar *Pixels;
747
748         X = 0;
749         if (context->Header.Negative == 0)
750                 Pixels = (context->pixbuf->pixels +
751                           context->pixbuf->rowstride *
752                           (context->Header.height - context->Lines - 1));
753         else
754                 Pixels = (context->pixbuf->pixels +
755                           context->pixbuf->rowstride *
756                           context->Lines);
757         while (X < context->Header.width) {
758                 gint Bit;
759
760                 Bit = (context->buff[X / 8]) >> (7 - (X & 7));
761                 Bit = Bit & 1;
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];
765                 X++;
766         }
767 }
768
769
770 static void OneLine(struct bmp_progressive_state *context)
771 {
772         context->BufferDone = 0;
773         if (context->Lines >= context->Header.height)
774                 return;
775
776         if (context->Type == 32)
777                 OneLine32(context);
778         else if (context->Type == 24)
779                 OneLine24(context);
780         else if (context->Type == 16)
781                 OneLine16(context);
782         else if (context->Type == 8)
783                 OneLine8(context);
784         else if (context->Type == 4)
785                 OneLine4(context);
786         else if (context->Type == 1)
787                 OneLine1(context);
788         else
789                 g_assert_not_reached ();
790
791         context->Lines++;
792
793         if (context->updated_func != NULL) {
794                 (*context->updated_func) (context->pixbuf,
795                                           0,
796                                           context->Lines,
797                                           context->Header.width,
798                                           1,
799                                           context->user_data);
800
801         }
802 }
803
804 static void
805 DoCompressed(struct bmp_progressive_state *context)
806 {
807         gint count, pos;
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;
818
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--;
824                                 }
825
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;
831
832                                         memset (context->compr.linebuff +
833                                                 context->compr.linebuffdone / 2,
834                                                 context->buff[1],
835                                                 (count + 1) / 2);
836                                         context->compr.RunCount -= count;
837                                         context->compr.linebuffdone += count;
838                                 }
839                                 if (context->compr.linebuffdone == context->compr.linebuffsize) {
840                                         guchar *tmp = context->buff;
841                                         context->buff = context->compr.linebuff;
842                                         OneLine (context);
843                                         context->buff = tmp;
844
845                                         if (context->compr.linebuffdone & 1)
846                                                 context->buff[1] = (context->buff[1] << 4) |
847                                                                    (context->buff[1] >> 4);
848                                         context->compr.linebuffdone = 0;
849                                 }
850                         }
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;
856                                         OneLine (context);
857                                         context->buff = tmp;
858
859                                         context->compr.linebuffdone = 0;
860                                 }
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;
865                                         OneLine (context);
866                                         context->buff = tmp;
867                                 }
868
869                                 context->compr.phase = 2;
870                         } else if (context->buff[1] == 2)       /* Cursor displacement */
871                                 ;       /* not implemented */
872                         else {
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);
879                         }
880                 }
881                 context->BufferDone = 0;
882                 break;
883         case 1:
884                 pos = 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;
889
890                         if ((context->compr.linebuffdone & 1) || (pos & 1)) {
891                                 gint i, newval;
892                                 guchar *ptr;
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)) {
898                                                 if ((pos + i) % 2)
899                                                         newval <<= 4;
900                                                 else
901                                                         newval >>= 4;
902                                         }
903                                         *ptr = (*ptr & (0xf << (((i + context->compr.linebuffdone) % 2) * 4))) | newval;
904                                 }
905                         } else {
906                                 memmove (context->compr.linebuff +
907                                          context->compr.linebuffdone / 2,
908                                          context->buff + pos / 2,
909                                          (count + 1) / 2);
910                         }
911                         pos += count;
912                         context->compr.linebuffdone += count;
913                         if (context->compr.linebuffdone == context->compr.linebuffsize) {
914                                 guchar *tmp = context->buff;
915                                 context->buff = context->compr.linebuff;
916                                 OneLine (context);
917                                 context->buff = tmp;
918
919                                 context->compr.linebuffdone = 0;
920                         }
921                 }
922                 context->compr.phase = 0;
923                 context->BufferSize = 2;
924                 context->buff = g_realloc (context->buff, context->BufferSize);
925                 context->BufferDone = 0;
926                 break;
927         case 2:
928                 context->BufferDone = 0;
929                 break;
930         }
931 }
932
933 /*
934  * context - from image_begin_load
935  * buf - new image data
936  * size - length of new image data
937  *
938  * append image data onto inrecrementally built output image
939  */
940 static gboolean
941 gdk_pixbuf__bmp_image_load_increment(gpointer data,
942                                      const guchar * buf,
943                                      guint size,
944                                      GError **error)
945 {
946         struct bmp_progressive_state *context =
947             (struct bmp_progressive_state *) data;
948
949         gint BytesToCopy;
950
951         if (context->read_state == READ_STATE_DONE)
952                 return TRUE;
953         else if (context->read_state == READ_STATE_ERROR)
954                 return FALSE;
955
956         while (size > 0) {
957                 if (context->BufferDone < context->BufferSize) {        /* We still
958                                                                            have headerbytes to do */
959                         BytesToCopy =
960                             context->BufferSize - context->BufferDone;
961                         if (BytesToCopy > size)
962                                 BytesToCopy = size;
963
964                         memmove(context->buff + context->BufferDone,
965                                 buf, BytesToCopy);
966
967                         size -= BytesToCopy;
968                         buf += BytesToCopy;
969                         context->BufferDone += BytesToCopy;
970
971                         if (context->BufferDone != context->BufferSize)
972                                 break;
973                 }
974
975                 switch (context->read_state) {
976                 case READ_STATE_HEADERS:
977                         if (!DecodeHeader (context->buff,
978                                            context->buff + 14, context,
979                                            error))
980                                 return FALSE;
981
982                         break;
983
984                 case READ_STATE_PALETTE:
985                         DecodeColormap (context->buff, context, error);
986                         break;
987
988                 case READ_STATE_BITMASKS:
989                         decode_bitmasks (context, context->buff);
990                         break;
991
992                 case READ_STATE_DATA:
993                         if (context->Compressed == BI_RGB || context->Compressed == BI_BITFIELDS)
994                                 OneLine (context);
995                         else
996                                 DoCompressed (context);
997
998                         break;
999
1000                 default:
1001                         g_assert_not_reached ();
1002                 }
1003         }
1004
1005         return TRUE;
1006 }
1007
1008 void
1009 gdk_pixbuf__bmp_fill_vtable (GdkPixbufModule *module)
1010 {
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;
1015 }