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