]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-bmp.c
Build Wintab support always on Windows. Don't require the Wintab SDK.
[~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 (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 (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         /* FIXME this is totally unrobust against bogus image data. */
262         if (State->BufferSize < lsb_32 (&BIH[0]) + 14) {
263                 State->BufferSize = lsb_32 (&BIH[0]) + 14;
264                 if (!grow_buffer (State, error))
265                         return FALSE;
266                 return TRUE;
267         }
268
269 #if DUMPBIH
270         DumpBIH(BIH);
271 #endif    
272
273         State->Header.size = lsb_32 (&BIH[0]);
274         if (State->Header.size == 124) {
275                 /* BMP v5 */
276                 State->Header.width = lsb_32 (&BIH[4]);
277                 State->Header.height = lsb_32 (&BIH[8]);
278                 State->Header.depth = lsb_16 (&BIH[14]);
279                 State->Compressed = lsb_32 (&BIH[16]);
280         } else if (State->Header.size == 108) {
281                 /* BMP v4 */
282                 State->Header.width = lsb_32 (&BIH[4]);
283                 State->Header.height = lsb_32 (&BIH[8]);
284                 State->Header.depth = lsb_16 (&BIH[14]);
285                 State->Compressed = lsb_32 (&BIH[16]);
286         } else if (State->Header.size == 64) {
287                 /* BMP OS/2 v2 */
288                 State->Header.width = lsb_32 (&BIH[4]);
289                 State->Header.height = lsb_32 (&BIH[8]);
290                 State->Header.depth = lsb_16 (&BIH[14]);
291                 State->Compressed = lsb_32 (&BIH[16]);
292         } else if (State->Header.size == 40) {
293                 /* BMP v3 */ 
294                 State->Header.width = lsb_32 (&BIH[4]);
295                 State->Header.height = lsb_32 (&BIH[8]);
296                 State->Header.depth = lsb_16 (&BIH[14]);
297                 State->Compressed = lsb_32 (&BIH[16]);
298         } else if (State->Header.size == 12) {
299                 /* BMP OS/2 */
300                 State->Header.width = lsb_16 (&BIH[4]);
301                 State->Header.height = lsb_16 (&BIH[6]);
302                 State->Header.depth = lsb_16 (&BIH[10]);
303                 State->Compressed = BI_RGB;
304         } else {
305                 g_set_error (error,
306                              GDK_PIXBUF_ERROR,
307                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
308                              _("BMP image has unsupported header size"));
309                 State->read_state = READ_STATE_ERROR;
310                 return FALSE;
311         }
312
313         if (State->Header.size == 12)
314                 clrUsed = 1 << State->Header.depth;
315         else
316                 clrUsed = (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
317
318         if (clrUsed != 0)
319                 State->Header.n_colors = clrUsed;
320         else
321             State->Header.n_colors = (1 << State->Header.depth);
322         
323         if (State->Header.n_colors > (1 << State->Header.depth)) {
324                 g_set_error (error,
325                              GDK_PIXBUF_ERROR,
326                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
327                              _("BMP image has bogus header data"));
328                 State->read_state = READ_STATE_ERROR;
329                 return FALSE;
330         }
331
332         State->Type = State->Header.depth;      /* This may be less trivial someday */
333
334         /* Negative heights indicates bottom-down pixelorder */
335         if (State->Header.height < 0) {
336                 State->Header.height = -State->Header.height;
337                 State->Header.Negative = 1;
338         }
339
340         if (State->Header.Negative && 
341             (State->Compressed != BI_RGB && State->Compressed != BI_BITFIELDS))
342         {
343                 g_set_error (error,
344                              GDK_PIXBUF_ERROR,
345                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
346                              _("Topdown BMP images cannot be compressed"));
347                 State->read_state = READ_STATE_ERROR;
348                 return FALSE;
349         }
350
351         if (State->Header.width <= 0 || State->Header.height == 0 ||
352             (State->Compressed == BI_RLE4 && State->Type != 4)    ||
353             (State->Compressed == BI_RLE8 && State->Type != 8)    ||
354             (State->Compressed == BI_BITFIELDS && !(State->Type == 16 || State->Type == 32)) ||
355             (State->Compressed > BI_BITFIELDS)) {
356                 g_set_error (error,
357                              GDK_PIXBUF_ERROR,
358                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
359                              _("BMP image has bogus header data"));
360                 State->read_state = READ_STATE_ERROR;
361                 return FALSE;
362         }
363
364         if (State->Type == 32)
365                 State->LineWidth = State->Header.width * 4;
366         else if (State->Type == 24)
367                 State->LineWidth = State->Header.width * 3;
368         else if (State->Type == 16)
369                 State->LineWidth = State->Header.width * 2;
370         else if (State->Type == 8)
371                 State->LineWidth = State->Header.width * 1;
372         else if (State->Type == 4)
373                 State->LineWidth = (State->Header.width + 1) / 2;
374         else if (State->Type == 1) {
375                 State->LineWidth = State->Header.width / 8;
376                 if ((State->Header.width & 7) != 0)
377                         State->LineWidth++;
378         } else {
379                 g_set_error (error,
380                              GDK_PIXBUF_ERROR,
381                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
382                              _("BMP image has bogus header data"));
383                 State->read_state = READ_STATE_ERROR;
384                 return FALSE;
385         }
386
387         /* Pad to a 32 bit boundary */
388         if (((State->LineWidth % 4) > 0)
389             && (State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
390                 State->LineWidth = (State->LineWidth / 4) * 4 + 4;
391
392         if (State->pixbuf == NULL) {
393                 if (State->size_func) {
394                         gint width = State->Header.width;
395                         gint height = State->Header.height;
396
397                         (*State->size_func) (&width, &height, State->user_data);
398                         if (width == 0 || height == 0) {
399                                 State->read_state = READ_STATE_DONE;
400                                 State->BufferSize = 0;
401                                 return TRUE;
402                         }
403                 }
404
405                 if (State->Type == 32 || 
406                     State->Compressed == BI_RLE4 || 
407                     State->Compressed == BI_RLE8)
408                         State->pixbuf =
409                                 gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
410                                                (gint) State->Header.width,
411                                                (gint) State->Header.height);
412                 else
413                         State->pixbuf =
414                                 gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
415                                                (gint) State->Header.width,
416                                                (gint) State->Header.height);
417                 
418                 if (State->pixbuf == NULL) {
419                         g_set_error (error,
420                                      GDK_PIXBUF_ERROR,
421                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
422                                      _("Not enough memory to load bitmap image"));
423                         State->read_state = READ_STATE_ERROR;
424                         return FALSE;
425                         }
426                 
427                 if (State->prepared_func != NULL)
428                         /* Notify the client that we are ready to go */
429                         (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
430                 
431                 /* make all pixels initially transparent */
432                 if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
433                         memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
434                         State->compr.p = State->pixbuf->pixels 
435                                 + State->pixbuf->rowstride * (State->Header.height- 1);
436                 }
437         }
438         
439         State->BufferDone = 0;
440         if (State->Type <= 8) {
441                 gint samples;
442
443                 State->read_state = READ_STATE_PALETTE;
444
445                 /* Allocate enough to hold the palette */
446                 samples = (State->Header.size == 12 ? 3 : 4);
447                 State->BufferSize = State->Header.n_colors * samples;
448
449                 /* Skip over everything between the palette and the data.
450                    This protects us against a malicious BFH[10] value.
451                 */
452                 State->BufferPadding = (lsb_32 (&BFH[10]) - 14 - State->Header.size) - State->BufferSize;
453
454         } else if (State->Compressed == BI_RGB) {
455                 if (State->BufferSize < lsb_32 (&BFH[10]))
456                 {
457                         /* skip over padding between headers and image data */
458                         State->read_state = READ_STATE_HEADERS;
459                         State->BufferDone = State->BufferSize;
460                         State->BufferSize = lsb_32 (&BFH[10]);
461                 }
462                 else
463                 {
464                         State->read_state = READ_STATE_DATA;
465                         State->BufferSize = State->LineWidth;
466                 }
467         } else if (State->Compressed == BI_BITFIELDS) {
468                if (State->Header.size == 108 || State->Header.size == 124) 
469                {
470                         /* v4 and v5 have the bitmasks in the header */
471                         if (!decode_bitmasks (&BIH[40], State, error)) {
472                                State->read_state = READ_STATE_ERROR;
473                                return FALSE;
474                         }
475                }
476                else 
477                {
478                        State->read_state = READ_STATE_BITMASKS;
479                        State->BufferSize = 12;
480                }
481         } else {
482                 g_set_error (error,
483                              GDK_PIXBUF_ERROR,
484                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
485                              _("BMP image has bogus header data"));
486                 State->read_state = READ_STATE_ERROR;
487                 return FALSE;
488         }
489
490         if (!grow_buffer (State, error)) 
491                 return FALSE;
492
493         return TRUE;
494 }
495
496 static gboolean DecodeColormap (guchar *buff,
497                                 struct bmp_progressive_state *State,
498                                 GError **error)
499 {
500         gint i;
501         gint samples;
502
503         g_assert (State->read_state == READ_STATE_PALETTE);
504
505         samples = (State->Header.size == 12 ? 3 : 4);
506         if (State->BufferSize < State->Header.n_colors * samples) {
507                 State->BufferSize = State->Header.n_colors * samples;
508                 if (!grow_buffer (State, error))
509                         return FALSE;
510                 return TRUE;
511         }
512
513         State->Colormap = g_malloc0 ((1 << State->Header.depth) * sizeof (*State->Colormap));
514         for (i = 0; i < State->Header.n_colors; i++)
515
516         {
517                 State->Colormap[i][0] = buff[i * samples];
518                 State->Colormap[i][1] = buff[i * samples + 1];
519                 State->Colormap[i][2] = buff[i * samples + 2];
520 #ifdef DUMPCMAP
521                 g_print ("color %d %x %x %x\n", i,
522                          State->Colormap[i][0],
523                          State->Colormap[i][1],
524                          State->Colormap[i][2]);
525 #endif
526         }
527
528         State->read_state = READ_STATE_DATA;
529
530         State->BufferDone = 0;
531         if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
532                 State->BufferSize = 2;
533         else
534                 State->BufferSize = State->LineWidth;
535         
536         if (!grow_buffer (State, error))
537                 return FALSE;
538
539         return TRUE;
540 }
541
542 /* Finds the lowest set bit and the number of set bits */
543 static void
544 find_bits (int n, int *lowest, int *n_set)
545 {
546         int i;
547
548         *n_set = 0;
549
550         for (i = 31; i >= 0; i--)
551                 if (n & (1 << i)) {
552                         *lowest = i;
553                         (*n_set)++;
554                 }
555 }
556
557 /* Decodes the bitmasks for BI_BITFIELDS coding */
558 static gboolean
559 decode_bitmasks (guchar *buf,
560                  struct bmp_progressive_state *State, 
561                  GError **error)
562 {
563         State->a_mask = State->a_shift = State->a_bits = 0;
564         State->r_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
565         buf += 4;
566
567         State->g_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
568         buf += 4;
569
570         State->b_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
571
572         find_bits (State->r_mask, &State->r_shift, &State->r_bits);
573         find_bits (State->g_mask, &State->g_shift, &State->g_bits);
574         find_bits (State->b_mask, &State->b_shift, &State->b_bits);
575
576         /* v4 and v5 have an alpha mask */
577         if (State->Header.size == 108 || State->Header.size == 124) {
578               buf += 4;
579               State->a_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
580               find_bits (State->a_mask, &State->a_shift, &State->a_bits);
581         }
582
583         if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
584                 if (State->Type == 16) {
585                        State->r_mask = 0x7c00;
586                        State->r_shift = 10;
587                        State->g_mask = 0x03e0;
588                        State->g_shift = 5;
589                        State->b_mask = 0x001f;
590                        State->b_shift = 0;
591
592                        State->r_bits = State->g_bits = State->b_bits = 5;
593                 }
594                 else {
595                        State->r_mask = 0x00ff0000;
596                        State->r_shift = 16;
597                        State->g_mask = 0x0000ff00;
598                        State->g_shift = 8;
599                        State->b_mask = 0x000000ff;
600                        State->b_shift = 0;
601                        State->a_mask = 0xff000000;
602                        State->a_shift = 24;
603
604                        State->r_bits = State->g_bits = State->b_bits = State->a_bits = 8;
605                 }
606         }
607
608         if (State->r_bits > 8) {
609           State->r_shift += State->r_bits - 8;
610           State->r_bits = 8;
611         }
612         if (State->g_bits > 8) {
613           State->g_shift += State->g_bits - 8;
614           State->g_bits = 8;
615         }
616         if (State->b_bits > 8) {
617           State->b_shift += State->b_bits - 8;
618           State->b_bits = 8;
619         }
620         if (State->a_bits > 8) {
621           State->a_shift += State->a_bits - 8;
622           State->a_bits = 8;
623         }
624
625         State->read_state = READ_STATE_DATA;
626         State->BufferDone = 0;
627         State->BufferSize = State->LineWidth;
628         if (!grow_buffer (State, error)) 
629                 return FALSE;
630
631         return TRUE;
632 }
633
634 /*
635  * func - called when we have pixmap created (but no image data)
636  * user_data - passed as arg 1 to func
637  * return context (opaque to user)
638  */
639
640 static gpointer
641 gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
642                                  GdkPixbufModulePreparedFunc prepared_func,
643                                  GdkPixbufModuleUpdatedFunc updated_func,
644                                  gpointer user_data,
645                                  GError **error)
646 {
647         struct bmp_progressive_state *context;
648         
649         context = g_new0(struct bmp_progressive_state, 1);
650         context->size_func = size_func;
651         context->prepared_func = prepared_func;
652         context->updated_func = updated_func;
653         context->user_data = user_data;
654
655         context->read_state = READ_STATE_HEADERS;
656
657         context->BufferSize = 26;
658         context->BufferPadding = 0;
659         context->buff = g_malloc(26);
660         context->BufferDone = 0;
661         /* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
662
663         context->Colormap = NULL;
664
665         context->Lines = 0;
666
667         context->Type = 0;
668
669         memset(&context->Header, 0, sizeof(struct headerpair));
670         memset(&context->compr, 0, sizeof(struct bmp_compression_state));
671
672
673         context->pixbuf = NULL;
674         
675         return (gpointer) context;
676 }
677
678 /*
679  * context - returned from image_begin_load
680  *
681  * free context, unref gdk_pixbuf
682  */
683 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
684 {
685         struct bmp_progressive_state *context =
686             (struct bmp_progressive_state *) data;
687
688         /* FIXME this thing needs to report errors if
689          * we have unused image data
690          */
691         
692         g_return_val_if_fail(context != NULL, TRUE);
693
694         if (context->Colormap != NULL)
695                 g_free(context->Colormap);
696
697         if (context->pixbuf)
698                 g_object_unref(context->pixbuf);
699
700         g_free(context->buff);
701         g_free(context);
702
703         return TRUE;
704 }
705
706
707 /*
708 The OneLineXX functions are called when 1 line worth of data is present.
709 OneLine24 is the 24 bpp-version.
710 */
711 static void OneLine32(struct bmp_progressive_state *context)
712 {
713         int i;
714         guchar *pixels;
715         guchar *src;
716
717         if (!context->Header.Negative)
718                 pixels = (context->pixbuf->pixels +
719                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
720         else
721                 pixels = (context->pixbuf->pixels +
722                           context->pixbuf->rowstride * context->Lines);
723
724         src = context->buff;
725
726         if (context->Compressed == BI_BITFIELDS) {
727                 int r_lshift, r_rshift;
728                 int g_lshift, g_rshift;
729                 int b_lshift, b_rshift;
730                 int a_lshift, a_rshift;
731
732                 r_lshift = 8 - context->r_bits;
733                 g_lshift = 8 - context->g_bits;
734                 b_lshift = 8 - context->b_bits;
735                 a_lshift = 8 - context->a_bits;
736
737                 r_rshift = context->r_bits - r_lshift;
738                 g_rshift = context->g_bits - g_lshift;
739                 b_rshift = context->b_bits - b_lshift;
740                 a_rshift = context->a_bits - a_lshift;
741
742                 for (i = 0; i < context->Header.width; i++) {
743                         int v, r, g, b, a;
744
745                         v = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
746
747                         r = (v & context->r_mask) >> context->r_shift;
748                         g = (v & context->g_mask) >> context->g_shift;
749                         b = (v & context->b_mask) >> context->b_shift;
750                         a = (v & context->a_mask) >> context->a_shift;
751
752                         *pixels++ = (r << r_lshift) | (r >> r_rshift);
753                         *pixels++ = (g << g_lshift) | (g >> g_rshift);
754                         *pixels++ = (b << b_lshift) | (b >> b_rshift);
755                         if (context->a_bits)
756                           *pixels++ = 0xff - ((a << a_lshift) | (a >> a_rshift));
757                         else
758                           *pixels++ = 0xff;
759
760                         src += 4;
761                 }
762         } else
763                 for (i = 0; i < context->Header.width; i++) {
764                         *pixels++ = src[2];
765                         *pixels++ = src[1];
766                         *pixels++ = src[0];
767                         *pixels++ = 0xff;
768
769                         src += 4;
770                 }
771 }
772
773 static void OneLine24(struct bmp_progressive_state *context)
774 {
775         gint X;
776         guchar *Pixels;
777
778         X = 0;
779         if (context->Header.Negative == 0)
780                 Pixels = (context->pixbuf->pixels +
781                           context->pixbuf->rowstride *
782                           (context->Header.height - context->Lines - 1));
783         else
784                 Pixels = (context->pixbuf->pixels +
785                           context->pixbuf->rowstride *
786                           context->Lines);
787         while (X < context->Header.width) {
788                 Pixels[X * 3 + 0] = context->buff[X * 3 + 2];
789                 Pixels[X * 3 + 1] = context->buff[X * 3 + 1];
790                 Pixels[X * 3 + 2] = context->buff[X * 3 + 0];
791                 X++;
792         }
793
794 }
795
796 static void OneLine16(struct bmp_progressive_state *context)
797 {
798         int i;
799         guchar *pixels;
800         guchar *src;
801
802         if (!context->Header.Negative)
803                 pixels = (context->pixbuf->pixels +
804                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
805         else
806                 pixels = (context->pixbuf->pixels +
807                           context->pixbuf->rowstride * context->Lines);
808
809         src = context->buff;
810
811         if (context->Compressed == BI_BITFIELDS) {
812                 int r_lshift, r_rshift;
813                 int g_lshift, g_rshift;
814                 int b_lshift, b_rshift;
815
816                 r_lshift = 8 - context->r_bits;
817                 g_lshift = 8 - context->g_bits;
818                 b_lshift = 8 - context->b_bits;
819
820                 r_rshift = context->r_bits - r_lshift;
821                 g_rshift = context->g_bits - g_lshift;
822                 b_rshift = context->b_bits - b_lshift;
823
824                 for (i = 0; i < context->Header.width; i++) {
825                         int v, r, g, b;
826
827                         v = (int) src[0] | ((int) src[1] << 8);
828
829                         r = (v & context->r_mask) >> context->r_shift;
830                         g = (v & context->g_mask) >> context->g_shift;
831                         b = (v & context->b_mask) >> context->b_shift;
832
833                         *pixels++ = (r << r_lshift) | (r >> r_rshift);
834                         *pixels++ = (g << g_lshift) | (g >> g_rshift);
835                         *pixels++ = (b << b_lshift) | (b >> b_rshift);
836
837                         src += 2;
838                 }
839         } else
840                 for (i = 0; i < context->Header.width; i++) {
841                         int v, r, g, b;
842
843                         v = src[0] | (src[1] << 8);
844
845                         r = (v >> 10) & 0x1f;
846                         g = (v >> 5) & 0x1f;
847                         b = v & 0x1f;
848
849                         *pixels++ = (r << 3) | (r >> 2);
850                         *pixels++ = (g << 3) | (g >> 2);
851                         *pixels++ = (b << 3) | (b >> 2);
852
853                         src += 2;
854                 }
855 }
856
857 static void OneLine8(struct bmp_progressive_state *context)
858 {
859         gint X;
860         guchar *Pixels;
861
862         X = 0;
863         if (context->Header.Negative == 0)
864                 Pixels = (context->pixbuf->pixels +
865                           context->pixbuf->rowstride *
866                           (context->Header.height - context->Lines - 1));
867         else
868                 Pixels = (context->pixbuf->pixels +
869                           context->pixbuf->rowstride *
870                           context->Lines);
871         while (X < context->Header.width) {
872                 Pixels[X * 3 + 0] =
873                     context->Colormap[context->buff[X]][2];
874                 Pixels[X * 3 + 1] =
875                     context->Colormap[context->buff[X]][1];
876                 Pixels[X * 3 + 2] =
877                     context->Colormap[context->buff[X]][0];
878                 X++;
879         }
880 }
881
882 static void OneLine4(struct bmp_progressive_state *context)
883 {
884         gint X;
885         guchar *Pixels;
886
887         X = 0;
888         if (context->Header.Negative == 0)
889                 Pixels = (context->pixbuf->pixels +
890                           context->pixbuf->rowstride *
891                           (context->Header.height - context->Lines - 1));
892         else
893                 Pixels = (context->pixbuf->pixels +
894                           context->pixbuf->rowstride *
895                           context->Lines);
896
897         while (X < context->Header.width) {
898                 guchar Pix;
899
900                 Pix = context->buff[X / 2];
901
902                 Pixels[X * 3 + 0] =
903                     context->Colormap[Pix >> 4][2];
904                 Pixels[X * 3 + 1] =
905                     context->Colormap[Pix >> 4][1];
906                 Pixels[X * 3 + 2] =
907                     context->Colormap[Pix >> 4][0];
908                 X++;
909                 if (X < context->Header.width) {
910                         /* Handle the other 4 bit pixel only when there is one */
911                         Pixels[X * 3 + 0] =
912                             context->Colormap[Pix & 15][2];
913                         Pixels[X * 3 + 1] =
914                             context->Colormap[Pix & 15][1];
915                         Pixels[X * 3 + 2] =
916                             context->Colormap[Pix & 15][0];
917                         X++;
918                 }
919         }
920
921 }
922
923 static void OneLine1(struct bmp_progressive_state *context)
924 {
925         gint X;
926         guchar *Pixels;
927
928         X = 0;
929         if (context->Header.Negative == 0)
930                 Pixels = (context->pixbuf->pixels +
931                           context->pixbuf->rowstride *
932                           (context->Header.height - context->Lines - 1));
933         else
934                 Pixels = (context->pixbuf->pixels +
935                           context->pixbuf->rowstride *
936                           context->Lines);
937         while (X < context->Header.width) {
938                 gint Bit;
939
940                 Bit = (context->buff[X / 8]) >> (7 - (X & 7));
941                 Bit = Bit & 1;
942                 Pixels[X * 3 + 0] = context->Colormap[Bit][2];
943                 Pixels[X * 3 + 1] = context->Colormap[Bit][1];
944                 Pixels[X * 3 + 2] = context->Colormap[Bit][0];
945                 X++;
946         }
947 }
948
949
950 static void OneLine(struct bmp_progressive_state *context)
951 {
952         context->BufferDone = 0;
953         if (context->Lines >= context->Header.height)
954                 return;
955
956         if (context->Type == 32)
957                 OneLine32(context);
958         else if (context->Type == 24)
959                 OneLine24(context);
960         else if (context->Type == 16)
961                 OneLine16(context);
962         else if (context->Type == 8)
963                 OneLine8(context);
964         else if (context->Type == 4)
965                 OneLine4(context);
966         else if (context->Type == 1)
967                 OneLine1(context);
968         else
969                 g_assert_not_reached ();
970
971         context->Lines++;
972
973         if (context->updated_func != NULL) {
974                 (*context->updated_func) (context->pixbuf,
975                                           0,
976                                           (context->Header.Negative ?
977                                            (context->Lines - 1) :
978                                            (context->Header.height - context->Lines)),
979                                           context->Header.width,
980                                           1,
981                                           context->user_data);
982
983         }
984 }
985
986 #define NEUTRAL       0
987 #define ENCODED       1
988 #define ESCAPE        2   
989 #define DELTA_X       3
990 #define DELTA_Y       4
991 #define ABSOLUTE      5
992 #define SKIP          6
993
994 #define END_OF_LINE   0
995 #define END_OF_BITMAP 1
996 #define DELTA         2
997
998 static gboolean 
999 DoCompressed(struct bmp_progressive_state *context, GError **error)
1000 {
1001         gint i, j;
1002         gint y;
1003         guchar c;
1004         gint idx;
1005
1006         /* context->compr.y might be past the last line because we are
1007          * on padding past the end of a valid data, or we might have hit
1008          * out-of-bounds data. Either way we just eat-and-ignore the
1009          * rest of the file. Doing the check only here and not when
1010          * we change y below is fine since BufferSize is always 2 here
1011          * and the BMP file format always starts new data on 16-bit
1012          * boundaries.
1013          */
1014         if (context->compr.y >= context->Header.height) {
1015                 context->BufferDone = 0;
1016                 return TRUE;
1017         }
1018
1019         y = context->compr.y;
1020
1021         for (i = 0; i < context->BufferSize; i++) {
1022                 c = context->buff[i];
1023                 switch (context->compr.phase) {
1024                     case NEUTRAL:
1025                             if (c) {
1026                                     context->compr.run = c;
1027                                     context->compr.phase = ENCODED;
1028                             }
1029                             else
1030                                     context->compr.phase = ESCAPE;
1031                             break;
1032                     case ENCODED:
1033                             for (j = 0; j < context->compr.run; j++) {
1034                                     if (context->Compressed == BI_RLE8)
1035                                             idx = c;
1036                                     else if (j & 1) 
1037                                             idx = c & 0x0f;
1038                                     else 
1039                                             idx = (c >> 4) & 0x0f;
1040                                     if (context->compr.x < context->Header.width) {
1041                                             *context->compr.p++ = context->Colormap[idx][2];
1042                                             *context->compr.p++ = context->Colormap[idx][1];
1043                                             *context->compr.p++ = context->Colormap[idx][0];
1044                                             *context->compr.p++ = 0xff;
1045                                             context->compr.x++;    
1046                                     }
1047                             }
1048                             context->compr.phase = NEUTRAL;
1049                             break;
1050                     case ESCAPE:
1051                             switch (c) {
1052                                 case END_OF_LINE:
1053                                         context->compr.x = 0;
1054                                         context->compr.y++;
1055                                         context->compr.p = context->pixbuf->pixels 
1056                                                 + (context->pixbuf->rowstride * (context->Header.height - context->compr.y - 1))
1057                                                 + (4 * context->compr.x);
1058                                         context->compr.phase = NEUTRAL;
1059                                         break;
1060                                 case END_OF_BITMAP:
1061                                         context->compr.x = 0;
1062                                         context->compr.y = context->Header.height;
1063                                         context->compr.phase = NEUTRAL;
1064                                         break;
1065                                 case DELTA:
1066                                         context->compr.phase = DELTA_X;
1067                                         break;
1068                                 default:
1069                                         context->compr.run = c;
1070                                         context->compr.count = 0;
1071                                         context->compr.phase = ABSOLUTE;
1072                                         break;
1073                             }
1074                             break;
1075                     case DELTA_X:
1076                             context->compr.x += c;
1077                             context->compr.phase = DELTA_Y;
1078                             break;
1079                     case DELTA_Y:
1080                             context->compr.y += c;
1081                             context->compr.p = context->pixbuf->pixels 
1082                                     + (context->pixbuf->rowstride * (context->Header.height - context->compr.y - 1))
1083                                     + (4 * context->compr.x);
1084                             context->compr.phase = NEUTRAL;
1085                             break;
1086                     case ABSOLUTE:
1087                             if (context->Compressed == BI_RLE8) {
1088                                     idx = c;
1089                                     if (context->compr.x < context->Header.width) {
1090                                             *context->compr.p++ = context->Colormap[idx][2];
1091                                             *context->compr.p++ = context->Colormap[idx][1];
1092                                             *context->compr.p++ = context->Colormap[idx][0];
1093                                             *context->compr.p++ = 0xff;
1094                                             context->compr.x++;    
1095                                     }
1096                                     context->compr.count++;
1097
1098                                     if (context->compr.count == context->compr.run) {
1099                                             if (context->compr.run & 1)
1100                                                     context->compr.phase = SKIP;
1101                                             else
1102                                                     context->compr.phase = NEUTRAL;
1103                                     }
1104                             }
1105                             else {
1106                                     for (j = 0; j < 2; j++) {
1107                                             if (context->compr.count & 1)
1108                                                     idx = c & 0x0f;
1109                                             else 
1110                                                     idx = (c >> 4) & 0x0f;
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 & 3) == 1
1122                                                         || (context->compr.run & 3) == 2) 
1123                                                             context->compr.phase = SKIP;
1124                                                     else
1125                                                             context->compr.phase = NEUTRAL;
1126                                                     break;
1127                                             }
1128                                     }
1129                             }
1130                             break;
1131                     case SKIP:
1132                             context->compr.phase = NEUTRAL;
1133                             break;
1134                 }
1135         }
1136         if (context->updated_func != NULL) {
1137                 if (context->compr.y > y)
1138                 {
1139                         gint new_y = MIN (context->compr.y, context->Header.height);
1140                         (*context->updated_func) (context->pixbuf,
1141                                                   0,
1142                                                   context->Header.height - new_y,
1143                                                   context->Header.width,
1144                                                   new_y - y,
1145                                                   context->user_data);
1146                 }
1147
1148         }
1149
1150         context->BufferDone = 0;
1151         return TRUE;
1152 }
1153
1154 /*
1155  * context - from image_begin_load
1156  * buf - new image data
1157  * size - length of new image data
1158  *
1159  * append image data onto incrementally built output image
1160  */
1161 static gboolean
1162 gdk_pixbuf__bmp_image_load_increment(gpointer data,
1163                                      const guchar * buf,
1164                                      guint size,
1165                                      GError **error)
1166 {
1167         struct bmp_progressive_state *context =
1168             (struct bmp_progressive_state *) data;
1169
1170         gint BytesToCopy;
1171         gint BytesToRemove;
1172
1173         if (context->read_state == READ_STATE_DONE)
1174                 return TRUE;
1175         else if (context->read_state == READ_STATE_ERROR)
1176                 return FALSE;
1177
1178         while (size > 0) {
1179                 if (context->BufferDone < context->BufferSize) {        /* We still
1180                                                                            have headerbytes to do */
1181                         BytesToCopy =
1182                             context->BufferSize - context->BufferDone;
1183                         if (BytesToCopy > size)
1184                                 BytesToCopy = size;
1185
1186                         memmove(context->buff + context->BufferDone,
1187                                 buf, BytesToCopy);
1188
1189                         size -= BytesToCopy;
1190                         buf += BytesToCopy;
1191                         context->BufferDone += BytesToCopy;
1192
1193                         if (context->BufferDone != context->BufferSize)
1194                                 break;
1195                 }
1196
1197                 /* context->buff is full.  Now we discard all "padding" */
1198                 if (context->BufferPadding != 0) {
1199                         BytesToRemove = context->BufferPadding - size;
1200                         if (BytesToRemove > size) {
1201                                 BytesToRemove = size;
1202                         }
1203                         size -= BytesToRemove;
1204                         context->BufferPadding -= BytesToRemove;
1205
1206                         if (context->BufferPadding != 0)
1207                                 break;
1208                 }
1209
1210                 switch (context->read_state) {
1211                 case READ_STATE_HEADERS:
1212                         if (!DecodeHeader (context->buff,
1213                                            context->buff + 14, context,
1214                                            error))
1215                                 return FALSE;
1216
1217                         break;
1218
1219                 case READ_STATE_PALETTE:
1220                         if (!DecodeColormap (context->buff, context, error))
1221                                 return FALSE;
1222                         break;
1223
1224                 case READ_STATE_BITMASKS:
1225                         if (!decode_bitmasks (context->buff, context, error))
1226                                 return FALSE;
1227                         break;
1228
1229                 case READ_STATE_DATA:
1230                         if (context->Compressed == BI_RGB || context->Compressed == BI_BITFIELDS)
1231                                 OneLine (context);
1232                         else if (!DoCompressed (context, error))
1233                                 return FALSE;
1234
1235                         break;
1236                 case READ_STATE_DONE:
1237                         return TRUE;
1238                         break;
1239
1240                 default:
1241                         g_assert_not_reached ();
1242                 }
1243         }
1244
1245         return TRUE;
1246 }
1247
1248 /* for our convenience when filling file header */
1249 #define put16(buf,data) { guint16 x; \
1250                           x = GUINT16_TO_LE (data); \
1251                           memcpy(buf, &x, 2); \
1252                           buf += 2; }
1253 #define put32(buf,data) { guint32 x; \
1254                           x = GUINT32_TO_LE (data); \
1255                           memcpy(buf, &x, 4); \
1256                           buf += 4; }
1257
1258 static gboolean
1259 gdk_pixbuf__bmp_image_save_to_callback (GdkPixbufSaveFunc   save_func,
1260                                         gpointer            user_data,
1261                                         GdkPixbuf          *pixbuf, 
1262                                         gchar             **keys,
1263                                         gchar             **values,
1264                                         GError            **error)
1265 {
1266         guint width, height, channel, size, stride, src_stride, x, y;
1267         guchar BFH_BIH[54], *pixels, *buf, *src, *dst, *dst_line;
1268         gboolean ret;
1269
1270         width = gdk_pixbuf_get_width (pixbuf);
1271         height = gdk_pixbuf_get_height (pixbuf);
1272         channel = gdk_pixbuf_get_n_channels (pixbuf);
1273         pixels = gdk_pixbuf_get_pixels (pixbuf);
1274         src_stride = gdk_pixbuf_get_rowstride (pixbuf);
1275         stride = (width * 3 + 3) & ~3;
1276         size = stride * height;
1277
1278         /* filling BFH */
1279         dst = BFH_BIH;
1280         *dst++ = 'B';                   /* bfType */
1281         *dst++ = 'M';
1282         put32 (dst, size + 14 + 40);    /* bfSize */
1283         put32 (dst, 0);                 /* bfReserved1 + bfReserved2 */
1284         put32 (dst, 14 + 40);           /* bfOffBits */
1285
1286         /* filling BIH */
1287         put32 (dst, 40);                /* biSize */
1288         put32 (dst, width);             /* biWidth */
1289         put32 (dst, height);            /* biHeight */
1290         put16 (dst, 1);                 /* biPlanes */
1291         put16 (dst, 24);                /* biBitCount */
1292         put32 (dst, BI_RGB);            /* biCompression */
1293         put32 (dst, size);              /* biSizeImage */
1294         put32 (dst, 0);                 /* biXPelsPerMeter */
1295         put32 (dst, 0);                 /* biYPelsPerMeter */
1296         put32 (dst, 0);                 /* biClrUsed */
1297         put32 (dst, 0);                 /* biClrImportant */
1298
1299         if (!save_func (BFH_BIH, 14 + 40, error, user_data))
1300                 return FALSE;
1301
1302         dst_line = buf = g_try_malloc (size);
1303         if (!buf) {
1304                 g_set_error (error,
1305                              GDK_PIXBUF_ERROR,
1306                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1307                              _("Couldn't allocate memory for saving BMP file"));
1308                 return FALSE;
1309         }
1310
1311         /* saving as a bottom-up bmp */
1312         pixels += (height - 1) * src_stride;
1313         for (y = 0; y < height; ++y, pixels -= src_stride, dst_line += stride) {
1314                 dst = dst_line;
1315                 src = pixels;
1316                 for (x = 0; x < width; ++x, dst += 3, src += channel) {
1317                         dst[0] = src[2];
1318                         dst[1] = src[1];
1319                         dst[2] = src[0];
1320                 }
1321         }
1322         ret = save_func (buf, size, error, user_data);
1323         g_free (buf);
1324
1325         return ret;
1326 }
1327
1328 static gboolean
1329 save_to_file_cb (const gchar *buf,
1330                  gsize count,
1331                  GError **error,
1332                  gpointer data)
1333 {
1334         gint bytes;
1335         
1336         while (count > 0) {
1337                 bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data);
1338                 if (bytes <= 0)
1339                         break;
1340                 count -= bytes;
1341                 buf += bytes;
1342         }
1343
1344         if (count) {
1345                 g_set_error (error,
1346                              GDK_PIXBUF_ERROR,
1347                              GDK_PIXBUF_ERROR_FAILED,
1348                              _("Couldn't write to BMP file"));
1349                 return FALSE;
1350         }
1351         
1352         return TRUE;
1353 }
1354
1355 static gboolean
1356 gdk_pixbuf__bmp_image_save (FILE          *f, 
1357                             GdkPixbuf     *pixbuf, 
1358                             gchar        **keys,
1359                             gchar        **values,
1360                             GError       **error)
1361 {
1362         return gdk_pixbuf__bmp_image_save_to_callback (save_to_file_cb,
1363                                                        f, pixbuf, keys,
1364                                                        values, error);
1365 }
1366
1367 #ifndef INCLUDE_bmp
1368 #define MODULE_ENTRY(type,function) function
1369 #else
1370 #define MODULE_ENTRY(type,function) _gdk_pixbuf__ ## type ## _ ## function
1371 #endif
1372
1373 void
1374 MODULE_ENTRY (bmp, fill_vtable) (GdkPixbufModule *module)
1375 {
1376         module->begin_load = gdk_pixbuf__bmp_image_begin_load;
1377         module->stop_load = gdk_pixbuf__bmp_image_stop_load;
1378         module->load_increment = gdk_pixbuf__bmp_image_load_increment;
1379         module->save = gdk_pixbuf__bmp_image_save;
1380         module->save_to_callback = gdk_pixbuf__bmp_image_save_to_callback;
1381 }
1382
1383 void
1384 MODULE_ENTRY (bmp, fill_info) (GdkPixbufFormat *info)
1385 {
1386         static GdkPixbufModulePattern signature[] = {
1387                 { "BM", NULL, 100 },
1388                 { NULL, NULL, 0 }
1389         };
1390         static gchar * mime_types[] = {
1391                 "image/bmp",
1392                 "image/x-bmp",
1393                 "image/x-MS-bmp",
1394                 NULL
1395         };
1396         static gchar * extensions[] = {
1397                 "bmp",
1398                 NULL
1399         };
1400
1401         info->name = "bmp";
1402         info->signature = signature;
1403         info->description = N_("The BMP image format");
1404         info->mime_types = mime_types;
1405         info->extensions = extensions;
1406         info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1407         info->license = "LGPL";
1408 }
1409