/src/graphicsmagick/coders/dib.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2025 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % |
5 | | % This program is covered by multiple licenses, which are described in |
6 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
7 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
8 | | % |
9 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
10 | | % % |
11 | | % % |
12 | | % % |
13 | | % DDDD IIIII BBBB % |
14 | | % D D I B B % |
15 | | % D D I BBBB % |
16 | | % D D I B B % |
17 | | % DDDD IIIII BBBB % |
18 | | % % |
19 | | % % |
20 | | % Read/Write Windows DIB Image Format. % |
21 | | % % |
22 | | % % |
23 | | % Software Design % |
24 | | % John Cristy % |
25 | | % July 1992 % |
26 | | % % |
27 | | % % |
28 | | % % |
29 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
30 | | % |
31 | | % |
32 | | */ |
33 | | |
34 | | /* |
35 | | Include declarations. |
36 | | */ |
37 | | #include "magick/studio.h" |
38 | | #include "magick/analyze.h" |
39 | | #include "magick/blob.h" |
40 | | #include "magick/colormap.h" |
41 | | #include "magick/log.h" |
42 | | #include "magick/magick.h" |
43 | | #include "magick/monitor.h" |
44 | | #include "magick/pixel_cache.h" |
45 | | #include "magick/render.h" |
46 | | #include "magick/transform.h" |
47 | | #include "magick/utility.h" |
48 | | |
49 | | /* |
50 | | Macro definitions (from Windows wingdi.h). |
51 | | */ |
52 | | #undef BI_RLE8 |
53 | 1.22M | #define BI_RLE8 1 |
54 | | |
55 | | /* |
56 | | Typedef declarations. |
57 | | */ |
58 | | typedef struct _DIBInfo |
59 | | { |
60 | | magick_uint32_t |
61 | | header_size; |
62 | | |
63 | | magick_int32_t |
64 | | width, |
65 | | height; |
66 | | |
67 | | magick_uint16_t |
68 | | planes, |
69 | | bits_per_pixel; |
70 | | |
71 | | magick_uint32_t |
72 | | compression, /* 0=uncompressed, 1=8bit RLE, 2=4bit RLE, 3=RGB masked */ |
73 | | image_size, |
74 | | x_pixels, |
75 | | y_pixels, |
76 | | number_colors, |
77 | | colors_important; |
78 | | |
79 | | magick_uint16_t |
80 | | red_mask, |
81 | | green_mask, |
82 | | blue_mask, |
83 | | alpha_mask; |
84 | | |
85 | | magick_int32_t |
86 | | colorspace; |
87 | | |
88 | | PointInfo |
89 | | red_primary, |
90 | | green_primary, |
91 | | blue_primary, |
92 | | gamma_scale; |
93 | | } DIBInfo; |
94 | | |
95 | | /* |
96 | | Forward declarations. |
97 | | */ |
98 | | static unsigned int |
99 | | WriteDIBImage(const ImageInfo *,Image *); |
100 | | |
101 | | static void LogDIBInfo(const DIBInfo *dib_info) |
102 | 91.6k | { |
103 | | /* |
104 | | Dump 40-byte version 3+ bitmap header. |
105 | | BMP version 4 has same members, but is 108 bytes. |
106 | | */ |
107 | 91.6k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
108 | 91.6k | "DIB Header:\n" |
109 | 91.6k | " Header Size: %u\n" |
110 | 91.6k | " Width: %d\n" |
111 | 91.6k | " Height: %d\n" |
112 | 91.6k | " Planes: %u\n" |
113 | 91.6k | " Bits Per Pixel: %u\n" |
114 | 91.6k | " Compression: %u\n" |
115 | 91.6k | " Size Of Bitmap: %u\n" |
116 | 91.6k | " Horizontal Resolution:%u\n" |
117 | 91.6k | " Vertical Resolution: %u\n" |
118 | 91.6k | " Colors Used: %u\n" |
119 | 91.6k | " Colors Important: %u", |
120 | 91.6k | (unsigned int) dib_info->header_size, |
121 | 91.6k | (signed int) dib_info->width, |
122 | 91.6k | (signed int) dib_info->height, |
123 | 91.6k | (unsigned int) dib_info->planes, |
124 | 91.6k | (unsigned int) dib_info->bits_per_pixel, |
125 | 91.6k | (unsigned int) dib_info->compression, |
126 | 91.6k | (unsigned int) dib_info->image_size, |
127 | 91.6k | (unsigned int) dib_info->x_pixels, |
128 | 91.6k | (unsigned int) dib_info->y_pixels, |
129 | 91.6k | (unsigned int) dib_info->number_colors, |
130 | 91.6k | (unsigned int) dib_info->colors_important |
131 | 91.6k | ); |
132 | 91.6k | } |
133 | | /* |
134 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
135 | | % % |
136 | | % % |
137 | | % % |
138 | | % D e c o d e I m a g e % |
139 | | % % |
140 | | % % |
141 | | % % |
142 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
143 | | % |
144 | | % Method DecodeImage unpacks the packed image pixels into runlength-encoded |
145 | | % pixel packets. |
146 | | % |
147 | | % The format of the DecodeImage method is: |
148 | | % |
149 | | % unsigned int DecodeImage(Image *image,const unsigned long compression, |
150 | | % unsigned char *pixels) |
151 | | % |
152 | | % A description of each parameter follows: |
153 | | % |
154 | | % o status: Method DecodeImage returns True if all the pixels are |
155 | | % uncompressed without error, otherwise False. |
156 | | % |
157 | | % o image: The address of a structure of type Image. |
158 | | % |
159 | | % o compression: A value of 1 means the compressed pixels are runlength |
160 | | % encoded for a 256-color bitmap. A value of 2 means a 16-color bitmap. |
161 | | % |
162 | | % o pixels: The address of a byte (8 bits) array of pixel data created by |
163 | | % the decoding process. |
164 | | % |
165 | | % o pixels_size: The size of the allocated buffer array. |
166 | | % |
167 | | % |
168 | | */ |
169 | | static MagickPassFail DecodeImage(Image *image,const unsigned long compression, |
170 | | unsigned char *pixels, const size_t pixels_size) |
171 | 9.37k | { |
172 | 9.37k | unsigned long |
173 | 9.37k | x, |
174 | 9.37k | y; |
175 | | |
176 | 9.37k | unsigned int |
177 | 9.37k | i; |
178 | | |
179 | 9.37k | int |
180 | 9.37k | byte, |
181 | 9.37k | count; |
182 | | |
183 | 9.37k | register unsigned char |
184 | 9.37k | *q; |
185 | | |
186 | 9.37k | unsigned char |
187 | 9.37k | *end; |
188 | | |
189 | 9.37k | assert(image != (Image *) NULL); |
190 | 9.37k | assert(pixels != (unsigned char *) NULL); |
191 | 9.37k | if (image->logging) |
192 | 9.37k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
193 | 9.37k | " Decoding RLE compressed pixels to" |
194 | 9.37k | " %" MAGICK_SIZE_T_F "u bytes", |
195 | 9.37k | (MAGICK_SIZE_T) image->rows*(size_t)image->columns); |
196 | | |
197 | 9.37k | byte=0; |
198 | 9.37k | x=0; |
199 | 9.37k | q=pixels; |
200 | 9.37k | end=pixels + pixels_size; |
201 | | /* |
202 | | Decompress sufficient data to support the number of pixels (or |
203 | | rows) in the image and then return. |
204 | | |
205 | | Do not wait to read the final EOL and EOI markers (if not yet |
206 | | encountered) since we always read this marker just before we |
207 | | return. |
208 | | */ |
209 | 1.22M | for (y=0; y < image->rows; ) |
210 | 1.21M | { |
211 | 1.21M | if (q < pixels || q >= end) |
212 | 4.06k | { |
213 | 4.06k | if (image->logging) |
214 | 4.06k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
215 | 4.06k | " Decode buffer full (y=%lu, " |
216 | 4.06k | "pixels_size=%" MAGICK_SIZE_T_F "u, " |
217 | 4.06k | "pixels=%p, q=%p, end=%p)", |
218 | 4.06k | y, (MAGICK_SIZE_T) pixels_size, |
219 | 4.06k | pixels, q, end); |
220 | 4.06k | break; |
221 | 4.06k | } |
222 | 1.21M | count=ReadBlobByte(image); |
223 | 1.21M | if (count == EOF) |
224 | 353 | return MagickFail; |
225 | 1.21M | if (count > 0) |
226 | 1.13M | { |
227 | 1.13M | count=Min(count, end - q); |
228 | | /* |
229 | | Encoded mode. |
230 | | */ |
231 | 1.13M | byte=ReadBlobByte(image); |
232 | 1.13M | if (byte == EOF) |
233 | 493 | return MagickFail; |
234 | 1.13M | if (compression == BI_RLE8) |
235 | 1.13M | { |
236 | 164M | for ( i=count; i != 0; --i ) |
237 | 163M | { |
238 | 163M | *q++=(unsigned char) byte; |
239 | 163M | } |
240 | 1.13M | } |
241 | 3.44k | else |
242 | 3.44k | { |
243 | 223k | for ( i=0; i < (unsigned int) count; i++ ) |
244 | 219k | { |
245 | 219k | *q++=(unsigned char) |
246 | 219k | ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f)); |
247 | 219k | } |
248 | 3.44k | } |
249 | 1.13M | x+=count; |
250 | 1.13M | } |
251 | 80.0k | else |
252 | 80.0k | { |
253 | | /* |
254 | | Escape mode. |
255 | | */ |
256 | 80.0k | count=ReadBlobByte(image); |
257 | 80.0k | if (count == EOF) |
258 | 138 | return MagickFail; |
259 | 79.8k | if (count == 0x01) |
260 | 405 | { |
261 | 405 | if (image->logging) |
262 | 405 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
263 | 405 | " RLE Escape code encountered"); |
264 | 405 | goto rle_decode_done; |
265 | 405 | } |
266 | 79.4k | switch (count) |
267 | 79.4k | { |
268 | 32.8k | case 0x00: |
269 | 32.8k | { |
270 | | /* |
271 | | End of line. |
272 | | */ |
273 | 32.8k | x=0; |
274 | 32.8k | y++; |
275 | 32.8k | q=pixels+(size_t) y*image->columns; |
276 | 32.8k | break; |
277 | 0 | } |
278 | 1.44k | case 0x02: |
279 | 1.44k | { |
280 | | /* |
281 | | Delta mode. |
282 | | */ |
283 | 1.44k | byte=ReadBlobByte(image); |
284 | 1.44k | if (byte == EOF) |
285 | 5 | return MagickFail; |
286 | 1.44k | x+=byte; |
287 | 1.44k | byte=ReadBlobByte(image); |
288 | 1.44k | if (byte == EOF) |
289 | 16 | return MagickFail; |
290 | 1.42k | y+=byte; |
291 | 1.42k | q=pixels+y*(size_t) image->columns+x; |
292 | 1.42k | break; |
293 | 1.44k | } |
294 | 45.1k | default: |
295 | 45.1k | { |
296 | | /* |
297 | | Absolute mode. |
298 | | */ |
299 | 45.1k | count=Min(count, end - q); |
300 | 45.1k | if (count < 0) |
301 | 0 | return MagickFail; |
302 | 45.1k | if (compression == BI_RLE8) |
303 | 5.09M | for (i=count; i != 0; --i) |
304 | 5.04M | { |
305 | 5.04M | byte=ReadBlobByte(image); |
306 | 5.04M | if (byte == EOF) |
307 | 156 | return MagickFail; |
308 | 5.04M | *q++=byte; |
309 | 5.04M | } |
310 | 2.55k | else |
311 | 35.5k | for (i=0; i < (unsigned int) count; i++) |
312 | 33.0k | { |
313 | 33.0k | if ((i & 0x01) == 0) |
314 | 17.1k | { |
315 | 17.1k | byte=ReadBlobByte(image); |
316 | 17.1k | if (byte == EOF) |
317 | 66 | return MagickFail; |
318 | 17.1k | } |
319 | 32.9k | *q++=(unsigned char) |
320 | 32.9k | ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f)); |
321 | 32.9k | } |
322 | 44.9k | x+=count; |
323 | | /* |
324 | | Read pad byte. |
325 | | */ |
326 | 44.9k | if (compression == BI_RLE8) |
327 | 42.4k | { |
328 | 42.4k | if (count & 0x01) |
329 | 36.5k | if (ReadBlobByte(image) == EOF) |
330 | 12 | return MagickFail; |
331 | 42.4k | } |
332 | 2.48k | else |
333 | 2.48k | if (((count & 0x03) == 1) || ((count & 0x03) == 2)) |
334 | 1.67k | if (ReadBlobByte(image) == EOF) |
335 | 34 | return MagickFail; |
336 | 44.9k | break; |
337 | 44.9k | } |
338 | 79.4k | } |
339 | 79.4k | } |
340 | 1.21M | if (QuantumTick(y,image->rows)) |
341 | 115k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
342 | 115k | LoadImageText,image->filename, |
343 | 115k | image->columns,image->rows)) |
344 | 0 | break; |
345 | 1.21M | } |
346 | 7.69k | (void) ReadBlobByte(image); /* end of line */ |
347 | 7.69k | (void) ReadBlobByte(image); |
348 | 8.10k | rle_decode_done: |
349 | 8.10k | if (image->logging) |
350 | 8.10k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
351 | 8.10k | " Decoded %" MAGICK_SIZE_T_F "u bytes", |
352 | 8.10k | (MAGICK_SIZE_T) (q-pixels)); |
353 | 8.10k | if ((MAGICK_SIZE_T) (q-pixels) < pixels_size) |
354 | 405 | { |
355 | 405 | if (image->logging) |
356 | 405 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
357 | 405 | " RLE decoded output is truncated"); |
358 | 405 | return MagickFail; |
359 | 405 | } |
360 | 7.69k | return(MagickPass); |
361 | 8.10k | } |
362 | | |
363 | | /* |
364 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
365 | | % % |
366 | | % % |
367 | | % % |
368 | | % E n c o d e I m a g e % |
369 | | % % |
370 | | % % |
371 | | % % |
372 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
373 | | % |
374 | | % Method EncodeImage compresses pixels using a runlength encoded format. |
375 | | % |
376 | | % The format of the EncodeImage method is: |
377 | | % |
378 | | % static unsigned int EncodeImage(Image *image, |
379 | | % const unsigned long bytes_per_line,const unsigned char *pixels, |
380 | | % unsigned char *compressed_pixels) |
381 | | % |
382 | | % A description of each parameter follows: |
383 | | % |
384 | | % o status: Method EncodeImage returns the number of bytes in the |
385 | | % runlength encoded compress_pixels array. |
386 | | % |
387 | | % o image: A pointer to an Image structure. |
388 | | % |
389 | | % o bytes_per_line: The number of bytes in a scanline of compressed pixels |
390 | | % |
391 | | % o pixels: The address of a byte (8 bits) array of pixel data created by |
392 | | % the compression process. |
393 | | % |
394 | | % o compressed_pixels: The address of a byte (8 bits) array of compressed |
395 | | % pixel data. |
396 | | % |
397 | | % |
398 | | */ |
399 | | static size_t EncodeImage(Image *image,const size_t bytes_per_line, |
400 | | const unsigned char *pixels,unsigned char *compressed_pixels) |
401 | 260 | { |
402 | 260 | unsigned long |
403 | 260 | y; |
404 | | |
405 | 260 | register const unsigned char |
406 | 260 | *p; |
407 | | |
408 | 260 | register unsigned long |
409 | 260 | i, |
410 | 260 | x; |
411 | | |
412 | 260 | register unsigned char |
413 | 260 | *q; |
414 | | |
415 | | /* |
416 | | Runlength encode pixels. |
417 | | */ |
418 | 260 | assert(image != (Image *) NULL); |
419 | 260 | assert(pixels != (const unsigned char *) NULL); |
420 | 260 | assert(compressed_pixels != (unsigned char *) NULL); |
421 | 260 | p=pixels; |
422 | 260 | q=compressed_pixels; |
423 | 260 | i=0; |
424 | 75.9k | for (y=0; y < image->rows; y++) |
425 | 75.7k | { |
426 | 35.4M | for (x=0; x < bytes_per_line; x+=i) |
427 | 35.4M | { |
428 | | /* |
429 | | Determine runlength. |
430 | | */ |
431 | 103M | for (i=1; (((size_t) x+i) < bytes_per_line); i++) |
432 | 103M | if ((*(p+i) != *p) || (i == 255U)) |
433 | 35.3M | break; |
434 | 35.4M | *q++=(unsigned char) i; |
435 | 35.4M | *q++=(*p); |
436 | 35.4M | p+=i; |
437 | 35.4M | } |
438 | | /* |
439 | | End of line. |
440 | | */ |
441 | 75.7k | *q++=0x00; |
442 | 75.7k | *q++=0x00; |
443 | 75.7k | if (QuantumTick(y,image->rows)) |
444 | 19.8k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
445 | 19.8k | SaveImageText,image->filename, |
446 | 19.8k | image->columns,image->rows)) |
447 | 0 | break; |
448 | 75.7k | } |
449 | | /* |
450 | | End of bitmap. |
451 | | */ |
452 | 260 | *q++=0; |
453 | 260 | *q++=0x01; |
454 | 260 | return((size_t) (q-compressed_pixels)); |
455 | 260 | } |
456 | | |
457 | | /* |
458 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
459 | | % % |
460 | | % % |
461 | | % % |
462 | | % I s D I B % |
463 | | % % |
464 | | % % |
465 | | % % |
466 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
467 | | % |
468 | | % Method IsDIB returns True if the image format type, identified by the |
469 | | % magick string, is DIB. |
470 | | % |
471 | | % The format of the IsDIB method is: |
472 | | % |
473 | | % unsigned int IsDIB(const unsigned char *magick,const size_t length) |
474 | | % |
475 | | % A description of each parameter follows: |
476 | | % |
477 | | % o status: Method IsDIB returns True if the image format type is DIB. |
478 | | % |
479 | | % o magick: This string is generally the first few bytes of an image file |
480 | | % or blob. |
481 | | % |
482 | | % o length: Specifies the length of the magick string. |
483 | | % |
484 | | % |
485 | | */ |
486 | | static unsigned int IsDIB(const unsigned char *magick,const size_t length) |
487 | 0 | { |
488 | 0 | if (length < 2) |
489 | 0 | return(False); |
490 | 0 | if( (*magick == 40) && (*(magick+1)==0)) |
491 | 0 | return(True); |
492 | 0 | return(False); |
493 | 0 | } |
494 | | |
495 | | /* |
496 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
497 | | % % |
498 | | % % |
499 | | % % |
500 | | % R e a d D I B I m a g e % |
501 | | % % |
502 | | % % |
503 | | % % |
504 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
505 | | % |
506 | | % Method ReadDIBImage reads a Microsoft Windows bitmap image file and |
507 | | % returns it. It allocates the memory necessary for the new Image structure |
508 | | % and returns a pointer to the new image. |
509 | | % |
510 | | % The format of the ReadDIBImage method is: |
511 | | % |
512 | | % image=ReadDIBImage(image_info) |
513 | | % |
514 | | % A description of each parameter follows: |
515 | | % |
516 | | % o image: Method ReadDIBImage returns a pointer to the image after |
517 | | % reading. A null image is returned if there is a memory shortage or |
518 | | % if the image cannot be read. |
519 | | % |
520 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
521 | | % |
522 | | % o exception: return any errors or warnings in this structure. |
523 | | % |
524 | | % |
525 | | */ |
526 | | static Image *ReadDIBImage(const ImageInfo *image_info,ExceptionInfo *exception) |
527 | 102k | { |
528 | 102k | DIBInfo |
529 | 102k | dib_info; |
530 | | |
531 | 102k | Image |
532 | 102k | *image; |
533 | | |
534 | 102k | IndexPacket |
535 | 102k | index; |
536 | | |
537 | 102k | long |
538 | 102k | bit, |
539 | 102k | y; |
540 | | |
541 | 102k | register IndexPacket |
542 | 102k | *indexes; |
543 | | |
544 | 102k | register long |
545 | 102k | x; |
546 | | |
547 | 102k | register PixelPacket |
548 | 102k | *q; |
549 | | |
550 | 102k | register long |
551 | 102k | i; |
552 | | |
553 | 102k | register unsigned char |
554 | 102k | *p; |
555 | | |
556 | 102k | TimerInfo |
557 | 102k | timer; |
558 | | |
559 | 102k | size_t |
560 | 102k | count, |
561 | 102k | length; |
562 | | |
563 | 102k | unsigned char |
564 | 102k | *pixels; |
565 | | |
566 | 102k | unsigned int |
567 | 102k | status; |
568 | | |
569 | 102k | size_t |
570 | 102k | bytes_per_line, |
571 | 102k | packet_size, |
572 | 102k | pixels_size; |
573 | | |
574 | 102k | magick_off_t |
575 | 102k | file_size; |
576 | | |
577 | | /* |
578 | | Open image file. |
579 | | */ |
580 | 102k | assert(image_info != (const ImageInfo *) NULL); |
581 | 102k | assert(image_info->signature == MagickSignature); |
582 | 102k | assert(exception != (ExceptionInfo *) NULL); |
583 | 102k | assert(exception->signature == MagickSignature); |
584 | 102k | GetTimerInfo(&timer); |
585 | 102k | image=AllocateImage(image_info); |
586 | 102k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
587 | 102k | if (status == False) |
588 | 102k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
589 | 102k | file_size=GetBlobSize(image); |
590 | | /* |
591 | | Determine if this is a DIB file. |
592 | | */ |
593 | 102k | (void) memset(&dib_info,0,sizeof(DIBInfo)); |
594 | 102k | dib_info.header_size=ReadBlobLSBLong(image); |
595 | 102k | if (dib_info.header_size!=40) |
596 | 97.6k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
597 | | /* |
598 | | Microsoft Windows 3.X DIB image file. |
599 | | */ |
600 | | |
601 | | /* |
602 | | BMP v3 defines width and height as signed LONG (32 bit) values. If |
603 | | height is a positive number, then the image is a "bottom-up" |
604 | | bitmap with origin in the lower-left corner. If height is a |
605 | | negative number, then the image is a "top-down" bitmap with the |
606 | | origin in the upper-left corner. The meaning of negative values |
607 | | is not defined for width. |
608 | | */ |
609 | 97.6k | dib_info.width=ReadBlobLSBSignedLong(image); |
610 | 97.6k | dib_info.height=ReadBlobLSBSignedLong(image); |
611 | 97.6k | dib_info.planes=ReadBlobLSBShort(image); |
612 | 97.6k | dib_info.bits_per_pixel=ReadBlobLSBShort(image); |
613 | 97.6k | dib_info.compression=ReadBlobLSBLong(image); |
614 | 97.6k | dib_info.image_size=ReadBlobLSBLong(image); |
615 | 97.6k | dib_info.x_pixels=ReadBlobLSBLong(image); |
616 | 97.6k | dib_info.y_pixels=ReadBlobLSBLong(image); |
617 | 97.6k | dib_info.number_colors=ReadBlobLSBLong(image); |
618 | 97.6k | dib_info.colors_important=ReadBlobLSBLong(image); |
619 | 97.6k | if (EOFBlob(image)) |
620 | 91.6k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
621 | 91.6k | LogDIBInfo(&dib_info); |
622 | 91.6k | if (dib_info.planes != 1) |
623 | 83.3k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
624 | 83.3k | if ((dib_info.bits_per_pixel != 1) && |
625 | 58.9k | (dib_info.bits_per_pixel != 4) && |
626 | 51.2k | (dib_info.bits_per_pixel != 8) && |
627 | 40.3k | (dib_info.bits_per_pixel != 16) && |
628 | 35.9k | (dib_info.bits_per_pixel != 24) && |
629 | 30.7k | (dib_info.bits_per_pixel != 32)) |
630 | 80.4k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
631 | 80.4k | if ((dib_info.compression == 3) && ((dib_info.bits_per_pixel == 16) || |
632 | 1.06k | (dib_info.bits_per_pixel == 32))) |
633 | 1.84k | { |
634 | 1.84k | dib_info.red_mask=ReadBlobLSBShort(image); |
635 | 1.84k | dib_info.green_mask=ReadBlobLSBShort(image); |
636 | 1.84k | dib_info.blue_mask=ReadBlobLSBShort(image); |
637 | 1.84k | } |
638 | 80.4k | if (EOFBlob(image)) |
639 | 79.7k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
640 | 79.7k | if (dib_info.width <= 0) |
641 | 78.0k | ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image); |
642 | 78.0k | if (dib_info.height == 0) |
643 | 74.9k | ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image); |
644 | 74.9k | if (dib_info.height < -2147483647) |
645 | 74.3k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
646 | 74.3k | image->matte=dib_info.bits_per_pixel == 32; |
647 | 74.3k | image->columns=AbsoluteValue(dib_info.width); |
648 | 74.3k | image->rows=AbsoluteValue(dib_info.height); |
649 | 74.3k | image->depth=8; |
650 | 74.3k | if (dib_info.number_colors > 256) |
651 | 58.5k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
652 | 58.5k | if (dib_info.colors_important > 256) |
653 | 47.9k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
654 | 47.9k | if ((dib_info.number_colors != 0) && (dib_info.bits_per_pixel > 8)) |
655 | 43.0k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
656 | 43.0k | if ((dib_info.image_size != 0U) && (dib_info.image_size > file_size)) |
657 | 34.9k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
658 | 34.9k | if ((dib_info.number_colors != 0) || (dib_info.bits_per_pixel <= 8)) |
659 | 24.4k | { |
660 | 24.4k | image->storage_class=PseudoClass; |
661 | 24.4k | image->colors=dib_info.number_colors; |
662 | 24.4k | if (image->colors == 0) |
663 | 9.02k | image->colors=1L << dib_info.bits_per_pixel; |
664 | 24.4k | } |
665 | 34.9k | if (image_info->size) |
666 | 1.35k | { |
667 | 1.35k | int |
668 | 1.35k | flags; |
669 | | |
670 | 1.35k | RectangleInfo |
671 | 1.35k | geometry; |
672 | | |
673 | 1.35k | flags=GetGeometry(image_info->size,&geometry.x,&geometry.y, |
674 | 1.35k | &geometry.width,&geometry.height); |
675 | 1.35k | if ((flags & WidthValue) && (geometry.width != 0) |
676 | 1.35k | && (geometry.width < image->columns)) |
677 | 1.00k | image->columns=geometry.width; |
678 | 1.35k | if ((flags & HeightValue) && (geometry.height != 0) |
679 | 1.35k | && (geometry.height < image->rows)) |
680 | 1.26k | image->rows=geometry.height; |
681 | 1.35k | } |
682 | | |
683 | 34.9k | if (CheckImagePixelLimits(image, exception) != MagickPass) |
684 | 22.8k | ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
685 | | |
686 | 12.0k | if (image->storage_class == PseudoClass) |
687 | 10.6k | { |
688 | 10.6k | unsigned char |
689 | 10.6k | *dib_colormap; |
690 | | |
691 | 10.6k | size_t |
692 | 10.6k | packet_size; |
693 | | |
694 | | /* |
695 | | Read DIB raster colormap. |
696 | | */ |
697 | 10.6k | if (!AllocateImageColormap(image,image->colors)) |
698 | 10.6k | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
699 | 10.6k | dib_colormap=MagickAllocateResourceLimitedArray(unsigned char *,image->colors,4); |
700 | 10.6k | if (dib_colormap == (unsigned char *) NULL) |
701 | 10.6k | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
702 | 10.6k | packet_size=4; |
703 | 10.6k | if ((count=ReadBlob(image,packet_size*image->colors,(char *) dib_colormap)) |
704 | 10.6k | != packet_size*image->colors) |
705 | 993 | { |
706 | 993 | if (image->logging) |
707 | 993 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
708 | 993 | "Read %" MAGICK_SIZE_T_F "u bytes from blob" |
709 | 993 | " (expected %" MAGICK_SIZE_T_F "u bytes)", |
710 | 993 | (MAGICK_SIZE_T) count, |
711 | 993 | (MAGICK_SIZE_T) packet_size*image->colors); |
712 | 993 | MagickFreeResourceLimitedMemory(dib_colormap); |
713 | 993 | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
714 | 0 | } |
715 | 9.67k | p=dib_colormap; |
716 | 59.1k | for (i=0; i < (long) image->colors; i++) |
717 | 49.4k | { |
718 | 49.4k | image->colormap[i].blue=ScaleCharToQuantum(*p++); |
719 | 49.4k | image->colormap[i].green=ScaleCharToQuantum(*p++); |
720 | 49.4k | image->colormap[i].red=ScaleCharToQuantum(*p++); |
721 | 49.4k | if (packet_size == 4) |
722 | 49.4k | p++; |
723 | 49.4k | } |
724 | 9.67k | MagickFreeResourceLimitedMemory(dib_colormap); |
725 | 9.67k | } |
726 | | /* |
727 | | Read image data. |
728 | | */ |
729 | 11.0k | packet_size=dib_info.bits_per_pixel; |
730 | 11.0k | if (dib_info.compression == 2) |
731 | 968 | packet_size<<=1; |
732 | | |
733 | | /* |
734 | | Below emulates: |
735 | | bytes_per_line=4*((image->columns*dib_info.packet_size+31)/32); |
736 | | */ |
737 | 11.0k | bytes_per_line=MagickArraySize(image->columns,packet_size); |
738 | 11.0k | if ((bytes_per_line > 0) && (~((size_t) 0) - bytes_per_line) > 31) |
739 | 11.0k | bytes_per_line = MagickArraySize(4,(bytes_per_line+31)/32); |
740 | 11.0k | if (bytes_per_line == 0) |
741 | 11.0k | ThrowReaderException(CoderError,ArithmeticOverflow,image); |
742 | 11.0k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
743 | 11.0k | "%" MAGICK_SIZE_T_F "u bytes per line", |
744 | 11.0k | (MAGICK_SIZE_T) bytes_per_line); |
745 | | /* |
746 | | Validate that file data size is suitable for claimed dimensions. |
747 | | */ |
748 | 11.0k | { |
749 | 11.0k | size_t |
750 | 11.0k | maximum_image_size; |
751 | | |
752 | 11.0k | maximum_image_size=MagickArraySize(bytes_per_line,image->rows); |
753 | 11.0k | if ((maximum_image_size == 0) || |
754 | 11.0k | (maximum_image_size > |
755 | 11.0k | ((size_t) file_size * ((dib_info.compression == 1 ? 256 : |
756 | 11.0k | dib_info.compression == 2 ? 8 : 1))))) |
757 | 10.9k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
758 | 10.9k | } |
759 | | |
760 | | /* |
761 | | FIXME: Need to add support for compression=3 images. Size |
762 | | calculations are wrong and there is no support for applying the |
763 | | masks. |
764 | | */ |
765 | 0 | length=MagickArraySize(bytes_per_line,image->rows); |
766 | 10.9k | if (length == 0) |
767 | 10.9k | ThrowReaderException(CoderError,ArithmeticOverflow,image); |
768 | 10.9k | if ((image->columns+1UL) < image->columns) |
769 | 10.9k | ThrowReaderException(CoderError,ArithmeticOverflow,image); |
770 | 10.9k | pixels_size=MagickArraySize(image->rows,Max(bytes_per_line,(size_t) image->columns+1)); |
771 | 10.9k | if (pixels_size == 0) |
772 | 10.9k | ThrowReaderException(CoderError,ArithmeticOverflow,image); |
773 | 10.9k | pixels=MagickAllocateResourceLimitedMemory(unsigned char *,pixels_size); |
774 | 10.9k | if (pixels == (unsigned char *) NULL) |
775 | 10.9k | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
776 | 10.9k | if ((dib_info.compression == 0) || (dib_info.compression == 3)) |
777 | 1.58k | { |
778 | 1.58k | if ((count=ReadBlob(image,length,(char *) pixels)) != length) |
779 | 132 | { |
780 | 132 | if (image->logging) |
781 | 132 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
782 | 132 | "Read %" MAGICK_SIZE_T_F "u bytes from blob" |
783 | 132 | " (expected %" MAGICK_SIZE_T_F "u bytes)", |
784 | 132 | (MAGICK_SIZE_T) count, |
785 | 132 | (MAGICK_SIZE_T) length); |
786 | 132 | MagickFreeResourceLimitedMemory(pixels); |
787 | 132 | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
788 | 0 | } |
789 | 1.58k | } |
790 | 9.37k | else |
791 | 9.37k | { |
792 | | /* |
793 | | Convert run-length encoded raster pixels. |
794 | | |
795 | | DecodeImage() normally decompresses to rows*columns bytes of data. |
796 | | */ |
797 | 9.37k | (void) memset(pixels,0,pixels_size); |
798 | 9.37k | status=DecodeImage(image,dib_info.compression,pixels, |
799 | 9.37k | (size_t) image->rows*image->columns); |
800 | 9.37k | if (status == False) |
801 | 1.67k | { |
802 | 1.67k | MagickFreeResourceLimitedMemory(pixels); |
803 | 1.67k | ThrowReaderException(CorruptImageError,UnableToRunlengthDecodeImage, |
804 | 1.67k | image); |
805 | 0 | } |
806 | 9.37k | } |
807 | | /* |
808 | | Initialize image structure. |
809 | | */ |
810 | 9.14k | image->units=PixelsPerCentimeterResolution; |
811 | 9.14k | image->x_resolution=dib_info.x_pixels/100.0; |
812 | 9.14k | image->y_resolution=dib_info.y_pixels/100.0; |
813 | | /* |
814 | | Convert DIB raster image to pixel packets. |
815 | | */ |
816 | 9.14k | switch (dib_info.bits_per_pixel) |
817 | 9.14k | { |
818 | 655 | case 1: |
819 | 655 | { |
820 | | /* |
821 | | Convert bitmap scanline. |
822 | | */ |
823 | 101k | for (y=(long) image->rows-1; y >= 0; y--) |
824 | 101k | { |
825 | 101k | p=pixels+((size_t) image->rows-y-1)*bytes_per_line; |
826 | 101k | q=SetImagePixels(image,0,y,image->columns,1); |
827 | 101k | if (q == (PixelPacket *) NULL) |
828 | 0 | break; |
829 | 101k | indexes=AccessMutableIndexes(image); |
830 | 13.1M | for (x=0; x < ((long) image->columns-7); x+=8) |
831 | 13.0M | { |
832 | 117M | for (bit=0; bit < 8; bit++) |
833 | 104M | { |
834 | 104M | index=((*p) & (0x80 >> bit) ? 0x01 : 0x00); |
835 | 104M | VerifyColormapIndex(image,index); |
836 | 104M | indexes[x+bit]=index; |
837 | 104M | *q++=image->colormap[index]; |
838 | 104M | } |
839 | 13.0M | p++; |
840 | 13.0M | } |
841 | 101k | if ((image->columns % 8) != 0) |
842 | 54.7k | { |
843 | 179k | for (bit=0; bit < (long) (image->columns % 8); bit++) |
844 | 124k | { |
845 | 124k | index=((*p) & (0x80 >> bit) ? 0x01 : 0x00); |
846 | 124k | VerifyColormapIndex(image,index); |
847 | 124k | indexes[x+bit]=index; |
848 | 124k | *q++=image->colormap[index]; |
849 | 124k | } |
850 | 54.7k | p++; |
851 | 54.7k | } |
852 | 101k | if (!SyncImagePixels(image)) |
853 | 0 | break; |
854 | 101k | if (image->previous == (Image *) NULL) |
855 | 101k | if (QuantumTick(y,image->rows)) |
856 | 32.2k | { |
857 | 32.2k | status=MagickMonitorFormatted((size_t) image->rows-y-1,image->rows, |
858 | 32.2k | exception,LoadImageText, |
859 | 32.2k | image->filename, |
860 | 32.2k | image->columns,image->rows); |
861 | 32.2k | if (status == False) |
862 | 0 | break; |
863 | 32.2k | } |
864 | 101k | } |
865 | 655 | break; |
866 | 0 | } |
867 | 3.38k | case 4: |
868 | 3.38k | { |
869 | | /* |
870 | | Convert PseudoColor scanline. |
871 | | */ |
872 | 33.4k | for (y=(long) image->rows-1; y >= 0; y--) |
873 | 30.0k | { |
874 | 30.0k | p=pixels+((size_t) image->rows-y-1)*bytes_per_line; |
875 | 30.0k | q=SetImagePixels(image,0,y,image->columns,1); |
876 | 30.0k | if (q == (PixelPacket *) NULL) |
877 | 0 | break; |
878 | 30.0k | indexes=AccessMutableIndexes(image); |
879 | 7.09M | for (x=0; x < ((long) image->columns-1); x+=2) |
880 | 7.06M | { |
881 | 7.06M | index=(IndexPacket) ((*p >> 4) & 0xf); |
882 | 7.06M | VerifyColormapIndex(image,index); |
883 | 7.06M | indexes[x]=index; |
884 | 7.06M | *q++=image->colormap[index]; |
885 | 7.06M | index=(IndexPacket) (*p & 0xf); |
886 | 7.06M | VerifyColormapIndex(image,index); |
887 | 7.06M | indexes[x+1]=index; |
888 | 7.06M | *q++=image->colormap[index]; |
889 | 7.06M | p++; |
890 | 7.06M | } |
891 | 30.0k | if ((image->columns % 2) != 0) |
892 | 25.8k | { |
893 | 25.8k | index=(IndexPacket) ((*p >> 4) & 0xf); |
894 | 25.8k | VerifyColormapIndex(image,index); |
895 | 25.8k | indexes[x]=index; |
896 | 25.8k | *q++=image->colormap[index]; |
897 | 25.8k | p++; |
898 | 25.8k | } |
899 | 30.0k | if (!SyncImagePixels(image)) |
900 | 0 | break; |
901 | 30.0k | if (image->previous == (Image *) NULL) |
902 | 30.0k | if (QuantumTick(y,image->rows)) |
903 | 14.2k | { |
904 | 14.2k | status=MagickMonitorFormatted((size_t) image->rows-y-1,image->rows, |
905 | 14.2k | exception,LoadImageText, |
906 | 14.2k | image->filename, |
907 | 14.2k | image->columns,image->rows); |
908 | 14.2k | if (status == False) |
909 | 0 | break; |
910 | 14.2k | } |
911 | 30.0k | } |
912 | 3.38k | break; |
913 | 0 | } |
914 | 4.32k | case 8: |
915 | 4.32k | { |
916 | | /* |
917 | | Convert PseudoColor scanline. |
918 | | */ |
919 | 4.32k | if ((dib_info.compression == 1) || (dib_info.compression == 2)) |
920 | 1.07k | bytes_per_line=image->columns; |
921 | 37.4k | for (y=(long) image->rows-1; y >= 0; y--) |
922 | 33.1k | { |
923 | 33.1k | p=pixels+((size_t) image->rows-y-1)*bytes_per_line; |
924 | 33.1k | q=SetImagePixels(image,0,y,image->columns,1); |
925 | 33.1k | if (q == (PixelPacket *) NULL) |
926 | 0 | break; |
927 | 33.1k | indexes=AccessMutableIndexes(image); |
928 | 425k | for (x=0; x < (long) image->columns; x++) |
929 | 392k | { |
930 | 392k | index=(IndexPacket) (*p); |
931 | 392k | VerifyColormapIndex(image,index); |
932 | 392k | indexes[x]=index; |
933 | 392k | *q=image->colormap[index]; |
934 | 392k | p++; |
935 | 392k | q++; |
936 | 392k | } |
937 | 33.1k | if (!SyncImagePixels(image)) |
938 | 0 | break; |
939 | 33.1k | if (image->previous == (Image *) NULL) |
940 | 33.1k | if (QuantumTick(y,image->rows)) |
941 | 16.4k | { |
942 | 16.4k | status=MagickMonitorFormatted((size_t) image->rows-y-1,image->rows, |
943 | 16.4k | exception,LoadImageText, |
944 | 16.4k | image->filename, |
945 | 16.4k | image->columns,image->rows); |
946 | 16.4k | if (status == False) |
947 | 0 | break; |
948 | 16.4k | } |
949 | 33.1k | } |
950 | 4.32k | break; |
951 | 0 | } |
952 | 408 | case 16: |
953 | 408 | { |
954 | 408 | unsigned short |
955 | 408 | word; |
956 | | |
957 | | /* |
958 | | Convert DirectColor (555 or 565) scanline. |
959 | | */ |
960 | 408 | image->storage_class=DirectClass; |
961 | 408 | if (dib_info.compression == 1) |
962 | 200 | bytes_per_line=(size_t) 2*image->columns; |
963 | 40.1k | for (y=(long) image->rows-1; y >= 0; y--) |
964 | 39.7k | { |
965 | 39.7k | p=pixels+((size_t) image->rows-y-1)*bytes_per_line; |
966 | 39.7k | q=SetImagePixels(image,0,y,image->columns,1); |
967 | 39.7k | if (q == (PixelPacket *) NULL) |
968 | 0 | break; |
969 | 1.05M | for (x=0; x < (long) image->columns; x++) |
970 | 1.01M | { |
971 | 1.01M | word=(*p++); |
972 | 1.01M | word|=(*p++ << 8); |
973 | 1.01M | if (dib_info.red_mask == 0) |
974 | 1.01M | { |
975 | 1.01M | q->red=ScaleCharToQuantum(ScaleColor5to8((word >> 10) & 0x1f)); |
976 | 1.01M | q->green=ScaleCharToQuantum(ScaleColor5to8((word >> 5) & 0x1f)); |
977 | 1.01M | q->blue=ScaleCharToQuantum(ScaleColor5to8(word & 0x1f)); |
978 | 1.01M | } |
979 | 599 | else |
980 | 599 | { |
981 | 599 | q->red=ScaleCharToQuantum(ScaleColor5to8((word >> 11) & 0x1f)); |
982 | 599 | q->green=ScaleCharToQuantum(ScaleColor6to8((word >> 5) & 0x3f)); |
983 | 599 | q->blue=ScaleCharToQuantum(ScaleColor5to8(word & 0x1f)); |
984 | 599 | } |
985 | 1.01M | q++; |
986 | 1.01M | } |
987 | 39.7k | if (!SyncImagePixels(image)) |
988 | 0 | break; |
989 | 39.7k | if (image->previous == (Image *) NULL) |
990 | 39.7k | if (QuantumTick(y,image->rows)) |
991 | 15.6k | { |
992 | 15.6k | status=MagickMonitorFormatted((size_t) image->rows-y-1,image->rows, |
993 | 15.6k | exception,LoadImageText, |
994 | 15.6k | image->filename, |
995 | 15.6k | image->columns,image->rows); |
996 | 15.6k | if (status == False) |
997 | 0 | break; |
998 | 15.6k | } |
999 | 39.7k | } |
1000 | 408 | break; |
1001 | 0 | } |
1002 | 197 | case 24: |
1003 | 371 | case 32: |
1004 | 371 | { |
1005 | | /* |
1006 | | Convert DirectColor scanline. |
1007 | | */ |
1008 | 39.2k | for (y=(long) image->rows-1; y >= 0; y--) |
1009 | 38.8k | { |
1010 | 38.8k | p=pixels+((size_t) image->rows-y-1)*bytes_per_line; |
1011 | 38.8k | q=SetImagePixels(image,0,y,image->columns,1); |
1012 | 38.8k | if (q == (PixelPacket *) NULL) |
1013 | 0 | break; |
1014 | 2.89M | for (x=0; x < (long) image->columns; x++) |
1015 | 2.85M | { |
1016 | 2.85M | q->blue=ScaleCharToQuantum(*p++); |
1017 | 2.85M | q->green=ScaleCharToQuantum(*p++); |
1018 | 2.85M | q->red=ScaleCharToQuantum(*p++); |
1019 | 2.85M | if (image->matte) |
1020 | 2.76M | q->opacity=ScaleCharToQuantum(*p++); |
1021 | 2.85M | q++; |
1022 | 2.85M | } |
1023 | 38.8k | if (!SyncImagePixels(image)) |
1024 | 0 | break; |
1025 | 38.8k | if (image->previous == (Image *) NULL) |
1026 | 38.8k | if (QuantumTick(y,image->rows)) |
1027 | 15.5k | { |
1028 | 15.5k | status=MagickMonitorFormatted((size_t) image->rows-y-1,image->rows, |
1029 | 15.5k | exception,LoadImageText, |
1030 | 15.5k | image->filename, |
1031 | 15.5k | image->columns,image->rows); |
1032 | 15.5k | if (status == False) |
1033 | 0 | break; |
1034 | 15.5k | } |
1035 | 38.8k | } |
1036 | 371 | break; |
1037 | 197 | } |
1038 | 0 | default: |
1039 | 0 | { |
1040 | 0 | MagickFreeResourceLimitedMemory(pixels); |
1041 | 0 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
1042 | 0 | } |
1043 | 9.14k | } |
1044 | 9.14k | MagickFreeResourceLimitedMemory(pixels); |
1045 | 9.14k | if (EOFBlob(image)) |
1046 | 958 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
1047 | 9.14k | image->filename); |
1048 | 9.14k | if (strcmp(image_info->magick,"ICODIB") == 0) |
1049 | 842 | { |
1050 | | /* |
1051 | | Handle ICO mask. |
1052 | | */ |
1053 | 842 | char |
1054 | 842 | byte; |
1055 | | |
1056 | 842 | image->matte=MagickFalse; |
1057 | 7.07k | for (y=(long) image->rows-1; y >= 0; y--) |
1058 | 7.02k | { |
1059 | 7.02k | if (image->logging) |
1060 | 7.02k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1061 | 7.02k | "y=%ld", y); |
1062 | 7.02k | q=GetImagePixels(image,0,y,image->columns,1); |
1063 | 7.02k | if (q == (PixelPacket *) NULL) |
1064 | 0 | break; |
1065 | 21.2k | for (x=0; x < ((long) image->columns-7); x+=8) |
1066 | 14.5k | { |
1067 | 14.5k | byte=0; |
1068 | 14.5k | if (ReadBlob(image,sizeof(byte),&byte) != sizeof(byte)) |
1069 | 316 | break; |
1070 | 128k | for (bit=0; bit < 8; bit++) |
1071 | 113k | { |
1072 | 113k | q[x+bit].opacity=(Quantum) |
1073 | 113k | (byte & (0x80 >> bit) ? TransparentOpacity : OpaqueOpacity); |
1074 | 113k | if (q[x+bit].opacity != OpaqueOpacity) |
1075 | 70.1k | image->matte=MagickTrue; |
1076 | 113k | } |
1077 | 14.2k | } |
1078 | | /* Detect early loop termination above due to EOF */ |
1079 | 7.02k | if (x < ((long) image->columns-7)) |
1080 | 316 | break; |
1081 | 6.70k | if ((image->columns % 8) != 0) |
1082 | 5.56k | { |
1083 | 5.56k | byte=0; |
1084 | 5.56k | if (ReadBlob(image,sizeof(byte),&byte) != sizeof(byte)) |
1085 | 481 | break; |
1086 | 18.1k | for (bit=0; bit < (long) (image->columns % 8); bit++) |
1087 | 13.1k | { |
1088 | 13.1k | q[x+bit].opacity=(Quantum) |
1089 | 13.1k | (byte & (0x80 >> bit) ? TransparentOpacity : OpaqueOpacity); |
1090 | 13.1k | if (q[x+bit].opacity != OpaqueOpacity) |
1091 | 4.20k | image->matte=MagickTrue; |
1092 | 13.1k | } |
1093 | 5.08k | } |
1094 | 6.22k | if (image->columns % 32) |
1095 | 20.4k | for (x=0; x < (long) ((32-(image->columns % 32))/8); x++) |
1096 | 14.7k | { |
1097 | 14.7k | byte=0; |
1098 | 14.7k | if (ReadBlob(image,sizeof(byte),&byte) != sizeof(byte)) |
1099 | 143 | break; |
1100 | 14.7k | } |
1101 | 6.22k | if (!SyncImagePixels(image)) |
1102 | 0 | break; |
1103 | 6.22k | if (image->previous == (Image *) NULL) |
1104 | 6.22k | if (QuantumTick(y,image->rows)) |
1105 | 4.25k | if (!MagickMonitorFormatted((size_t) image->rows-y-1,image->rows,&image->exception, |
1106 | 4.25k | LoadImageText,image->filename, |
1107 | 4.25k | image->columns,image->rows)) |
1108 | 0 | break; |
1109 | 6.22k | } |
1110 | | /* |
1111 | | If a PseudoClass image has a non-opaque opacity channel, then |
1112 | | we must mark it as DirectClass since there is no standard way |
1113 | | to store PseudoClass with an opacity channel. |
1114 | | */ |
1115 | 842 | if ((image->storage_class == PseudoClass) && (image->matte == MagickTrue)) |
1116 | 65 | image->storage_class=DirectClass; |
1117 | | #if 0 |
1118 | | /* |
1119 | | FIXME: SourceForge bug 557 provides an icon for which magick |
1120 | | is set to "ICODIB" by the 'icon' coder but there is no data |
1121 | | for the ICO mask. Intentionally ignore EOF at this point |
1122 | | until this issue gets figured out. |
1123 | | */ |
1124 | | if (EOFBlob(image)) |
1125 | | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
1126 | | image->filename); |
1127 | | #endif |
1128 | 842 | } |
1129 | 9.14k | if (dib_info.height < 0) |
1130 | 8.12k | { |
1131 | 8.12k | Image |
1132 | 8.12k | *flipped_image; |
1133 | | /* |
1134 | | Correct image orientation. |
1135 | | */ |
1136 | 8.12k | flipped_image=FlipImage(image,exception); |
1137 | 8.12k | if (flipped_image == (Image *) NULL) |
1138 | 0 | { |
1139 | 0 | DestroyImageList(image); |
1140 | 0 | return((Image *) NULL); |
1141 | 0 | } |
1142 | 8.12k | DestroyBlob(flipped_image); |
1143 | 8.12k | flipped_image->blob=ReferenceBlob(image->blob); |
1144 | 8.12k | DestroyImage(image); |
1145 | 8.12k | image=flipped_image; |
1146 | 8.12k | } |
1147 | 9.14k | CloseBlob(image); |
1148 | 9.14k | StopTimer(&timer); |
1149 | 9.14k | image->timer=timer; |
1150 | 9.14k | return(image); |
1151 | 9.14k | } |
1152 | | |
1153 | | /* |
1154 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1155 | | % % |
1156 | | % % |
1157 | | % % |
1158 | | % R e g i s t e r D I B I m a g e % |
1159 | | % % |
1160 | | % % |
1161 | | % % |
1162 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1163 | | % |
1164 | | % Method RegisterDIBImage adds attributes for the DIB image format to |
1165 | | % the list of supported formats. The attributes include the image format |
1166 | | % tag, a method to read and/or write the format, whether the format |
1167 | | % supports the saving of more than one frame to the same file or blob, |
1168 | | % whether the format supports native in-memory I/O, and a brief |
1169 | | % description of the format. |
1170 | | % |
1171 | | % The format of the RegisterDIBImage method is: |
1172 | | % |
1173 | | % RegisterDIBImage(void) |
1174 | | % |
1175 | | */ |
1176 | | ModuleExport void RegisterDIBImage(void) |
1177 | 8 | { |
1178 | 8 | MagickInfo |
1179 | 8 | *entry; |
1180 | | |
1181 | 8 | entry=SetMagickInfo("DIB"); |
1182 | 8 | entry->decoder=(DecoderHandler) ReadDIBImage; |
1183 | 8 | entry->encoder=(EncoderHandler) WriteDIBImage; |
1184 | 8 | entry->magick=(MagickHandler) IsDIB; |
1185 | 8 | entry->adjoin=False; |
1186 | | #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
1187 | | entry->stealth=True; /* Don't list in '-list format' output */ |
1188 | | #endif /* if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) */ |
1189 | 8 | entry->description="Microsoft Windows 3.X Packed Device-Independent Bitmap"; |
1190 | 8 | entry->module="DIB"; |
1191 | 8 | (void) RegisterMagickInfo(entry); |
1192 | | |
1193 | 8 | entry=SetMagickInfo("ICODIB"); |
1194 | 8 | entry->decoder=(DecoderHandler) ReadDIBImage; |
1195 | | /* entry->encoder=(EncoderHandler) WriteDIBImage; */ |
1196 | 8 | entry->magick=(MagickHandler) IsDIB; |
1197 | 8 | entry->adjoin=False; |
1198 | 8 | entry->stealth=True; /* Don't list in '-list format' output */ |
1199 | 8 | entry->raw=True; /* Requires size to work correctly. */ |
1200 | 8 | entry->description="Microsoft Windows 3.X Packed Device-Independent Bitmap + Mask"; |
1201 | 8 | entry->module="DIB"; |
1202 | 8 | (void) RegisterMagickInfo(entry); |
1203 | | |
1204 | 8 | } |
1205 | | |
1206 | | /* |
1207 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1208 | | % % |
1209 | | % % |
1210 | | % % |
1211 | | % U n r e g i s t e r D I B I m a g e % |
1212 | | % % |
1213 | | % % |
1214 | | % % |
1215 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1216 | | % |
1217 | | % Method UnregisterDIBImage removes format registrations made by the |
1218 | | % DIB module from the list of supported formats. |
1219 | | % |
1220 | | % The format of the UnregisterDIBImage method is: |
1221 | | % |
1222 | | % UnregisterDIBImage(void) |
1223 | | % |
1224 | | */ |
1225 | | ModuleExport void UnregisterDIBImage(void) |
1226 | 0 | { |
1227 | 0 | (void) UnregisterMagickInfo("ICODIB"); |
1228 | 0 | (void) UnregisterMagickInfo("DIB"); |
1229 | 0 | } |
1230 | | |
1231 | | /* |
1232 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1233 | | % % |
1234 | | % % |
1235 | | % % |
1236 | | % W r i t e D I B I m a g e % |
1237 | | % % |
1238 | | % % |
1239 | | % % |
1240 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1241 | | % |
1242 | | % Method WriteDIBImage writes an image in Microsoft Windows bitmap encoded |
1243 | | % image format. |
1244 | | % |
1245 | | % The format of the WriteDIBImage method is: |
1246 | | % |
1247 | | % unsigned int WriteDIBImage(const ImageInfo *image_info,Image *image) |
1248 | | % |
1249 | | % A description of each parameter follows. |
1250 | | % |
1251 | | % o status: Method WriteDIBImage return True if the image is written. |
1252 | | % False is returned is there is a memory shortage or if the image file |
1253 | | % fails to write. |
1254 | | % |
1255 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
1256 | | % |
1257 | | % o image: A pointer to an Image structure. |
1258 | | % |
1259 | | % |
1260 | | */ |
1261 | | static unsigned int WriteDIBImage(const ImageInfo *image_info,Image *image) |
1262 | 411 | { |
1263 | 411 | DIBInfo |
1264 | 411 | dib_info; |
1265 | | |
1266 | 411 | unsigned long |
1267 | 411 | y; |
1268 | | |
1269 | 411 | register const PixelPacket |
1270 | 411 | *p; |
1271 | | |
1272 | 411 | register const IndexPacket |
1273 | 411 | *indexes; |
1274 | | |
1275 | 411 | register unsigned long |
1276 | 411 | i, |
1277 | 411 | x; |
1278 | | |
1279 | 411 | register unsigned char |
1280 | 411 | *q; |
1281 | | |
1282 | 411 | unsigned char |
1283 | 411 | *dib_data, |
1284 | 411 | *pixels; |
1285 | | |
1286 | 411 | unsigned int |
1287 | 411 | status; |
1288 | | |
1289 | 411 | size_t |
1290 | 411 | bytes_per_line, |
1291 | 411 | image_size; |
1292 | | |
1293 | 411 | ImageCharacteristics |
1294 | 411 | characteristics; |
1295 | | |
1296 | | /* |
1297 | | Open output image file. |
1298 | | */ |
1299 | 411 | assert(image_info != (const ImageInfo *) NULL); |
1300 | 411 | assert(image_info->signature == MagickSignature); |
1301 | 411 | assert(image != (Image *) NULL); |
1302 | 411 | assert(image->signature == MagickSignature); |
1303 | 411 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
1304 | 411 | if (status == False) |
1305 | 411 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
1306 | | /* |
1307 | | Ensure that image is in an RGB space. |
1308 | | */ |
1309 | 411 | (void) TransformColorspace(image,RGBColorspace); |
1310 | | /* |
1311 | | Analyze image to be written. |
1312 | | */ |
1313 | 411 | if (!GetImageCharacteristics(image,&characteristics, |
1314 | 411 | (OptimizeType == image_info->type), |
1315 | 411 | &image->exception)) |
1316 | 0 | { |
1317 | 0 | CloseBlob(image); |
1318 | 0 | return MagickFail; |
1319 | 0 | } |
1320 | | /* |
1321 | | Initialize DIB raster file header. |
1322 | | */ |
1323 | 411 | if (image->storage_class == DirectClass) |
1324 | 86 | { |
1325 | | /* |
1326 | | Full color DIB raster. |
1327 | | */ |
1328 | 86 | dib_info.number_colors=0; |
1329 | 86 | dib_info.bits_per_pixel=image->matte ? 32 : 24; |
1330 | 86 | } |
1331 | 325 | else |
1332 | 325 | { |
1333 | | /* |
1334 | | Colormapped DIB raster. |
1335 | | */ |
1336 | 325 | dib_info.bits_per_pixel=8; |
1337 | 325 | if (characteristics.monochrome) |
1338 | 65 | dib_info.bits_per_pixel=1; |
1339 | 325 | dib_info.number_colors=1 << dib_info.bits_per_pixel; |
1340 | 325 | } |
1341 | | /* |
1342 | | Below emulates: |
1343 | | bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32); |
1344 | | */ |
1345 | 411 | bytes_per_line=MagickArraySize(image->columns,dib_info.bits_per_pixel); |
1346 | 411 | if ((bytes_per_line > 0) && (~((size_t) 0) - bytes_per_line) > 31) |
1347 | 411 | bytes_per_line = MagickArraySize(4,(bytes_per_line+31)/32); |
1348 | 411 | if (bytes_per_line == 0) |
1349 | 411 | ThrowWriterException(CoderError,ArithmeticOverflow,image); |
1350 | 411 | image_size=MagickArraySize(bytes_per_line,image->rows); |
1351 | 411 | if ((image_size == 0) || ((image_size & 0xffffffff) != image_size)) |
1352 | 411 | ThrowWriterException(CoderError,ArithmeticOverflow,image); |
1353 | 411 | dib_info.header_size=40; |
1354 | 411 | dib_info.width=(long) image->columns; |
1355 | 411 | dib_info.height=(long) image->rows; |
1356 | 411 | dib_info.planes=1; |
1357 | 411 | dib_info.compression=0; |
1358 | 411 | dib_info.image_size=(magick_uint32_t) image_size; |
1359 | 411 | dib_info.x_pixels=75*39; |
1360 | 411 | dib_info.y_pixels=75*39; |
1361 | 411 | if (image->units == PixelsPerInchResolution) |
1362 | 0 | { |
1363 | 0 | dib_info.x_pixels=(unsigned long) (100.0*image->x_resolution/2.54); |
1364 | 0 | dib_info.y_pixels=(unsigned long) (100.0*image->y_resolution/2.54); |
1365 | 0 | } |
1366 | 411 | if (image->units == PixelsPerCentimeterResolution) |
1367 | 411 | { |
1368 | 411 | dib_info.x_pixels=(unsigned long) (100.0*image->x_resolution); |
1369 | 411 | dib_info.y_pixels=(unsigned long) (100.0*image->y_resolution); |
1370 | 411 | } |
1371 | 411 | dib_info.colors_important=dib_info.number_colors; |
1372 | | /* |
1373 | | Convert MIFF to DIB raster pixels. |
1374 | | */ |
1375 | 411 | pixels=MagickAllocateResourceLimitedMemory(unsigned char *,dib_info.image_size); |
1376 | 411 | if (pixels == (unsigned char *) NULL) |
1377 | 411 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
1378 | 411 | switch (dib_info.bits_per_pixel) |
1379 | 411 | { |
1380 | 65 | case 1: |
1381 | 65 | { |
1382 | 65 | register unsigned char |
1383 | 65 | bit, |
1384 | 65 | byte; |
1385 | | |
1386 | | /* |
1387 | | Convert PseudoClass image to a DIB monochrome image. |
1388 | | */ |
1389 | 16.9k | for (y=0; y < image->rows; y++) |
1390 | 16.9k | { |
1391 | 16.9k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1392 | 16.9k | if (p == (const PixelPacket *) NULL) |
1393 | 0 | break; |
1394 | 16.9k | indexes=AccessImmutableIndexes(image); |
1395 | 16.9k | q=pixels+(image->rows-y-1)*bytes_per_line; |
1396 | 16.9k | bit=0; |
1397 | 16.9k | byte=0; |
1398 | 8.35M | for (x=0; x < image->columns; x++) |
1399 | 8.33M | { |
1400 | 8.33M | byte<<=1; |
1401 | 8.33M | byte|=indexes[x] ? 0x01 : 0x00; |
1402 | 8.33M | bit++; |
1403 | 8.33M | if (bit == 8) |
1404 | 1.03M | { |
1405 | 1.03M | *q++=byte; |
1406 | 1.03M | bit=0; |
1407 | 1.03M | byte=0; |
1408 | 1.03M | } |
1409 | 8.33M | p++; |
1410 | 8.33M | } |
1411 | 16.9k | if (bit != 0) |
1412 | 15.7k | *q++=byte << (8-bit); |
1413 | | /* initialize padding bytes */ |
1414 | 55.3k | for (x=(image->columns+7)/8; x < bytes_per_line; x++) |
1415 | 38.3k | *q++=0x00; |
1416 | 16.9k | if (image->previous == (Image *) NULL) |
1417 | 16.9k | if (QuantumTick(y,image->rows)) |
1418 | 4.18k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1419 | 4.18k | SaveImageText,image->filename, |
1420 | 4.18k | image->columns,image->rows)) |
1421 | 0 | break; |
1422 | 16.9k | } |
1423 | 65 | break; |
1424 | 0 | } |
1425 | 260 | case 8: |
1426 | 260 | { |
1427 | | /* |
1428 | | Convert PseudoClass packet to DIB pixel. |
1429 | | */ |
1430 | 75.9k | for (y=0; y < image->rows; y++) |
1431 | 75.7k | { |
1432 | 75.7k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1433 | 75.7k | if (p == (const PixelPacket *) NULL) |
1434 | 0 | break; |
1435 | 75.7k | indexes=AccessImmutableIndexes(image); |
1436 | 75.7k | q=pixels+(image->rows-y-1)*bytes_per_line; |
1437 | 103M | for (x=0; x < image->columns; x++) |
1438 | 103M | { |
1439 | 103M | *q++=indexes[x]; |
1440 | 103M | p++; |
1441 | 103M | } |
1442 | | /* initialize padding bytes */ |
1443 | 157k | for (; x < bytes_per_line; x++) |
1444 | 82.2k | *q++=0x00; |
1445 | 75.7k | if (image->previous == (Image *) NULL) |
1446 | 75.7k | if (QuantumTick(y,image->rows)) |
1447 | 19.8k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1448 | 19.8k | SaveImageText,image->filename, |
1449 | 19.8k | image->columns,image->rows)) |
1450 | 0 | break; |
1451 | 75.7k | } |
1452 | 260 | break; |
1453 | 0 | } |
1454 | 66 | case 24: |
1455 | 86 | case 32: |
1456 | 86 | { |
1457 | | /* |
1458 | | Convert DirectClass packet to DIB RGB pixel. |
1459 | | */ |
1460 | 22.5k | for (y=0; y < image->rows; y++) |
1461 | 22.4k | { |
1462 | 22.4k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1463 | 22.4k | if (p == (const PixelPacket *) NULL) |
1464 | 0 | break; |
1465 | 22.4k | q=pixels+(image->rows-y-1)*bytes_per_line; |
1466 | 3.50M | for (x=0; x < image->columns; x++) |
1467 | 3.48M | { |
1468 | 3.48M | *q++=ScaleQuantumToChar(p->blue); |
1469 | 3.48M | *q++=ScaleQuantumToChar(p->green); |
1470 | 3.48M | *q++=ScaleQuantumToChar(p->red); |
1471 | 3.48M | if (image->matte) |
1472 | 2.63M | *q++=ScaleQuantumToChar(p->opacity); |
1473 | 3.48M | p++; |
1474 | 3.48M | } |
1475 | | /* initialize padding bytes */ |
1476 | 22.4k | if (dib_info.bits_per_pixel == 24) |
1477 | 19.7k | { |
1478 | | /* initialize padding bytes */ |
1479 | 40.3k | for (x=3*image->columns; x < bytes_per_line; x++) |
1480 | 20.5k | *q++=0x00; |
1481 | 19.7k | } |
1482 | 22.4k | if (image->previous == (Image *) NULL) |
1483 | 22.4k | if (QuantumTick(y,image->rows)) |
1484 | 4.67k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1485 | 4.67k | SaveImageText,image->filename, |
1486 | 4.67k | image->columns,image->rows)) |
1487 | 0 | break; |
1488 | 22.4k | } |
1489 | 86 | break; |
1490 | 66 | } |
1491 | 411 | } |
1492 | 411 | if (dib_info.bits_per_pixel == 8) |
1493 | 260 | if (image_info->compression != NoCompression) |
1494 | 260 | { |
1495 | 260 | size_t |
1496 | 260 | length; |
1497 | | |
1498 | | /* |
1499 | | Convert run-length encoded raster pixels. |
1500 | | */ |
1501 | 260 | length=2*((size_t) bytes_per_line+2)*((size_t) image->rows+2)+2; |
1502 | 260 | dib_data=MagickAllocateResourceLimitedMemory(unsigned char *,length); |
1503 | 260 | if (dib_data == (unsigned char *) NULL) |
1504 | 0 | { |
1505 | 0 | MagickFreeResourceLimitedMemory(pixels); |
1506 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
1507 | 0 | image); |
1508 | 0 | } |
1509 | 260 | dib_info.image_size=(unsigned long) |
1510 | 260 | EncodeImage(image,bytes_per_line,pixels,dib_data); |
1511 | 260 | MagickFreeResourceLimitedMemory(pixels); |
1512 | 260 | pixels=dib_data; |
1513 | 260 | dib_info.compression=1; |
1514 | 260 | } |
1515 | | /* |
1516 | | Write DIB header. |
1517 | | */ |
1518 | 411 | (void) WriteBlobLSBLong(image,dib_info.header_size); |
1519 | 411 | (void) WriteBlobLSBLong(image,dib_info.width); |
1520 | 411 | (void) WriteBlobLSBLong(image,dib_info.height); |
1521 | 411 | (void) WriteBlobLSBShort(image,dib_info.planes); |
1522 | 411 | (void) WriteBlobLSBShort(image,dib_info.bits_per_pixel); |
1523 | 411 | (void) WriteBlobLSBLong(image,dib_info.compression); |
1524 | 411 | (void) WriteBlobLSBLong(image,dib_info.image_size); |
1525 | 411 | (void) WriteBlobLSBLong(image,dib_info.x_pixels); |
1526 | 411 | (void) WriteBlobLSBLong(image,dib_info.y_pixels); |
1527 | 411 | (void) WriteBlobLSBLong(image,dib_info.number_colors); |
1528 | 411 | (void) WriteBlobLSBLong(image,dib_info.colors_important); |
1529 | 411 | if (image->storage_class == PseudoClass) |
1530 | 325 | { |
1531 | 325 | unsigned char |
1532 | 325 | *dib_colormap; |
1533 | | |
1534 | | /* |
1535 | | Dump colormap to file. |
1536 | | */ |
1537 | 325 | dib_colormap=MagickAllocateResourceLimitedArray(unsigned char *, |
1538 | 325 | (((size_t) 1U) << dib_info.bits_per_pixel),4); |
1539 | 325 | if (dib_colormap == (unsigned char *) NULL) |
1540 | 0 | { |
1541 | 0 | MagickFreeResourceLimitedMemory(pixels); |
1542 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
1543 | 0 | } |
1544 | 325 | q=dib_colormap; |
1545 | 5.78k | for (i=0; i < Min(image->colors,dib_info.number_colors); i++) |
1546 | 5.45k | { |
1547 | 5.45k | *q++=ScaleQuantumToChar(image->colormap[i].blue); |
1548 | 5.45k | *q++=ScaleQuantumToChar(image->colormap[i].green); |
1549 | 5.45k | *q++=ScaleQuantumToChar(image->colormap[i].red); |
1550 | 5.45k | *q++=(Quantum) 0x0; |
1551 | 5.45k | } |
1552 | 61.5k | for ( ; i < (1U << dib_info.bits_per_pixel); i++) |
1553 | 61.2k | { |
1554 | 61.2k | *q++=(Quantum) 0x0; |
1555 | 61.2k | *q++=(Quantum) 0x0; |
1556 | 61.2k | *q++=(Quantum) 0x0; |
1557 | 61.2k | *q++=(Quantum) 0x0; |
1558 | 61.2k | } |
1559 | 325 | (void) WriteBlob(image, 4*(((size_t) 1U) << dib_info.bits_per_pixel), |
1560 | 325 | (char *) dib_colormap); |
1561 | 325 | MagickFreeResourceLimitedMemory(dib_colormap); |
1562 | 325 | } |
1563 | 411 | (void) WriteBlob(image,dib_info.image_size,(char *) pixels); |
1564 | 411 | MagickFreeResourceLimitedMemory(pixels); |
1565 | 411 | status &= CloseBlob(image); |
1566 | 411 | return(status); |
1567 | 411 | } |