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 */
47struct BitmapFileHeader {
48 guint16 magic;
49 guint32 file_size;
50 guint32 reserved;
51 guint32 data_offset;
52};
53
54struct 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 */
77typedef 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
88DumpBIH printf's the values in a BitmapInfoHeader to the screen, for
89debugging purposes.
90
91*/
92#if DUMPBIH
93static 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
129struct 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 */
140struct 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
150struct 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
191static gpointer
192gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
193 GdkPixbufModulePreparedFunc prepared_func,
194 GdkPixbufModuleUpdatedFunc updated_func,
195 gpointer user_data,
196 GError **error);
197
198static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
199static 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 */
209static int
210lsb_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. */
216static short
217lsb_16 (guchar *src)
218{
219 return src[0] | (src[1] << 8);
220}
221
222static 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 (err: error,
229 GDK_PIXBUF_ERROR,
230 code: 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 (mem: State->buff, n_bytes: State->BufferSize);
237
238 if (!tmp) {
239 g_set_error_literal (err: error,
240 GDK_PIXBUF_ERROR,
241 code: 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
251static gboolean
252decode_bitmasks (guchar *buf,
253 struct bmp_progressive_state *State,
254 GError **error);
255
256static 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 (err: error,
267 GDK_PIXBUF_ERROR,
268 code: 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 (src: &BIH[0]) + 14) {
276 State->BufferSize = lsb_32 (src: &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 (src: &BIH[0]);
287 if (State->Header.size == 124) {
288 /* BMP v5 */
289 State->Header.width = lsb_32 (src: &BIH[4]);
290 State->Header.height = lsb_32 (src: &BIH[8]);
291 State->Header.depth = lsb_16 (src: &BIH[14]);
292 State->Compressed = lsb_32 (src: &BIH[16]);
293 } else if (State->Header.size == 108) {
294 /* BMP v4 */
295 State->Header.width = lsb_32 (src: &BIH[4]);
296 State->Header.height = lsb_32 (src: &BIH[8]);
297 State->Header.depth = lsb_16 (src: &BIH[14]);
298 State->Compressed = lsb_32 (src: &BIH[16]);
299 } else if (State->Header.size == 64) {
300 /* BMP OS/2 v2 */
301 State->Header.width = lsb_32 (src: &BIH[4]);
302 State->Header.height = lsb_32 (src: &BIH[8]);
303 State->Header.depth = lsb_16 (src: &BIH[14]);
304 State->Compressed = lsb_32 (src: &BIH[16]);
305 } else if (State->Header.size == 56) {
306 /* BMP v3 with RGBA bitmasks */
307 State->Header.width = lsb_32 (src: &BIH[4]);
308 State->Header.height = lsb_32 (src: &BIH[8]);
309 State->Header.depth = lsb_16 (src: &BIH[14]);
310 State->Compressed = lsb_32 (src: &BIH[16]);
311 } else if (State->Header.size == 52) {
312 /* BMP v3 with RGB bitmasks */
313 State->Header.width = lsb_32 (src: &BIH[4]);
314 State->Header.height = lsb_32 (src: &BIH[8]);
315 State->Header.depth = lsb_16 (src: &BIH[14]);
316 State->Compressed = lsb_32 (src: &BIH[16]);
317 } else if (State->Header.size == 40) {
318 /* BMP v3 */
319 State->Header.width = lsb_32 (src: &BIH[4]);
320 State->Header.height = lsb_32 (src: &BIH[8]);
321 State->Header.depth = lsb_16 (src: &BIH[14]);
322 State->Compressed = lsb_32 (src: &BIH[16]);
323 } else if (State->Header.size == 12) {
324 /* BMP OS/2 */
325 State->Header.width = lsb_16 (src: &BIH[4]);
326 State->Header.height = lsb_16 (src: &BIH[6]);
327 State->Header.depth = lsb_16 (src: &BIH[10]);
328 State->Compressed = BI_RGB;
329 } else {
330 g_set_error_literal (err: error,
331 GDK_PIXBUF_ERROR,
332 code: 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 (err: error,
341 GDK_PIXBUF_ERROR,
342 code: 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 (err: error,
356 GDK_PIXBUF_ERROR,
357 code: 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 (err: error,
374 GDK_PIXBUF_ERROR,
375 code: 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 (err: error,
388 GDK_PIXBUF_ERROR,
389 code: 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 (err: error,
401 GDK_PIXBUF_ERROR,
402 code: 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 (err: error,
413 GDK_PIXBUF_ERROR,
414 code: 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 (err: error,
426 GDK_PIXBUF_ERROR,
427 code: 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 {
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 (err: error,
461 GDK_PIXBUF_ERROR,
462 code: 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 (colorspace: GDK_COLORSPACE_RGB, has_alpha, bits_per_sample: 8,
476 width: (gint) State->Header.width,
477 height: (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 (err: error,
483 GDK_PIXBUF_ERROR,
484 code: 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 (colorspace: GDK_COLORSPACE_RGB, has_alpha, bits_per_sample: 8,
491 width: (gint) State->Header.width,
492 height: (gint) State->Header.height);
493
494 if (State->pixbuf == NULL) {
495 g_set_error_literal (err: error,
496 GDK_PIXBUF_ERROR,
497 code: 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 /* Notify the client that we are ready to go */
504 (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
505
506 /* make all pixels initially transparent */
507 if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
508 gint rowstride = gdk_pixbuf_get_rowstride (pixbuf: State->pixbuf);
509
510 memset (s: gdk_pixbuf_get_pixels (pixbuf: State->pixbuf), c: 0, n: rowstride * State->Header.height);
511 State->compr.p = gdk_pixbuf_get_pixels (pixbuf: State->pixbuf)
512 + rowstride * (State->Header.height- 1);
513 }
514 }
515
516 State->BufferDone = 0;
517 if (State->Type <= 8) {
518 gint samples;
519
520 State->read_state = READ_STATE_PALETTE;
521
522 /* Allocate enough to hold the palette */
523 samples = (State->Header.size == 12 ? 3 : 4);
524 State->BufferSize = State->Header.n_colors * samples;
525
526 /* Skip over everything between the palette and the data.
527 This protects us against a malicious BFH[10] value.
528 */
529 State->BufferPadding = (lsb_32 (src: &BFH[10]) - 14 - State->Header.size) - State->BufferSize;
530
531 } else if (State->Compressed == BI_RGB) {
532 if (State->BufferSize < lsb_32 (src: &BFH[10]))
533 {
534 /* skip over padding between headers and image data */
535 State->read_state = READ_STATE_HEADERS;
536 State->BufferDone = State->BufferSize;
537 State->BufferSize = lsb_32 (src: &BFH[10]);
538 }
539 else
540 {
541 State->read_state = READ_STATE_DATA;
542 State->BufferSize = State->LineWidth;
543 }
544 } else if (State->Compressed == BI_BITFIELDS) {
545 if (State->Header.size == 52 || State->Header.size == 56 ||
546 State->Header.size == 108 || State->Header.size == 124)
547 {
548 /* extended v3, v4 and v5 have the bitmasks in the header */
549 if (!decode_bitmasks (buf: &BIH[40], State, error)) {
550 State->read_state = READ_STATE_ERROR;
551 return FALSE;
552 }
553 }
554 else
555 {
556 State->read_state = READ_STATE_BITMASKS;
557 State->BufferSize = 12;
558 }
559 } else {
560 g_set_error_literal (err: error,
561 GDK_PIXBUF_ERROR,
562 code: GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
563 _("BMP image has bogus header data"));
564 State->read_state = READ_STATE_ERROR;
565 return FALSE;
566 }
567
568 if (!grow_buffer (State, error))
569 return FALSE;
570
571 return TRUE;
572}
573
574static gboolean DecodeColormap (guchar *buff,
575 struct bmp_progressive_state *State,
576 GError **error)
577{
578 gint i;
579 gint samples;
580 guint newbuffersize;
581
582 g_assert (State->read_state == READ_STATE_PALETTE);
583
584 samples = (State->Header.size == 12 ? 3 : 4);
585 newbuffersize = State->Header.n_colors * samples;
586 if (newbuffersize / samples != State->Header.n_colors) /* Integer overflow check */
587 return FALSE;
588 if (State->BufferSize < newbuffersize) {
589 State->BufferSize = newbuffersize;
590 if (!grow_buffer (State, error))
591 return FALSE;
592 return TRUE;
593 }
594
595 State->Colormap = g_malloc0 (n_bytes: (1 << State->Header.depth) * sizeof (*State->Colormap));
596 for (i = 0; i < State->Header.n_colors; i++)
597
598 {
599 State->Colormap[i][0] = buff[i * samples];
600 State->Colormap[i][1] = buff[i * samples + 1];
601 State->Colormap[i][2] = buff[i * samples + 2];
602#ifdef DUMPCMAP
603 g_print ("color %d %x %x %x\n", i,
604 State->Colormap[i][0],
605 State->Colormap[i][1],
606 State->Colormap[i][2]);
607#endif
608 }
609
610 State->read_state = READ_STATE_DATA;
611
612 State->BufferDone = 0;
613 if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
614 State->BufferSize = 2;
615 else
616 State->BufferSize = State->LineWidth;
617
618 if (!grow_buffer (State, error))
619 return FALSE;
620
621 return TRUE;
622}
623
624/* Finds the lowest set bit and the number of set bits */
625static void
626find_bits (int n, int *lowest, int *n_set)
627{
628 unsigned int i;
629
630 *lowest = 0;
631 *n_set = 0;
632
633 for (i = 31; n != 0; n <<= 1, i--)
634 if (n & ((unsigned int) 1 << 31)) {
635 *lowest = i;
636 (*n_set)++;
637 }
638}
639
640/* Decodes the bitmasks for BI_BITFIELDS coding */
641static gboolean
642decode_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 (n: State->r_mask, lowest: &State->r_shift, n_set: &State->r_bits);
656 find_bits (n: State->g_mask, lowest: &State->g_shift, n_set: &State->g_bits);
657 find_bits (n: State->b_mask, lowest: &State->b_shift, n_set: &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 (n: State->a_mask, lowest: &State->a_shift, n_set: &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
723static gpointer
724gdk_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 g_assert (size_func != NULL);
733 g_assert (prepared_func != NULL);
734 g_assert (updated_func != NULL);
735
736 context = g_new0(struct bmp_progressive_state, 1);
737 context->size_func = size_func;
738 context->prepared_func = prepared_func;
739 context->updated_func = updated_func;
740 context->user_data = user_data;
741
742 context->read_state = READ_STATE_HEADERS;
743
744 context->BufferSize = 26;
745 context->BufferPadding = 0;
746 context->buff = g_malloc(n_bytes: 26);
747 context->BufferDone = 0;
748 /* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
749
750 context->Colormap = NULL;
751
752 context->Lines = 0;
753
754 context->Type = 0;
755
756 memset(s: &context->Header, c: 0, n: sizeof(struct headerpair));
757 memset(s: &context->compr, c: 0, n: sizeof(struct bmp_compression_state));
758
759
760 context->pixbuf = NULL;
761
762 return (gpointer) context;
763}
764
765/*
766 * context - returned from image_begin_load
767 *
768 * free context, unref gdk_pixbuf
769 */
770static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
771{
772 gboolean retval = TRUE;
773
774 struct bmp_progressive_state *context =
775 (struct bmp_progressive_state *) data;
776
777 /* FIXME this thing needs to report errors if
778 * we have unused image data
779 */
780
781 g_return_val_if_fail(context != NULL, TRUE);
782
783 g_free(mem: context->Colormap);
784
785 if (context->pixbuf)
786 g_object_unref(object: context->pixbuf);
787
788 if (context->read_state == READ_STATE_HEADERS) {
789 g_set_error_literal (err: error,
790 GDK_PIXBUF_ERROR,
791 code: GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
792 _("Premature end-of-file encountered"));
793 retval = FALSE;
794 }
795
796 g_free(mem: context->buff);
797 g_free(mem: context);
798
799 return retval;
800}
801
802
803/*
804The OneLineXX functions are called when 1 line worth of data is present.
805OneLine24 is the 24 bpp-version.
806*/
807static void OneLine32(struct bmp_progressive_state *context)
808{
809 int i;
810 guchar *pixels;
811 guchar *src;
812 gint rowstride = gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
813
814 if (!context->Header.Negative)
815 pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
816 rowstride * (context->Header.height - context->Lines - 1));
817 else
818 pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
819 rowstride * context->Lines);
820
821 src = context->buff;
822
823 if (context->Compressed == BI_BITFIELDS) {
824 int r_lshift, r_rshift;
825 int g_lshift, g_rshift;
826 int b_lshift, b_rshift;
827 int a_lshift, a_rshift;
828
829 r_lshift = 8 - context->r_bits;
830 g_lshift = 8 - context->g_bits;
831 b_lshift = 8 - context->b_bits;
832 a_lshift = 8 - context->a_bits;
833
834 r_rshift = context->r_bits - r_lshift;
835 g_rshift = context->g_bits - g_lshift;
836 b_rshift = context->b_bits - b_lshift;
837 a_rshift = context->a_bits - a_lshift;
838
839 for (i = 0; i < context->Header.width; i++) {
840 unsigned int v, r, g, b, a;
841
842 v = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
843
844 r = (v & context->r_mask) >> context->r_shift;
845 g = (v & context->g_mask) >> context->g_shift;
846 b = (v & context->b_mask) >> context->b_shift;
847 a = (v & context->a_mask) >> context->a_shift;
848
849 *pixels++ = (r << r_lshift) | (r >> r_rshift);
850 *pixels++ = (g << g_lshift) | (g >> g_rshift);
851 *pixels++ = (b << b_lshift) | (b >> b_rshift);
852 if (context->a_bits)
853 *pixels++ = (a << a_lshift) | (a >> a_rshift);
854 else
855 *pixels++ = 0xff;
856
857 src += 4;
858 }
859 } else
860 for (i = 0; i < context->Header.width; i++) {
861 *pixels++ = src[2];
862 *pixels++ = src[1];
863 *pixels++ = src[0];
864 *pixels++ = 0xff;
865
866 src += 4;
867 }
868}
869
870static void OneLine24(struct bmp_progressive_state *context)
871{
872 gint X;
873 guchar *Pixels;
874 gint rowstride = gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
875
876 X = 0;
877 if (context->Header.Negative == 0)
878 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
879 rowstride * (context->Header.height - context->Lines - 1));
880 else
881 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
882 rowstride * context->Lines);
883 while (X < context->Header.width) {
884 Pixels[X * 3 + 0] = context->buff[X * 3 + 2];
885 Pixels[X * 3 + 1] = context->buff[X * 3 + 1];
886 Pixels[X * 3 + 2] = context->buff[X * 3 + 0];
887 X++;
888 }
889
890}
891
892static void OneLine16(struct bmp_progressive_state *context)
893{
894 int i;
895 guchar *pixels;
896 guchar *src;
897 gint rowstride = gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
898
899 if (!context->Header.Negative)
900 pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
901 rowstride * (context->Header.height - context->Lines - 1));
902 else
903 pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
904 rowstride * context->Lines);
905
906 src = context->buff;
907
908 if (context->Compressed == BI_BITFIELDS) {
909 int r_lshift, r_rshift;
910 int g_lshift, g_rshift;
911 int b_lshift, b_rshift;
912
913 r_lshift = 8 - context->r_bits;
914 g_lshift = 8 - context->g_bits;
915 b_lshift = 8 - context->b_bits;
916
917 r_rshift = context->r_bits - r_lshift;
918 g_rshift = context->g_bits - g_lshift;
919 b_rshift = context->b_bits - b_lshift;
920
921 for (i = 0; i < context->Header.width; i++) {
922 int v, r, g, b;
923
924 v = (int) src[0] | ((int) src[1] << 8);
925
926 r = (v & context->r_mask) >> context->r_shift;
927 g = (v & context->g_mask) >> context->g_shift;
928 b = (v & context->b_mask) >> context->b_shift;
929
930 *pixels++ = (r << r_lshift) | (r >> r_rshift);
931 *pixels++ = (g << g_lshift) | (g >> g_rshift);
932 *pixels++ = (b << b_lshift) | (b >> b_rshift);
933
934 src += 2;
935 }
936 } else
937 for (i = 0; i < context->Header.width; i++) {
938 int v, r, g, b;
939
940 v = src[0] | (src[1] << 8);
941
942 r = (v >> 10) & 0x1f;
943 g = (v >> 5) & 0x1f;
944 b = v & 0x1f;
945
946 *pixels++ = (r << 3) | (r >> 2);
947 *pixels++ = (g << 3) | (g >> 2);
948 *pixels++ = (b << 3) | (b >> 2);
949
950 src += 2;
951 }
952}
953
954static void OneLine8(struct bmp_progressive_state *context)
955{
956 gint X;
957 guchar *Pixels;
958 gint rowstride = gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
959
960 X = 0;
961 if (context->Header.Negative == 0)
962 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
963 rowstride * (context->Header.height - context->Lines - 1));
964 else
965 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
966 rowstride * context->Lines);
967 while (X < context->Header.width) {
968 Pixels[X * 3 + 0] =
969 context->Colormap[context->buff[X]][2];
970 Pixels[X * 3 + 1] =
971 context->Colormap[context->buff[X]][1];
972 Pixels[X * 3 + 2] =
973 context->Colormap[context->buff[X]][0];
974 X++;
975 }
976}
977
978static void OneLine4(struct bmp_progressive_state *context)
979{
980 gint X;
981 guchar *Pixels;
982 gint rowstride = gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
983
984 X = 0;
985 if (context->Header.Negative == 0)
986 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
987 rowstride * (context->Header.height - context->Lines - 1));
988 else
989 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
990 rowstride * context->Lines);
991
992 while (X < context->Header.width) {
993 guchar Pix;
994
995 Pix = context->buff[X / 2];
996
997 Pixels[X * 3 + 0] =
998 context->Colormap[Pix >> 4][2];
999 Pixels[X * 3 + 1] =
1000 context->Colormap[Pix >> 4][1];
1001 Pixels[X * 3 + 2] =
1002 context->Colormap[Pix >> 4][0];
1003 X++;
1004 if (X < context->Header.width) {
1005 /* Handle the other 4 bit pixel only when there is one */
1006 Pixels[X * 3 + 0] =
1007 context->Colormap[Pix & 15][2];
1008 Pixels[X * 3 + 1] =
1009 context->Colormap[Pix & 15][1];
1010 Pixels[X * 3 + 2] =
1011 context->Colormap[Pix & 15][0];
1012 X++;
1013 }
1014 }
1015
1016}
1017
1018static void OneLine1(struct bmp_progressive_state *context)
1019{
1020 gint X;
1021 guchar *Pixels;
1022 gint rowstride = gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
1023
1024 X = 0;
1025 if (context->Header.Negative == 0)
1026 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
1027 rowstride * (context->Header.height - context->Lines - 1));
1028 else
1029 Pixels = (gdk_pixbuf_get_pixels (pixbuf: context->pixbuf) +
1030 rowstride * context->Lines);
1031 while (X < context->Header.width) {
1032 gint Bit;
1033
1034 Bit = (context->buff[X / 8]) >> (7 - (X & 7));
1035 Bit = Bit & 1;
1036 Pixels[X * 3 + 0] = context->Colormap[Bit][2];
1037 Pixels[X * 3 + 1] = context->Colormap[Bit][1];
1038 Pixels[X * 3 + 2] = context->Colormap[Bit][0];
1039 X++;
1040 }
1041}
1042
1043
1044static void OneLine(struct bmp_progressive_state *context)
1045{
1046 context->BufferDone = 0;
1047 if (context->Lines >= context->Header.height)
1048 return;
1049
1050 if (context->Type == 32)
1051 OneLine32(context);
1052 else if (context->Type == 24)
1053 OneLine24(context);
1054 else if (context->Type == 16)
1055 OneLine16(context);
1056 else if (context->Type == 8)
1057 OneLine8(context);
1058 else if (context->Type == 4)
1059 OneLine4(context);
1060 else if (context->Type == 1)
1061 OneLine1(context);
1062 else
1063 g_assert_not_reached ();
1064
1065 context->Lines++;
1066
1067 (*context->updated_func) (context->pixbuf,
1068 0,
1069 (context->Header.Negative ?
1070 (context->Lines - 1) :
1071 (context->Header.height - context->Lines)),
1072 context->Header.width,
1073 1,
1074 context->user_data);
1075
1076}
1077
1078#define NEUTRAL 0
1079#define ENCODED 1
1080#define ESCAPE 2
1081#define DELTA_X 3
1082#define DELTA_Y 4
1083#define ABSOLUTE 5
1084#define SKIP 6
1085
1086#define END_OF_LINE 0
1087#define END_OF_BITMAP 1
1088#define DELTA 2
1089
1090static gboolean
1091DoCompressed(struct bmp_progressive_state *context, GError **error)
1092{
1093 gint i, j;
1094 gint y;
1095 guchar c;
1096 gint idx;
1097
1098 /* context->compr.y might be past the last line because we are
1099 * on padding past the end of a valid data, or we might have hit
1100 * out-of-bounds data. Either way we just eat-and-ignore the
1101 * rest of the file. Doing the check only here and not when
1102 * we change y below is fine since BufferSize is always 2 here
1103 * and the BMP file format always starts new data on 16-bit
1104 * boundaries.
1105 */
1106 if (context->compr.y >= context->Header.height) {
1107 context->BufferDone = 0;
1108 return TRUE;
1109 }
1110
1111 y = context->compr.y;
1112
1113 for (i = 0; i < context->BufferSize; i++) {
1114 c = context->buff[i];
1115 switch (context->compr.phase) {
1116 case NEUTRAL:
1117 if (c) {
1118 context->compr.run = c;
1119 context->compr.phase = ENCODED;
1120 }
1121 else
1122 context->compr.phase = ESCAPE;
1123 break;
1124 case ENCODED:
1125 for (j = 0; j < context->compr.run; j++) {
1126 if (context->Compressed == BI_RLE8)
1127 idx = c;
1128 else if (j & 1)
1129 idx = c & 0x0f;
1130 else
1131 idx = (c >> 4) & 0x0f;
1132 if (context->compr.x < context->Header.width) {
1133 *context->compr.p++ = context->Colormap[idx][2];
1134 *context->compr.p++ = context->Colormap[idx][1];
1135 *context->compr.p++ = context->Colormap[idx][0];
1136 *context->compr.p++ = 0xff;
1137 context->compr.x++;
1138 }
1139 }
1140 context->compr.phase = NEUTRAL;
1141 break;
1142 case ESCAPE:
1143 switch (c) {
1144 case END_OF_LINE:
1145 context->compr.x = 0;
1146 context->compr.y++;
1147 context->compr.p = gdk_pixbuf_get_pixels (pixbuf: context->pixbuf)
1148 + (gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf) * (context->Header.height - context->compr.y - 1))
1149 + (4 * context->compr.x);
1150 context->compr.phase = NEUTRAL;
1151 break;
1152 case END_OF_BITMAP:
1153 context->compr.x = 0;
1154 context->compr.y = context->Header.height;
1155 context->compr.phase = NEUTRAL;
1156 break;
1157 case DELTA:
1158 context->compr.phase = DELTA_X;
1159 break;
1160 default:
1161 context->compr.run = c;
1162 context->compr.count = 0;
1163 context->compr.phase = ABSOLUTE;
1164 break;
1165 }
1166 break;
1167 case DELTA_X:
1168 context->compr.x += c;
1169 context->compr.phase = DELTA_Y;
1170 break;
1171 case DELTA_Y:
1172 context->compr.y += c;
1173 context->compr.p = gdk_pixbuf_get_pixels (pixbuf: context->pixbuf)
1174 + (gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf) * (context->Header.height - context->compr.y - 1))
1175 + (4 * context->compr.x);
1176 context->compr.phase = NEUTRAL;
1177 break;
1178 case ABSOLUTE:
1179 if (context->Compressed == BI_RLE8) {
1180 idx = c;
1181 if (context->compr.x < context->Header.width) {
1182 *context->compr.p++ = context->Colormap[idx][2];
1183 *context->compr.p++ = context->Colormap[idx][1];
1184 *context->compr.p++ = context->Colormap[idx][0];
1185 *context->compr.p++ = 0xff;
1186 context->compr.x++;
1187 }
1188 context->compr.count++;
1189
1190 if (context->compr.count == context->compr.run) {
1191 if (context->compr.run & 1)
1192 context->compr.phase = SKIP;
1193 else
1194 context->compr.phase = NEUTRAL;
1195 }
1196 }
1197 else {
1198 for (j = 0; j < 2; j++) {
1199 if (context->compr.count & 1)
1200 idx = c & 0x0f;
1201 else
1202 idx = (c >> 4) & 0x0f;
1203 if (context->compr.x < context->Header.width) {
1204 *context->compr.p++ = context->Colormap[idx][2];
1205 *context->compr.p++ = context->Colormap[idx][1];
1206 *context->compr.p++ = context->Colormap[idx][0];
1207 *context->compr.p++ = 0xff;
1208 context->compr.x++;
1209 }
1210 context->compr.count++;
1211
1212 if (context->compr.count == context->compr.run) {
1213 if ((context->compr.run & 3) == 1
1214 || (context->compr.run & 3) == 2)
1215 context->compr.phase = SKIP;
1216 else
1217 context->compr.phase = NEUTRAL;
1218 break;
1219 }
1220 }
1221 }
1222 break;
1223 case SKIP:
1224 context->compr.phase = NEUTRAL;
1225 break;
1226 }
1227 }
1228
1229 if (context->compr.y > y) {
1230 gint new_y = MIN (context->compr.y, context->Header.height);
1231 (*context->updated_func) (context->pixbuf,
1232 0,
1233 context->Header.height - new_y,
1234 context->Header.width,
1235 new_y - y,
1236 context->user_data);
1237 }
1238
1239 context->BufferDone = 0;
1240 return TRUE;
1241}
1242
1243/*
1244 * context - from image_begin_load
1245 * buf - new image data
1246 * size - length of new image data
1247 *
1248 * append image data onto incrementally built output image
1249 */
1250static gboolean
1251gdk_pixbuf__bmp_image_load_increment(gpointer data,
1252 const guchar * buf,
1253 guint size,
1254 GError **error)
1255{
1256 struct bmp_progressive_state *context =
1257 (struct bmp_progressive_state *) data;
1258
1259 gint BytesToCopy;
1260 gint BytesToRemove;
1261
1262 if (context->read_state == READ_STATE_DONE)
1263 return TRUE;
1264 else if (context->read_state == READ_STATE_ERROR)
1265 return FALSE;
1266
1267 while (size > 0) {
1268 if (context->BufferDone < context->BufferSize) { /* We still
1269 have headerbytes to do */
1270 BytesToCopy =
1271 context->BufferSize - context->BufferDone;
1272 if (BytesToCopy > size)
1273 BytesToCopy = size;
1274
1275 memmove(dest: context->buff + context->BufferDone,
1276 src: buf, n: BytesToCopy);
1277
1278 size -= BytesToCopy;
1279 buf += BytesToCopy;
1280 context->BufferDone += BytesToCopy;
1281
1282 if (context->BufferDone != context->BufferSize)
1283 break;
1284 }
1285
1286 /* context->buff is full. Now we discard all "padding" */
1287 if (context->BufferPadding != 0) {
1288 BytesToRemove = context->BufferPadding - size;
1289 if (BytesToRemove > size) {
1290 BytesToRemove = size;
1291 }
1292 size -= BytesToRemove;
1293 context->BufferPadding -= BytesToRemove;
1294
1295 if (context->BufferPadding != 0)
1296 break;
1297 }
1298
1299 switch (context->read_state) {
1300 case READ_STATE_HEADERS:
1301 if (!DecodeHeader (BFH: context->buff,
1302 BIH: context->buff + 14, State: context,
1303 error))
1304 return FALSE;
1305
1306 break;
1307
1308 case READ_STATE_PALETTE:
1309 if (!DecodeColormap (buff: context->buff, State: context, error)) {
1310 g_set_error_literal (err: error,
1311 GDK_PIXBUF_ERROR,
1312 code: GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1313 _("Error while decoding colormap"));
1314 return FALSE;
1315 }
1316 break;
1317
1318 case READ_STATE_BITMASKS:
1319 if (!decode_bitmasks (buf: context->buff, State: context, error))
1320 return FALSE;
1321 break;
1322
1323 case READ_STATE_DATA:
1324 if (context->Compressed == BI_RGB || context->Compressed == BI_BITFIELDS)
1325 OneLine (context);
1326 else if (!DoCompressed (context, error))
1327 return FALSE;
1328
1329 break;
1330 case READ_STATE_DONE:
1331 return TRUE;
1332 break;
1333
1334 default:
1335 g_assert_not_reached ();
1336 }
1337 }
1338
1339 return TRUE;
1340}
1341
1342/* for our convenience when filling file header */
1343#define put16(buf,data) { guint16 x; \
1344 x = GUINT16_TO_LE (data); \
1345 memcpy(buf, &x, 2); \
1346 buf += 2; }
1347#define put32(buf,data) { guint32 x; \
1348 x = GUINT32_TO_LE (data); \
1349 memcpy(buf, &x, 4); \
1350 buf += 4; }
1351
1352static gboolean
1353gdk_pixbuf__bmp_image_save_to_callback (GdkPixbufSaveFunc save_func,
1354 gpointer user_data,
1355 GdkPixbuf *pixbuf,
1356 gchar **keys,
1357 gchar **values,
1358 GError **error)
1359{
1360 guint width, height, channel, size, stride, src_stride, x, y;
1361 guint bf_size;
1362 guchar BFH_BIH[54], *pixels, *buf, *src, *dst, *dst_line;
1363 gboolean ret;
1364
1365 width = gdk_pixbuf_get_width (pixbuf);
1366 height = gdk_pixbuf_get_height (pixbuf);
1367 channel = gdk_pixbuf_get_n_channels (pixbuf);
1368 pixels = gdk_pixbuf_get_pixels (pixbuf);
1369 src_stride = gdk_pixbuf_get_rowstride (pixbuf);
1370
1371 /* stride = (width * 3 + 3) & ~3 */
1372 if (!g_uint_checked_mul (&stride, width, 3) ||
1373 !g_uint_checked_add (&stride, stride, 3)) {
1374 g_set_error_literal (err: error, GDK_PIXBUF_ERROR,
1375 code: GDK_PIXBUF_ERROR_FAILED,
1376 _("Image is too wide for BMP format."));
1377 return FALSE;
1378 }
1379
1380 stride &= ~3;
1381
1382 /* size = stride * height
1383 * bf_size = size + 14 + 40 */
1384 if (!g_uint_checked_mul (&size, stride, height) ||
1385 !g_uint_checked_add (&bf_size, size, 14 + 40)) {
1386 g_set_error_literal (err: error, GDK_PIXBUF_ERROR,
1387 code: GDK_PIXBUF_ERROR_FAILED,
1388 _("Image is too wide for BMP format."));
1389 return FALSE;
1390 }
1391
1392 /* filling BFH */
1393 dst = BFH_BIH;
1394 *dst++ = 'B'; /* bfType */
1395 *dst++ = 'M';
1396 put32 (dst, bf_size); /* bfSize */
1397 put32 (dst, 0); /* bfReserved1 + bfReserved2 */
1398 put32 (dst, 14 + 40); /* bfOffBits */
1399
1400 /* filling BIH */
1401 put32 (dst, 40); /* biSize */
1402 put32 (dst, width); /* biWidth */
1403 put32 (dst, height); /* biHeight */
1404 put16 (dst, 1); /* biPlanes */
1405 put16 (dst, 24); /* biBitCount */
1406 put32 (dst, BI_RGB); /* biCompression */
1407 put32 (dst, size); /* biSizeImage */
1408 put32 (dst, 0); /* biXPelsPerMeter */
1409 put32 (dst, 0); /* biYPelsPerMeter */
1410 put32 (dst, 0); /* biClrUsed */
1411 put32 (dst, 0); /* biClrImportant */
1412
1413 if (!save_func ((gchar *)BFH_BIH, 14 + 40, error, user_data))
1414 return FALSE;
1415
1416 dst_line = buf = g_try_malloc (n_bytes: size);
1417 if (!buf) {
1418 g_set_error_literal (err: error,
1419 GDK_PIXBUF_ERROR,
1420 code: GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1421 _("Couldn’t allocate memory for saving BMP file"));
1422 return FALSE;
1423 }
1424
1425 /* saving as a bottom-up bmp */
1426 pixels += (height - 1) * src_stride;
1427 for (y = 0; y < height; ++y, pixels -= src_stride, dst_line += stride) {
1428 dst = dst_line;
1429 src = pixels;
1430 for (x = 0; x < width; ++x, dst += 3, src += channel) {
1431 dst[0] = src[2];
1432 dst[1] = src[1];
1433 dst[2] = src[0];
1434 }
1435 }
1436 ret = save_func ((gchar *)buf, size, error, user_data);
1437 g_free (mem: buf);
1438
1439 return ret;
1440}
1441
1442static gboolean
1443save_to_file_cb (const gchar *buf,
1444 gsize count,
1445 GError **error,
1446 gpointer data)
1447{
1448 gint bytes;
1449
1450 while (count > 0) {
1451 bytes = fwrite (ptr: buf, size: sizeof (gchar), n: count, s: (FILE *) data);
1452 if (bytes <= 0)
1453 break;
1454 count -= bytes;
1455 buf += bytes;
1456 }
1457
1458 if (count) {
1459 g_set_error_literal (err: error,
1460 GDK_PIXBUF_ERROR,
1461 code: GDK_PIXBUF_ERROR_FAILED,
1462 _("Couldn’t write to BMP file"));
1463 return FALSE;
1464 }
1465
1466 return TRUE;
1467}
1468
1469static gboolean
1470gdk_pixbuf__bmp_image_save (FILE *f,
1471 GdkPixbuf *pixbuf,
1472 gchar **keys,
1473 gchar **values,
1474 GError **error)
1475{
1476 return gdk_pixbuf__bmp_image_save_to_callback (save_func: save_to_file_cb,
1477 user_data: f, pixbuf, keys,
1478 values, error);
1479}
1480
1481#ifndef INCLUDE_bmp
1482#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1483#else
1484#define MODULE_ENTRY(function) void _gdk_pixbuf__bmp_ ## function
1485#endif
1486
1487MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1488{
1489 module->begin_load = gdk_pixbuf__bmp_image_begin_load;
1490 module->stop_load = gdk_pixbuf__bmp_image_stop_load;
1491 module->load_increment = gdk_pixbuf__bmp_image_load_increment;
1492 module->save = gdk_pixbuf__bmp_image_save;
1493 module->save_to_callback = gdk_pixbuf__bmp_image_save_to_callback;
1494}
1495
1496MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1497{
1498 static const GdkPixbufModulePattern signature[] = {
1499 { "BM", NULL, 100 },
1500 { NULL, NULL, 0 }
1501 };
1502 static const gchar * mime_types[] = {
1503 "image/bmp",
1504 "image/x-bmp",
1505 "image/x-MS-bmp",
1506 NULL
1507 };
1508 static const gchar * extensions[] = {
1509 "bmp",
1510 NULL
1511 };
1512
1513 info->name = "bmp";
1514 info->signature = (GdkPixbufModulePattern *) signature;
1515 info->description = NC_("image format", "BMP");
1516 info->mime_types = (gchar **) mime_types;
1517 info->extensions = (gchar **) extensions;
1518 info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1519 info->license = "LGPL";
1520}
1521
1522

source code of gtk/subprojects/gdk-pixbuf/gdk-pixbuf/io-bmp.c