]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-bmp.c
[quartz] Delete the typedef of GdkDevicePrivate
[~andy/gtk] / gdk-pixbuf / io-bmp.c
1 /* -*- mode: C; c-file-style: "linux" -*- */
2 /* GdkPixbuf library - Windows Bitmap image loader
3  *
4  * Copyright (C) 1999 The Free Software Foundation
5  *
6  * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
7  *          Federico Mena-Quintero <federico@gimp.org>
8  *
9  * Based on io-ras.c
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  */
26
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <string.h>
33 #include "gdk-pixbuf-private.h"
34 #include "gdk-pixbuf-io.h"
35
36 #define DUMPBIH 0
37
38 \f
39
40 #if 0
41 /* If these structures were unpacked, they would define the two headers of the
42  * BMP file.  After them comes the palette, and then the image data.
43  *
44  * We do not use these structures; we just keep them here for reference.
45  */
46 struct BitmapFileHeader {
47         guint16 magic;
48         guint32 file_size;
49         guint32 reserved;
50         guint32 data_offset;
51 };
52
53 struct BitmapInfoHeader {
54         guint32 header_size;
55         guint32 width;
56         guint32 height;
57         guint16 planes;
58         guint16 bpp;
59         guint32 compression;
60         guint32 data_size;
61         guint32 x_ppm;
62         guint32 y_ppm;
63         guint32 n_colors;
64         guint32 n_important_colors;
65 };
66 #endif
67
68 /* Compression values */
69
70 #define BI_RGB 0
71 #define BI_RLE8 1
72 #define BI_RLE4 2
73 #define BI_BITFIELDS 3
74
75 /* State machine */
76 typedef enum {
77         READ_STATE_HEADERS,     /* Reading the bitmap file header and bitmap info header */
78         READ_STATE_PALETTE,     /* Reading the palette */
79         READ_STATE_BITMASKS,    /* Reading the bitmasks for BI_BITFIELDS */
80         READ_STATE_DATA,        /* Reading the actual image data */
81         READ_STATE_ERROR,       /* An error occurred; further data will be ignored */
82         READ_STATE_DONE         /* Done reading the image; further data will be ignored */
83 } ReadState;
84
85 /*
86
87 DumpBIH printf's the values in a BitmapInfoHeader to the screen, for
88 debugging purposes.
89
90 */
91 #if DUMPBIH
92 static void DumpBIH(unsigned char *BIH)
93 {
94         printf("biSize      = %i \n",
95                (int) (BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) +
96                (BIH[0]));
97         printf("biWidth     = %i \n",
98                (int) (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) +
99                (BIH[4]));
100         printf("biHeight    = %i \n",
101                (int) (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
102                (BIH[8]));
103         printf("biPlanes    = %i \n", (int) (BIH[13] << 8) + (BIH[12]));
104         printf("biBitCount  = %i \n", (int) (BIH[15] << 8) + (BIH[14]));
105         printf("biCompress  = %i \n",
106                (int) (BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
107                (BIH[16]));
108         printf("biSizeImage = %i \n",
109                (int) (BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
110                (BIH[20]));
111         printf("biXPels     = %i \n",
112                (int) (BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
113                (BIH[24]));
114         printf("biYPels     = %i \n",
115                (int) (BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
116                (BIH[28]));
117         printf("biClrUsed   = %i \n",
118                (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
119                (BIH[32]));
120         printf("biClrImprtnt= %i \n",
121                (int) (BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
122                (BIH[36]));
123 }
124 #endif
125 /* struct headerpair contains the decoded width/height/depth info for
126    the current bitmap */
127
128 struct headerpair {
129         guint32 size;
130         gint32 width;
131         gint32 height;
132         guint depth;
133         guint Negative;         /* Negative = 1 -> top down BMP,
134                                    Negative = 0 -> bottom up BMP */
135         guint  n_colors;
136 };
137
138 /* Data needed for the "state" during decompression */
139 struct bmp_compression_state {
140         gint phase;
141         gint run;
142         gint count;
143         gint x, y;
144         guchar *p;
145 };
146
147 /* Progressive loading */
148
149 struct bmp_progressive_state {
150         GdkPixbufModuleSizeFunc size_func;
151         GdkPixbufModulePreparedFunc prepared_func;
152         GdkPixbufModuleUpdatedFunc updated_func;
153         gpointer user_data;
154
155         ReadState read_state;
156
157         guint LineWidth;
158         guint Lines;            /* # of finished lines */
159
160         guchar *buff;
161         guint BufferSize;
162         guint BufferPadding;
163         guint BufferDone;
164
165         guchar (*Colormap)[3];
166
167         gint Type;              /*
168                                    32 = RGB + alpha
169                                    24 = RGB
170                                    16 = RGB
171                                    4  = 4 bpp colormapped
172                                    8  = 8 bpp colormapped
173                                    1  = 1 bit bitonal
174                                  */
175         guint Compressed;
176         struct bmp_compression_state compr;
177
178
179         struct headerpair Header;       /* Decoded (BE->CPU) header */
180
181         /* Bit masks, shift amounts, and significant bits for BI_BITFIELDS coding */
182         int r_mask, r_shift, r_bits;
183         int g_mask, g_shift, g_bits;
184         int b_mask, b_shift, b_bits;
185         int a_mask, a_shift, a_bits;
186
187         GdkPixbuf *pixbuf;      /* Our "target" */
188 };
189
190 static gpointer
191 gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
192                                  GdkPixbufModulePreparedFunc prepared_func,
193                                  GdkPixbufModuleUpdatedFunc updated_func,
194                                  gpointer user_data,
195                                  GError **error);
196
197 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
198 static gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data,
199                                                      const guchar * buf,
200                                                      guint size,
201                                                      GError **error);
202
203
204 /* Picks up a 32-bit little-endian integer starting at the specified location.
205  * Does it by hand instead of dereferencing a simple (gint *) cast due to
206  * alignment constraints many platforms.
207  */
208 static int
209 lsb_32 (guchar *src)
210 {
211         return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
212 }
213
214 /* Same as above, but for 16-bit little-endian integers. */
215 static short
216 lsb_16 (guchar *src)
217 {
218         return src[0] | (src[1] << 8);
219 }
220
221 static gboolean grow_buffer (struct bmp_progressive_state *State,
222                              GError **error)
223 {
224   guchar *tmp;
225
226   if (State->BufferSize == 0) {
227     g_set_error_literal (error,
228                          GDK_PIXBUF_ERROR,
229                          GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
230                          _("BMP image has bogus header data"));
231     State->read_state = READ_STATE_ERROR;
232     return FALSE;
233   }
234
235   tmp = g_try_realloc (State->buff, State->BufferSize);
236
237   if (!tmp) {
238     g_set_error_literal (error,
239                          GDK_PIXBUF_ERROR,
240                          GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
241                          _("Not enough memory to load bitmap image"));
242     State->read_state = READ_STATE_ERROR;
243     return FALSE;
244   }
245
246   State->buff = tmp;
247   return TRUE;
248 }
249
250 static gboolean
251 decode_bitmasks (guchar *buf,
252                  struct bmp_progressive_state *State, 
253                  GError **error);
254
255 static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
256                              struct bmp_progressive_state *State,
257                              GError **error)
258 {
259         gint clrUsed;
260
261         /* First check for the two first bytes content. A sane
262            BMP file must start with bytes 0x42 0x4D.  */
263         if (*BFH != 0x42 || *(BFH + 1) != 0x4D) {
264                 g_set_error_literal (error,
265                                      GDK_PIXBUF_ERROR,
266                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
267                                      _("BMP image has bogus header data"));
268                 State->read_state = READ_STATE_ERROR;
269                 return FALSE;
270         }
271
272         /* FIXME this is totally unrobust against bogus image data. */
273         if (State->BufferSize < lsb_32 (&BIH[0]) + 14) {
274                 State->BufferSize = lsb_32 (&BIH[0]) + 14;
275                 if (!grow_buffer (State, error))
276                         return FALSE;
277                 return TRUE;
278         }
279
280 #if DUMPBIH
281         DumpBIH(BIH);
282 #endif    
283
284         State->Header.size = lsb_32 (&BIH[0]);
285         if (State->Header.size == 124) {
286                 /* BMP v5 */
287                 State->Header.width = lsb_32 (&BIH[4]);
288                 State->Header.height = lsb_32 (&BIH[8]);
289                 State->Header.depth = lsb_16 (&BIH[14]);
290                 State->Compressed = lsb_32 (&BIH[16]);
291         } else if (State->Header.size == 108) {
292                 /* BMP v4 */
293                 State->Header.width = lsb_32 (&BIH[4]);
294                 State->Header.height = lsb_32 (&BIH[8]);
295                 State->Header.depth = lsb_16 (&BIH[14]);
296                 State->Compressed = lsb_32 (&BIH[16]);
297         } else if (State->Header.size == 64) {
298                 /* BMP OS/2 v2 */
299                 State->Header.width = lsb_32 (&BIH[4]);
300                 State->Header.height = lsb_32 (&BIH[8]);
301                 State->Header.depth = lsb_16 (&BIH[14]);
302                 State->Compressed = lsb_32 (&BIH[16]);
303         } else if (State->Header.size == 40) {
304                 /* BMP v3 */ 
305                 State->Header.width = lsb_32 (&BIH[4]);
306                 State->Header.height = lsb_32 (&BIH[8]);
307                 State->Header.depth = lsb_16 (&BIH[14]);
308                 State->Compressed = lsb_32 (&BIH[16]);
309         } else if (State->Header.size == 12) {
310                 /* BMP OS/2 */
311                 State->Header.width = lsb_16 (&BIH[4]);
312                 State->Header.height = lsb_16 (&BIH[6]);
313                 State->Header.depth = lsb_16 (&BIH[10]);
314                 State->Compressed = BI_RGB;
315         } else {
316                 g_set_error_literal (error,
317                                      GDK_PIXBUF_ERROR,
318                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
319                                      _("BMP image has unsupported header size"));
320                 State->read_state = READ_STATE_ERROR;
321                 return FALSE;
322         }
323
324         if (State->Header.size == 12)
325                 clrUsed = 1 << State->Header.depth;
326         else
327                 clrUsed = (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
328
329         if (clrUsed != 0)
330                 State->Header.n_colors = clrUsed;
331         else
332             State->Header.n_colors = (1 << State->Header.depth);
333         
334         if (State->Header.n_colors > (1 << State->Header.depth)) {
335                 g_set_error_literal (error,
336                                      GDK_PIXBUF_ERROR,
337                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
338                                      _("BMP image has bogus header data"));
339                 State->read_state = READ_STATE_ERROR;
340                 return FALSE;
341         }
342
343         State->Type = State->Header.depth;      /* This may be less trivial someday */
344
345         /* Negative heights indicates bottom-down pixelorder */
346         if (State->Header.height < 0) {
347                 State->Header.height = -State->Header.height;
348                 State->Header.Negative = 1;
349         }
350
351         if (State->Header.Negative && 
352             (State->Compressed != BI_RGB && State->Compressed != BI_BITFIELDS))
353         {
354                 g_set_error_literal (error,
355                                      GDK_PIXBUF_ERROR,
356                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
357                                      _("Topdown BMP images cannot be compressed"));
358                 State->read_state = READ_STATE_ERROR;
359                 return FALSE;
360         }
361
362         if (State->Header.width <= 0 || State->Header.height == 0 ||
363             (State->Compressed == BI_RLE4 && State->Type != 4)    ||
364             (State->Compressed == BI_RLE8 && State->Type != 8)    ||
365             (State->Compressed == BI_BITFIELDS && !(State->Type == 16 || State->Type == 32)) ||
366             (State->Compressed > BI_BITFIELDS)) {
367                 g_set_error_literal (error,
368                                      GDK_PIXBUF_ERROR,
369                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
370                                      _("BMP image has bogus header data"));
371                 State->read_state = READ_STATE_ERROR;
372                 return FALSE;
373         }
374
375         if (State->Type == 32)
376                 State->LineWidth = State->Header.width * 4;
377         else if (State->Type == 24)
378                 State->LineWidth = State->Header.width * 3;
379         else if (State->Type == 16)
380                 State->LineWidth = State->Header.width * 2;
381         else if (State->Type == 8)
382                 State->LineWidth = State->Header.width * 1;
383         else if (State->Type == 4)
384                 State->LineWidth = (State->Header.width + 1) / 2;
385         else if (State->Type == 1) {
386                 State->LineWidth = State->Header.width / 8;
387                 if ((State->Header.width & 7) != 0)
388                         State->LineWidth++;
389         } else {
390                 g_set_error_literal (error,
391                                      GDK_PIXBUF_ERROR,
392                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
393                                      _("BMP image has bogus header data"));
394                 State->read_state = READ_STATE_ERROR;
395                 return FALSE;
396         }
397
398         /* Pad to a 32 bit boundary */
399         if (((State->LineWidth % 4) > 0)
400             && (State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
401                 State->LineWidth = (State->LineWidth / 4) * 4 + 4;
402
403         if (State->pixbuf == NULL) {
404                 if (State->size_func) {
405                         gint width = State->Header.width;
406                         gint height = State->Header.height;
407
408                         (*State->size_func) (&width, &height, State->user_data);
409                         if (width == 0 || height == 0) {
410                                 State->read_state = READ_STATE_DONE;
411                                 State->BufferSize = 0;
412                                 return TRUE;
413                         }
414                 }
415
416                 if (State->Type == 32 || 
417                     State->Compressed == BI_RLE4 || 
418                     State->Compressed == BI_RLE8)
419                         State->pixbuf =
420                                 gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
421                                                (gint) State->Header.width,
422                                                (gint) State->Header.height);
423                 else
424                         State->pixbuf =
425                                 gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
426                                                (gint) State->Header.width,
427                                                (gint) State->Header.height);
428                 
429                 if (State->pixbuf == NULL) {
430                         g_set_error_literal (error,
431                                              GDK_PIXBUF_ERROR,
432                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
433                                              _("Not enough memory to load bitmap image"));
434                         State->read_state = READ_STATE_ERROR;
435                         return FALSE;
436                         }
437                 
438                 if (State->prepared_func != NULL)
439                         /* Notify the client that we are ready to go */
440                         (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
441                 
442                 /* make all pixels initially transparent */
443                 if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
444                         memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
445                         State->compr.p = State->pixbuf->pixels 
446                                 + State->pixbuf->rowstride * (State->Header.height- 1);
447                 }
448         }
449         
450         State->BufferDone = 0;
451         if (State->Type <= 8) {
452                 gint samples;
453
454                 State->read_state = READ_STATE_PALETTE;
455
456                 /* Allocate enough to hold the palette */
457                 samples = (State->Header.size == 12 ? 3 : 4);
458                 State->BufferSize = State->Header.n_colors * samples;
459
460                 /* Skip over everything between the palette and the data.
461                    This protects us against a malicious BFH[10] value.
462                 */
463                 State->BufferPadding = (lsb_32 (&BFH[10]) - 14 - State->Header.size) - State->BufferSize;
464
465         } else if (State->Compressed == BI_RGB) {
466                 if (State->BufferSize < lsb_32 (&BFH[10]))
467                 {
468                         /* skip over padding between headers and image data */
469                         State->read_state = READ_STATE_HEADERS;
470                         State->BufferDone = State->BufferSize;
471                         State->BufferSize = lsb_32 (&BFH[10]);
472                 }
473                 else
474                 {
475                         State->read_state = READ_STATE_DATA;
476                         State->BufferSize = State->LineWidth;
477                 }
478         } else if (State->Compressed == BI_BITFIELDS) {
479                if (State->Header.size == 108 || State->Header.size == 124) 
480                {
481                         /* v4 and v5 have the bitmasks in the header */
482                         if (!decode_bitmasks (&BIH[40], State, error)) {
483                                State->read_state = READ_STATE_ERROR;
484                                return FALSE;
485                         }
486                }
487                else 
488                {
489                        State->read_state = READ_STATE_BITMASKS;
490                        State->BufferSize = 12;
491                }
492         } else {
493                 g_set_error_literal (error,
494                                      GDK_PIXBUF_ERROR,
495                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
496                                      _("BMP image has bogus header data"));
497                 State->read_state = READ_STATE_ERROR;
498                 return FALSE;
499         }
500
501         if (!grow_buffer (State, error)) 
502                 return FALSE;
503
504         return TRUE;
505 }
506
507 static gboolean DecodeColormap (guchar *buff,
508                                 struct bmp_progressive_state *State,
509                                 GError **error)
510 {
511         gint i;
512         gint samples;
513
514         g_assert (State->read_state == READ_STATE_PALETTE);
515
516         samples = (State->Header.size == 12 ? 3 : 4);
517         if (State->BufferSize < State->Header.n_colors * samples) {
518                 State->BufferSize = State->Header.n_colors * samples;
519                 if (!grow_buffer (State, error))
520                         return FALSE;
521                 return TRUE;
522         }
523
524         State->Colormap = g_malloc0 ((1 << State->Header.depth) * sizeof (*State->Colormap));
525         for (i = 0; i < State->Header.n_colors; i++)
526
527         {
528                 State->Colormap[i][0] = buff[i * samples];
529                 State->Colormap[i][1] = buff[i * samples + 1];
530                 State->Colormap[i][2] = buff[i * samples + 2];
531 #ifdef DUMPCMAP
532                 g_print ("color %d %x %x %x\n", i,
533                          State->Colormap[i][0],
534                          State->Colormap[i][1],
535                          State->Colormap[i][2]);
536 #endif
537         }
538
539         State->read_state = READ_STATE_DATA;
540
541         State->BufferDone = 0;
542         if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
543                 State->BufferSize = 2;
544         else
545                 State->BufferSize = State->LineWidth;
546         
547         if (!grow_buffer (State, error))
548                 return FALSE;
549
550         return TRUE;
551 }
552
553 /* Finds the lowest set bit and the number of set bits */
554 static void
555 find_bits (int n, int *lowest, int *n_set)
556 {
557         int i;
558
559         *n_set = 0;
560
561         for (i = 31; i >= 0; i--)
562                 if (n & (1 << i)) {
563                         *lowest = i;
564                         (*n_set)++;
565                 }
566 }
567
568 /* Decodes the bitmasks for BI_BITFIELDS coding */
569 static gboolean
570 decode_bitmasks (guchar *buf,
571                  struct bmp_progressive_state *State, 
572                  GError **error)
573 {
574         State->a_mask = State->a_shift = State->a_bits = 0;
575         State->r_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
576         buf += 4;
577
578         State->g_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
579         buf += 4;
580
581         State->b_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
582
583         find_bits (State->r_mask, &State->r_shift, &State->r_bits);
584         find_bits (State->g_mask, &State->g_shift, &State->g_bits);
585         find_bits (State->b_mask, &State->b_shift, &State->b_bits);
586
587         /* v4 and v5 have an alpha mask */
588         if (State->Header.size == 108 || State->Header.size == 124) {
589               buf += 4;
590               State->a_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
591               find_bits (State->a_mask, &State->a_shift, &State->a_bits);
592         }
593
594         if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
595                 if (State->Type == 16) {
596                        State->r_mask = 0x7c00;
597                        State->r_shift = 10;
598                        State->g_mask = 0x03e0;
599                        State->g_shift = 5;
600                        State->b_mask = 0x001f;
601                        State->b_shift = 0;
602
603                        State->r_bits = State->g_bits = State->b_bits = 5;
604                 }
605                 else {
606                        State->r_mask = 0x00ff0000;
607                        State->r_shift = 16;
608                        State->g_mask = 0x0000ff00;
609                        State->g_shift = 8;
610                        State->b_mask = 0x000000ff;
611                        State->b_shift = 0;
612                        State->a_mask = 0xff000000;
613                        State->a_shift = 24;
614
615                        State->r_bits = State->g_bits = State->b_bits = State->a_bits = 8;
616                 }
617         }
618
619         if (State->r_bits > 8) {
620           State->r_shift += State->r_bits - 8;
621           State->r_bits = 8;
622         }
623         if (State->g_bits > 8) {
624           State->g_shift += State->g_bits - 8;
625           State->g_bits = 8;
626         }
627         if (State->b_bits > 8) {
628           State->b_shift += State->b_bits - 8;
629           State->b_bits = 8;
630         }
631         if (State->a_bits > 8) {
632           State->a_shift += State->a_bits - 8;
633           State->a_bits = 8;
634         }
635
636         State->read_state = READ_STATE_DATA;
637         State->BufferDone = 0;
638         State->BufferSize = State->LineWidth;
639         if (!grow_buffer (State, error)) 
640                 return FALSE;
641
642         return TRUE;
643 }
644
645 /*
646  * func - called when we have pixmap created (but no image data)
647  * user_data - passed as arg 1 to func
648  * return context (opaque to user)
649  */
650
651 static gpointer
652 gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
653                                  GdkPixbufModulePreparedFunc prepared_func,
654                                  GdkPixbufModuleUpdatedFunc updated_func,
655                                  gpointer user_data,
656                                  GError **error)
657 {
658         struct bmp_progressive_state *context;
659         
660         context = g_new0(struct bmp_progressive_state, 1);
661         context->size_func = size_func;
662         context->prepared_func = prepared_func;
663         context->updated_func = updated_func;
664         context->user_data = user_data;
665
666         context->read_state = READ_STATE_HEADERS;
667
668         context->BufferSize = 26;
669         context->BufferPadding = 0;
670         context->buff = g_malloc(26);
671         context->BufferDone = 0;
672         /* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
673
674         context->Colormap = NULL;
675
676         context->Lines = 0;
677
678         context->Type = 0;
679
680         memset(&context->Header, 0, sizeof(struct headerpair));
681         memset(&context->compr, 0, sizeof(struct bmp_compression_state));
682
683
684         context->pixbuf = NULL;
685         
686         return (gpointer) context;
687 }
688
689 /*
690  * context - returned from image_begin_load
691  *
692  * free context, unref gdk_pixbuf
693  */
694 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
695 {
696         gboolean retval = TRUE;
697         
698         struct bmp_progressive_state *context =
699             (struct bmp_progressive_state *) data;
700
701         /* FIXME this thing needs to report errors if
702          * we have unused image data
703          */
704         
705         g_return_val_if_fail(context != NULL, TRUE);
706
707         g_free(context->Colormap);
708
709         if (context->pixbuf)
710                 g_object_unref(context->pixbuf);
711
712         if (context->read_state == READ_STATE_HEADERS) {
713                 if (error && *error == NULL) {
714                         g_set_error_literal (error,
715                                              GDK_PIXBUF_ERROR,
716                                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
717                                              _("Premature end-of-file encountered"));
718                 }
719                 retval = FALSE;
720         }
721         
722         g_free(context->buff);
723         g_free(context);
724
725         return retval;
726 }
727
728
729 /*
730 The OneLineXX functions are called when 1 line worth of data is present.
731 OneLine24 is the 24 bpp-version.
732 */
733 static void OneLine32(struct bmp_progressive_state *context)
734 {
735         int i;
736         guchar *pixels;
737         guchar *src;
738
739         if (!context->Header.Negative)
740                 pixels = (context->pixbuf->pixels +
741                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
742         else
743                 pixels = (context->pixbuf->pixels +
744                           context->pixbuf->rowstride * context->Lines);
745
746         src = context->buff;
747
748         if (context->Compressed == BI_BITFIELDS) {
749                 int r_lshift, r_rshift;
750                 int g_lshift, g_rshift;
751                 int b_lshift, b_rshift;
752                 int a_lshift, a_rshift;
753
754                 r_lshift = 8 - context->r_bits;
755                 g_lshift = 8 - context->g_bits;
756                 b_lshift = 8 - context->b_bits;
757                 a_lshift = 8 - context->a_bits;
758
759                 r_rshift = context->r_bits - r_lshift;
760                 g_rshift = context->g_bits - g_lshift;
761                 b_rshift = context->b_bits - b_lshift;
762                 a_rshift = context->a_bits - a_lshift;
763
764                 for (i = 0; i < context->Header.width; i++) {
765                         unsigned int v, r, g, b, a;
766
767                         v = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
768
769                         r = (v & context->r_mask) >> context->r_shift;
770                         g = (v & context->g_mask) >> context->g_shift;
771                         b = (v & context->b_mask) >> context->b_shift;
772                         a = (v & context->a_mask) >> context->a_shift;
773
774                         *pixels++ = (r << r_lshift) | (r >> r_rshift);
775                         *pixels++ = (g << g_lshift) | (g >> g_rshift);
776                         *pixels++ = (b << b_lshift) | (b >> b_rshift);
777                         if (context->a_bits)
778                           *pixels++ = (a << a_lshift) | (a >> a_rshift);
779                         else
780                           *pixels++ = 0xff;
781
782                         src += 4;
783                 }
784         } else
785                 for (i = 0; i < context->Header.width; i++) {
786                         *pixels++ = src[2];
787                         *pixels++ = src[1];
788                         *pixels++ = src[0];
789                         *pixels++ = 0xff;
790
791                         src += 4;
792                 }
793 }
794
795 static void OneLine24(struct bmp_progressive_state *context)
796 {
797         gint X;
798         guchar *Pixels;
799
800         X = 0;
801         if (context->Header.Negative == 0)
802                 Pixels = (context->pixbuf->pixels +
803                           context->pixbuf->rowstride *
804                           (context->Header.height - context->Lines - 1));
805         else
806                 Pixels = (context->pixbuf->pixels +
807                           context->pixbuf->rowstride *
808                           context->Lines);
809         while (X < context->Header.width) {
810                 Pixels[X * 3 + 0] = context->buff[X * 3 + 2];
811                 Pixels[X * 3 + 1] = context->buff[X * 3 + 1];
812                 Pixels[X * 3 + 2] = context->buff[X * 3 + 0];
813                 X++;
814         }
815
816 }
817
818 static void OneLine16(struct bmp_progressive_state *context)
819 {
820         int i;
821         guchar *pixels;
822         guchar *src;
823
824         if (!context->Header.Negative)
825                 pixels = (context->pixbuf->pixels +
826                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
827         else
828                 pixels = (context->pixbuf->pixels +
829                           context->pixbuf->rowstride * context->Lines);
830
831         src = context->buff;
832
833         if (context->Compressed == BI_BITFIELDS) {
834                 int r_lshift, r_rshift;
835                 int g_lshift, g_rshift;
836                 int b_lshift, b_rshift;
837
838                 r_lshift = 8 - context->r_bits;
839                 g_lshift = 8 - context->g_bits;
840                 b_lshift = 8 - context->b_bits;
841
842                 r_rshift = context->r_bits - r_lshift;
843                 g_rshift = context->g_bits - g_lshift;
844                 b_rshift = context->b_bits - b_lshift;
845
846                 for (i = 0; i < context->Header.width; i++) {
847                         int v, r, g, b;
848
849                         v = (int) src[0] | ((int) src[1] << 8);
850
851                         r = (v & context->r_mask) >> context->r_shift;
852                         g = (v & context->g_mask) >> context->g_shift;
853                         b = (v & context->b_mask) >> context->b_shift;
854
855                         *pixels++ = (r << r_lshift) | (r >> r_rshift);
856                         *pixels++ = (g << g_lshift) | (g >> g_rshift);
857                         *pixels++ = (b << b_lshift) | (b >> b_rshift);
858
859                         src += 2;
860                 }
861         } else
862                 for (i = 0; i < context->Header.width; i++) {
863                         int v, r, g, b;
864
865                         v = src[0] | (src[1] << 8);
866
867                         r = (v >> 10) & 0x1f;
868                         g = (v >> 5) & 0x1f;
869                         b = v & 0x1f;
870
871                         *pixels++ = (r << 3) | (r >> 2);
872                         *pixels++ = (g << 3) | (g >> 2);
873                         *pixels++ = (b << 3) | (b >> 2);
874
875                         src += 2;
876                 }
877 }
878
879 static void OneLine8(struct bmp_progressive_state *context)
880 {
881         gint X;
882         guchar *Pixels;
883
884         X = 0;
885         if (context->Header.Negative == 0)
886                 Pixels = (context->pixbuf->pixels +
887                           context->pixbuf->rowstride *
888                           (context->Header.height - context->Lines - 1));
889         else
890                 Pixels = (context->pixbuf->pixels +
891                           context->pixbuf->rowstride *
892                           context->Lines);
893         while (X < context->Header.width) {
894                 Pixels[X * 3 + 0] =
895                     context->Colormap[context->buff[X]][2];
896                 Pixels[X * 3 + 1] =
897                     context->Colormap[context->buff[X]][1];
898                 Pixels[X * 3 + 2] =
899                     context->Colormap[context->buff[X]][0];
900                 X++;
901         }
902 }
903
904 static void OneLine4(struct bmp_progressive_state *context)
905 {
906         gint X;
907         guchar *Pixels;
908
909         X = 0;
910         if (context->Header.Negative == 0)
911                 Pixels = (context->pixbuf->pixels +
912                           context->pixbuf->rowstride *
913                           (context->Header.height - context->Lines - 1));
914         else
915                 Pixels = (context->pixbuf->pixels +
916                           context->pixbuf->rowstride *
917                           context->Lines);
918
919         while (X < context->Header.width) {
920                 guchar Pix;
921
922                 Pix = context->buff[X / 2];
923
924                 Pixels[X * 3 + 0] =
925                     context->Colormap[Pix >> 4][2];
926                 Pixels[X * 3 + 1] =
927                     context->Colormap[Pix >> 4][1];
928                 Pixels[X * 3 + 2] =
929                     context->Colormap[Pix >> 4][0];
930                 X++;
931                 if (X < context->Header.width) {
932                         /* Handle the other 4 bit pixel only when there is one */
933                         Pixels[X * 3 + 0] =
934                             context->Colormap[Pix & 15][2];
935                         Pixels[X * 3 + 1] =
936                             context->Colormap[Pix & 15][1];
937                         Pixels[X * 3 + 2] =
938                             context->Colormap[Pix & 15][0];
939                         X++;
940                 }
941         }
942
943 }
944
945 static void OneLine1(struct bmp_progressive_state *context)
946 {
947         gint X;
948         guchar *Pixels;
949
950         X = 0;
951         if (context->Header.Negative == 0)
952                 Pixels = (context->pixbuf->pixels +
953                           context->pixbuf->rowstride *
954                           (context->Header.height - context->Lines - 1));
955         else
956                 Pixels = (context->pixbuf->pixels +
957                           context->pixbuf->rowstride *
958                           context->Lines);
959         while (X < context->Header.width) {
960                 gint Bit;
961
962                 Bit = (context->buff[X / 8]) >> (7 - (X & 7));
963                 Bit = Bit & 1;
964                 Pixels[X * 3 + 0] = context->Colormap[Bit][2];
965                 Pixels[X * 3 + 1] = context->Colormap[Bit][1];
966                 Pixels[X * 3 + 2] = context->Colormap[Bit][0];
967                 X++;
968         }
969 }
970
971
972 static void OneLine(struct bmp_progressive_state *context)
973 {
974         context->BufferDone = 0;
975         if (context->Lines >= context->Header.height)
976                 return;
977
978         if (context->Type == 32)
979                 OneLine32(context);
980         else if (context->Type == 24)
981                 OneLine24(context);
982         else if (context->Type == 16)
983                 OneLine16(context);
984         else if (context->Type == 8)
985                 OneLine8(context);
986         else if (context->Type == 4)
987                 OneLine4(context);
988         else if (context->Type == 1)
989                 OneLine1(context);
990         else
991                 g_assert_not_reached ();
992
993         context->Lines++;
994
995         if (context->updated_func != NULL) {
996                 (*context->updated_func) (context->pixbuf,
997                                           0,
998                                           (context->Header.Negative ?
999                                            (context->Lines - 1) :
1000                                            (context->Header.height - context->Lines)),
1001                                           context->Header.width,
1002                                           1,
1003                                           context->user_data);
1004
1005         }
1006 }
1007
1008 #define NEUTRAL       0
1009 #define ENCODED       1
1010 #define ESCAPE        2   
1011 #define DELTA_X       3
1012 #define DELTA_Y       4
1013 #define ABSOLUTE      5
1014 #define SKIP          6
1015
1016 #define END_OF_LINE   0
1017 #define END_OF_BITMAP 1
1018 #define DELTA         2
1019
1020 static gboolean 
1021 DoCompressed(struct bmp_progressive_state *context, GError **error)
1022 {
1023         gint i, j;
1024         gint y;
1025         guchar c;
1026         gint idx;
1027
1028         /* context->compr.y might be past the last line because we are
1029          * on padding past the end of a valid data, or we might have hit
1030          * out-of-bounds data. Either way we just eat-and-ignore the
1031          * rest of the file. Doing the check only here and not when
1032          * we change y below is fine since BufferSize is always 2 here
1033          * and the BMP file format always starts new data on 16-bit
1034          * boundaries.
1035          */
1036         if (context->compr.y >= context->Header.height) {
1037                 context->BufferDone = 0;
1038                 return TRUE;
1039         }
1040
1041         y = context->compr.y;
1042
1043         for (i = 0; i < context->BufferSize; i++) {
1044                 c = context->buff[i];
1045                 switch (context->compr.phase) {
1046                     case NEUTRAL:
1047                             if (c) {
1048                                     context->compr.run = c;
1049                                     context->compr.phase = ENCODED;
1050                             }
1051                             else
1052                                     context->compr.phase = ESCAPE;
1053                             break;
1054                     case ENCODED:
1055                             for (j = 0; j < context->compr.run; j++) {
1056                                     if (context->Compressed == BI_RLE8)
1057                                             idx = c;
1058                                     else if (j & 1) 
1059                                             idx = c & 0x0f;
1060                                     else 
1061                                             idx = (c >> 4) & 0x0f;
1062                                     if (context->compr.x < context->Header.width) {
1063                                             *context->compr.p++ = context->Colormap[idx][2];
1064                                             *context->compr.p++ = context->Colormap[idx][1];
1065                                             *context->compr.p++ = context->Colormap[idx][0];
1066                                             *context->compr.p++ = 0xff;
1067                                             context->compr.x++;    
1068                                     }
1069                             }
1070                             context->compr.phase = NEUTRAL;
1071                             break;
1072                     case ESCAPE:
1073                             switch (c) {
1074                                 case END_OF_LINE:
1075                                         context->compr.x = 0;
1076                                         context->compr.y++;
1077                                         context->compr.p = context->pixbuf->pixels 
1078                                                 + (context->pixbuf->rowstride * (context->Header.height - context->compr.y - 1))
1079                                                 + (4 * context->compr.x);
1080                                         context->compr.phase = NEUTRAL;
1081                                         break;
1082                                 case END_OF_BITMAP:
1083                                         context->compr.x = 0;
1084                                         context->compr.y = context->Header.height;
1085                                         context->compr.phase = NEUTRAL;
1086                                         break;
1087                                 case DELTA:
1088                                         context->compr.phase = DELTA_X;
1089                                         break;
1090                                 default:
1091                                         context->compr.run = c;
1092                                         context->compr.count = 0;
1093                                         context->compr.phase = ABSOLUTE;
1094                                         break;
1095                             }
1096                             break;
1097                     case DELTA_X:
1098                             context->compr.x += c;
1099                             context->compr.phase = DELTA_Y;
1100                             break;
1101                     case DELTA_Y:
1102                             context->compr.y += c;
1103                             context->compr.p = context->pixbuf->pixels 
1104                                     + (context->pixbuf->rowstride * (context->Header.height - context->compr.y - 1))
1105                                     + (4 * context->compr.x);
1106                             context->compr.phase = NEUTRAL;
1107                             break;
1108                     case ABSOLUTE:
1109                             if (context->Compressed == BI_RLE8) {
1110                                     idx = c;
1111                                     if (context->compr.x < context->Header.width) {
1112                                             *context->compr.p++ = context->Colormap[idx][2];
1113                                             *context->compr.p++ = context->Colormap[idx][1];
1114                                             *context->compr.p++ = context->Colormap[idx][0];
1115                                             *context->compr.p++ = 0xff;
1116                                             context->compr.x++;    
1117                                     }
1118                                     context->compr.count++;
1119
1120                                     if (context->compr.count == context->compr.run) {
1121                                             if (context->compr.run & 1)
1122                                                     context->compr.phase = SKIP;
1123                                             else
1124                                                     context->compr.phase = NEUTRAL;
1125                                     }
1126                             }
1127                             else {
1128                                     for (j = 0; j < 2; j++) {
1129                                             if (context->compr.count & 1)
1130                                                     idx = c & 0x0f;
1131                                             else 
1132                                                     idx = (c >> 4) & 0x0f;
1133                                             if (context->compr.x < context->Header.width) {
1134                                                     *context->compr.p++ = context->Colormap[idx][2];
1135                                                     *context->compr.p++ = context->Colormap[idx][1];
1136                                                     *context->compr.p++ = context->Colormap[idx][0];
1137                                                     *context->compr.p++ = 0xff;
1138                                                     context->compr.x++;    
1139                                             }
1140                                             context->compr.count++;
1141
1142                                             if (context->compr.count == context->compr.run) {
1143                                                     if ((context->compr.run & 3) == 1
1144                                                         || (context->compr.run & 3) == 2) 
1145                                                             context->compr.phase = SKIP;
1146                                                     else
1147                                                             context->compr.phase = NEUTRAL;
1148                                                     break;
1149                                             }
1150                                     }
1151                             }
1152                             break;
1153                     case SKIP:
1154                             context->compr.phase = NEUTRAL;
1155                             break;
1156                 }
1157         }
1158         if (context->updated_func != NULL) {
1159                 if (context->compr.y > y)
1160                 {
1161                         gint new_y = MIN (context->compr.y, context->Header.height);
1162                         (*context->updated_func) (context->pixbuf,
1163                                                   0,
1164                                                   context->Header.height - new_y,
1165                                                   context->Header.width,
1166                                                   new_y - y,
1167                                                   context->user_data);
1168                 }
1169
1170         }
1171
1172         context->BufferDone = 0;
1173         return TRUE;
1174 }
1175
1176 /*
1177  * context - from image_begin_load
1178  * buf - new image data
1179  * size - length of new image data
1180  *
1181  * append image data onto incrementally built output image
1182  */
1183 static gboolean
1184 gdk_pixbuf__bmp_image_load_increment(gpointer data,
1185                                      const guchar * buf,
1186                                      guint size,
1187                                      GError **error)
1188 {
1189         struct bmp_progressive_state *context =
1190             (struct bmp_progressive_state *) data;
1191
1192         gint BytesToCopy;
1193         gint BytesToRemove;
1194
1195         if (context->read_state == READ_STATE_DONE)
1196                 return TRUE;
1197         else if (context->read_state == READ_STATE_ERROR)
1198                 return FALSE;
1199
1200         while (size > 0) {
1201                 if (context->BufferDone < context->BufferSize) {        /* We still
1202                                                                            have headerbytes to do */
1203                         BytesToCopy =
1204                             context->BufferSize - context->BufferDone;
1205                         if (BytesToCopy > size)
1206                                 BytesToCopy = size;
1207
1208                         memmove(context->buff + context->BufferDone,
1209                                 buf, BytesToCopy);
1210
1211                         size -= BytesToCopy;
1212                         buf += BytesToCopy;
1213                         context->BufferDone += BytesToCopy;
1214
1215                         if (context->BufferDone != context->BufferSize)
1216                                 break;
1217                 }
1218
1219                 /* context->buff is full.  Now we discard all "padding" */
1220                 if (context->BufferPadding != 0) {
1221                         BytesToRemove = context->BufferPadding - size;
1222                         if (BytesToRemove > size) {
1223                                 BytesToRemove = size;
1224                         }
1225                         size -= BytesToRemove;
1226                         context->BufferPadding -= BytesToRemove;
1227
1228                         if (context->BufferPadding != 0)
1229                                 break;
1230                 }
1231
1232                 switch (context->read_state) {
1233                 case READ_STATE_HEADERS:
1234                         if (!DecodeHeader (context->buff,
1235                                            context->buff + 14, context,
1236                                            error))
1237                                 return FALSE;
1238
1239                         break;
1240
1241                 case READ_STATE_PALETTE:
1242                         if (!DecodeColormap (context->buff, context, error))
1243                                 return FALSE;
1244                         break;
1245
1246                 case READ_STATE_BITMASKS:
1247                         if (!decode_bitmasks (context->buff, context, error))
1248                                 return FALSE;
1249                         break;
1250
1251                 case READ_STATE_DATA:
1252                         if (context->Compressed == BI_RGB || context->Compressed == BI_BITFIELDS)
1253                                 OneLine (context);
1254                         else if (!DoCompressed (context, error))
1255                                 return FALSE;
1256
1257                         break;
1258                 case READ_STATE_DONE:
1259                         return TRUE;
1260                         break;
1261
1262                 default:
1263                         g_assert_not_reached ();
1264                 }
1265         }
1266
1267         return TRUE;
1268 }
1269
1270 /* for our convenience when filling file header */
1271 #define put16(buf,data) { guint16 x; \
1272                           x = GUINT16_TO_LE (data); \
1273                           memcpy(buf, &x, 2); \
1274                           buf += 2; }
1275 #define put32(buf,data) { guint32 x; \
1276                           x = GUINT32_TO_LE (data); \
1277                           memcpy(buf, &x, 4); \
1278                           buf += 4; }
1279
1280 static gboolean
1281 gdk_pixbuf__bmp_image_save_to_callback (GdkPixbufSaveFunc   save_func,
1282                                         gpointer            user_data,
1283                                         GdkPixbuf          *pixbuf, 
1284                                         gchar             **keys,
1285                                         gchar             **values,
1286                                         GError            **error)
1287 {
1288         guint width, height, channel, size, stride, src_stride, x, y;
1289         guchar BFH_BIH[54], *pixels, *buf, *src, *dst, *dst_line;
1290         gboolean ret;
1291
1292         width = gdk_pixbuf_get_width (pixbuf);
1293         height = gdk_pixbuf_get_height (pixbuf);
1294         channel = gdk_pixbuf_get_n_channels (pixbuf);
1295         pixels = gdk_pixbuf_get_pixels (pixbuf);
1296         src_stride = gdk_pixbuf_get_rowstride (pixbuf);
1297         stride = (width * 3 + 3) & ~3;
1298         size = stride * height;
1299
1300         /* filling BFH */
1301         dst = BFH_BIH;
1302         *dst++ = 'B';                   /* bfType */
1303         *dst++ = 'M';
1304         put32 (dst, size + 14 + 40);    /* bfSize */
1305         put32 (dst, 0);                 /* bfReserved1 + bfReserved2 */
1306         put32 (dst, 14 + 40);           /* bfOffBits */
1307
1308         /* filling BIH */
1309         put32 (dst, 40);                /* biSize */
1310         put32 (dst, width);             /* biWidth */
1311         put32 (dst, height);            /* biHeight */
1312         put16 (dst, 1);                 /* biPlanes */
1313         put16 (dst, 24);                /* biBitCount */
1314         put32 (dst, BI_RGB);            /* biCompression */
1315         put32 (dst, size);              /* biSizeImage */
1316         put32 (dst, 0);                 /* biXPelsPerMeter */
1317         put32 (dst, 0);                 /* biYPelsPerMeter */
1318         put32 (dst, 0);                 /* biClrUsed */
1319         put32 (dst, 0);                 /* biClrImportant */
1320
1321         if (!save_func ((gchar *)BFH_BIH, 14 + 40, error, user_data))
1322                 return FALSE;
1323
1324         dst_line = buf = g_try_malloc (size);
1325         if (!buf) {
1326                 g_set_error_literal (error,
1327                                      GDK_PIXBUF_ERROR,
1328                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1329                                      _("Couldn't allocate memory for saving BMP file"));
1330                 return FALSE;
1331         }
1332
1333         /* saving as a bottom-up bmp */
1334         pixels += (height - 1) * src_stride;
1335         for (y = 0; y < height; ++y, pixels -= src_stride, dst_line += stride) {
1336                 dst = dst_line;
1337                 src = pixels;
1338                 for (x = 0; x < width; ++x, dst += 3, src += channel) {
1339                         dst[0] = src[2];
1340                         dst[1] = src[1];
1341                         dst[2] = src[0];
1342                 }
1343         }
1344         ret = save_func ((gchar *)buf, size, error, user_data);
1345         g_free (buf);
1346
1347         return ret;
1348 }
1349
1350 static gboolean
1351 save_to_file_cb (const gchar *buf,
1352                  gsize count,
1353                  GError **error,
1354                  gpointer data)
1355 {
1356         gint bytes;
1357         
1358         while (count > 0) {
1359                 bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data);
1360                 if (bytes <= 0)
1361                         break;
1362                 count -= bytes;
1363                 buf += bytes;
1364         }
1365
1366         if (count) {
1367                 g_set_error_literal (error,
1368                                      GDK_PIXBUF_ERROR,
1369                                      GDK_PIXBUF_ERROR_FAILED,
1370                                      _("Couldn't write to BMP file"));
1371                 return FALSE;
1372         }
1373         
1374         return TRUE;
1375 }
1376
1377 static gboolean
1378 gdk_pixbuf__bmp_image_save (FILE          *f, 
1379                             GdkPixbuf     *pixbuf, 
1380                             gchar        **keys,
1381                             gchar        **values,
1382                             GError       **error)
1383 {
1384         return gdk_pixbuf__bmp_image_save_to_callback (save_to_file_cb,
1385                                                        f, pixbuf, keys,
1386                                                        values, error);
1387 }
1388
1389 #ifndef INCLUDE_bmp
1390 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1391 #else
1392 #define MODULE_ENTRY(function) void _gdk_pixbuf__bmp_ ## function
1393 #endif
1394
1395 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1396 {
1397         module->begin_load = gdk_pixbuf__bmp_image_begin_load;
1398         module->stop_load = gdk_pixbuf__bmp_image_stop_load;
1399         module->load_increment = gdk_pixbuf__bmp_image_load_increment;
1400         module->save = gdk_pixbuf__bmp_image_save;
1401         module->save_to_callback = gdk_pixbuf__bmp_image_save_to_callback;
1402 }
1403
1404 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1405 {
1406         static GdkPixbufModulePattern signature[] = {
1407                 { "BM", NULL, 100 },
1408                 { NULL, NULL, 0 }
1409         };
1410         static gchar * mime_types[] = {
1411                 "image/bmp",
1412                 "image/x-bmp",
1413                 "image/x-MS-bmp",
1414                 NULL
1415         };
1416         static gchar * extensions[] = {
1417                 "bmp",
1418                 NULL
1419         };
1420
1421         info->name = "bmp";
1422         info->signature = signature;
1423         info->description = N_("The BMP image format");
1424         info->mime_types = mime_types;
1425         info->extensions = extensions;
1426         info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1427         info->license = "LGPL";
1428 }
1429