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