/src/imagemagick/coders/xbm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % X X BBBB M M % |
7 | | % X X B B MM MM % |
8 | | % X BBBB M M M % |
9 | | % X X B B M M % |
10 | | % X X BBBB M M % |
11 | | % % |
12 | | % % |
13 | | % Read/Write X Windows System Bitmap Format % |
14 | | % % |
15 | | % Software Design % |
16 | | % Cristy % |
17 | | % July 1992 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/script/license.php % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | */ |
38 | | |
39 | | /* |
40 | | Include declarations. |
41 | | */ |
42 | | #include "MagickCore/studio.h" |
43 | | #include "MagickCore/attribute.h" |
44 | | #include "MagickCore/blob.h" |
45 | | #include "MagickCore/blob-private.h" |
46 | | #include "MagickCore/cache.h" |
47 | | #include "MagickCore/color-private.h" |
48 | | #include "MagickCore/colormap.h" |
49 | | #include "MagickCore/colorspace.h" |
50 | | #include "MagickCore/colorspace-private.h" |
51 | | #include "MagickCore/exception.h" |
52 | | #include "MagickCore/exception-private.h" |
53 | | #include "MagickCore/image.h" |
54 | | #include "MagickCore/image-private.h" |
55 | | #include "MagickCore/list.h" |
56 | | #include "MagickCore/magick.h" |
57 | | #include "MagickCore/memory_.h" |
58 | | #include "MagickCore/monitor.h" |
59 | | #include "MagickCore/monitor-private.h" |
60 | | #include "MagickCore/pixel-accessor.h" |
61 | | #include "MagickCore/quantum-private.h" |
62 | | #include "MagickCore/static.h" |
63 | | #include "MagickCore/string_.h" |
64 | | #include "MagickCore/string-private.h" |
65 | | #include "MagickCore/module.h" |
66 | | #include "MagickCore/utility.h" |
67 | | |
68 | | /* |
69 | | Forward declarations. |
70 | | */ |
71 | | static MagickBooleanType |
72 | | WriteXBMImage(const ImageInfo *,Image *,ExceptionInfo *); |
73 | | |
74 | | /* |
75 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
76 | | % % |
77 | | % % |
78 | | % % |
79 | | % I s X B M % |
80 | | % % |
81 | | % % |
82 | | % % |
83 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
84 | | % |
85 | | % IsXBM() returns MagickTrue if the image format type, identified by the |
86 | | % magick string, is XBM. |
87 | | % |
88 | | % The format of the IsXBM method is: |
89 | | % |
90 | | % MagickBooleanType IsXBM(const unsigned char *magick,const size_t length) |
91 | | % |
92 | | % A description of each parameter follows: |
93 | | % |
94 | | % o magick: compare image format pattern against these bytes. |
95 | | % |
96 | | % o length: Specifies the length of the magick string. |
97 | | % |
98 | | */ |
99 | | static MagickBooleanType IsXBM(const unsigned char *magick,const size_t length) |
100 | 0 | { |
101 | 0 | if (length < 7) |
102 | 0 | return(MagickFalse); |
103 | 0 | if (memcmp(magick,"#define",7) == 0) |
104 | 0 | return(MagickTrue); |
105 | 0 | return(MagickFalse); |
106 | 0 | } |
107 | | |
108 | | /* |
109 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
110 | | % % |
111 | | % % |
112 | | % % |
113 | | % R e a d X B M I m a g e % |
114 | | % % |
115 | | % % |
116 | | % % |
117 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
118 | | % |
119 | | % ReadXBMImage() reads an X11 bitmap image file and returns it. It |
120 | | % allocates the memory necessary for the new Image structure and returns a |
121 | | % pointer to the new image. |
122 | | % |
123 | | % The format of the ReadXBMImage method is: |
124 | | % |
125 | | % Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception) |
126 | | % |
127 | | % A description of each parameter follows: |
128 | | % |
129 | | % o image_info: the image info. |
130 | | % |
131 | | % o exception: return any errors or warnings in this structure. |
132 | | % |
133 | | */ |
134 | | |
135 | | static int XBMInteger(Image *image,short int *hex_digits) |
136 | 52.7k | { |
137 | 52.7k | int |
138 | 52.7k | c; |
139 | | |
140 | 52.7k | unsigned int |
141 | 52.7k | value; |
142 | | |
143 | | /* |
144 | | Skip any leading whitespace. |
145 | | */ |
146 | 52.7k | do |
147 | 54.3k | { |
148 | 54.3k | c=ReadBlobByte(image); |
149 | 54.3k | if (c == EOF) |
150 | 257 | return(-1); |
151 | 54.3k | } while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')); |
152 | | /* |
153 | | Evaluate number. |
154 | | */ |
155 | 52.4k | value=0; |
156 | 52.4k | do |
157 | 57.5k | { |
158 | 57.5k | if (value <= (unsigned int) (INT_MAX/16)) |
159 | 57.0k | { |
160 | 57.0k | value*=16; |
161 | 57.0k | c&=0xff; |
162 | 57.0k | if (value <= (unsigned int) ((INT_MAX-1)-hex_digits[c])) |
163 | 56.6k | value+=(unsigned int) hex_digits[c]; |
164 | 57.0k | } |
165 | 57.5k | c=ReadBlobByte(image); |
166 | 57.5k | if (c == EOF) |
167 | 186 | return(-1); |
168 | 57.5k | } while (hex_digits[c & 0xff] >= 0); |
169 | 52.2k | return((int) value); |
170 | 52.4k | } |
171 | | |
172 | | static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception) |
173 | 1.74k | { |
174 | 1.74k | char |
175 | 1.74k | buffer[MagickPathExtent], |
176 | 1.74k | name[MagickPathExtent]; |
177 | | |
178 | 1.74k | Image |
179 | 1.74k | *image; |
180 | | |
181 | 1.74k | int |
182 | 1.74k | c; |
183 | | |
184 | 1.74k | long |
185 | 1.74k | height, |
186 | 1.74k | width; |
187 | | |
188 | 1.74k | MagickBooleanType |
189 | 1.74k | status; |
190 | | |
191 | 1.74k | MagickOffsetType |
192 | 1.74k | offset; |
193 | | |
194 | 1.74k | Quantum |
195 | 1.74k | *q; |
196 | | |
197 | 1.74k | short int |
198 | 1.74k | hex_digits[256]; |
199 | | |
200 | 1.74k | ssize_t |
201 | 1.74k | i, |
202 | 1.74k | x, |
203 | 1.74k | y; |
204 | | |
205 | 1.74k | unsigned char |
206 | 1.74k | *data, |
207 | 1.74k | *p; |
208 | | |
209 | 1.74k | unsigned int |
210 | 1.74k | bit, |
211 | 1.74k | byte, |
212 | 1.74k | bytes_per_line, |
213 | 1.74k | length, |
214 | 1.74k | padding, |
215 | 1.74k | version; |
216 | | |
217 | | /* |
218 | | Open image file. |
219 | | */ |
220 | 1.74k | assert(image_info != (const ImageInfo *) NULL); |
221 | 1.74k | assert(image_info->signature == MagickCoreSignature); |
222 | 1.74k | assert(exception != (ExceptionInfo *) NULL); |
223 | 1.74k | assert(exception->signature == MagickCoreSignature); |
224 | 1.74k | if (IsEventLogging() != MagickFalse) |
225 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
226 | 0 | image_info->filename); |
227 | 1.74k | image=AcquireImage(image_info,exception); |
228 | 1.74k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
229 | 1.74k | if (status == MagickFalse) |
230 | 0 | { |
231 | 0 | image=DestroyImageList(image); |
232 | 0 | return((Image *) NULL); |
233 | 0 | } |
234 | | /* |
235 | | Read X bitmap header. |
236 | | */ |
237 | 1.74k | width=0; |
238 | 1.74k | height=0; |
239 | 1.74k | *name='\0'; |
240 | 4.76k | while (ReadBlobString(image,buffer) != (char *) NULL) |
241 | 4.26k | if (MagickSscanf(buffer,"#define %1024s %ld",name,&width) == 2) |
242 | 2.50k | if ((strlen(name) >= 6) && |
243 | 2.50k | (LocaleCompare(name+strlen(name)-6,"_width") == 0)) |
244 | 1.24k | break; |
245 | 4.32k | while (ReadBlobString(image,buffer) != (char *) NULL) |
246 | 3.63k | if (MagickSscanf(buffer,"#define %1024s %ld",name,&height) == 2) |
247 | 2.25k | if ((strlen(name) >= 7) && |
248 | 2.25k | (LocaleCompare(name+strlen(name)-7,"_height") == 0)) |
249 | 1.05k | break; |
250 | 1.74k | if ((width <= 0) || (height <= 0) || (EOFBlob(image) != MagickFalse)) |
251 | 1.05k | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
252 | 1.05k | image->columns=(size_t) width; |
253 | 1.05k | image->rows=(size_t) height; |
254 | 1.05k | image->depth=8; |
255 | 1.05k | image->storage_class=PseudoClass; |
256 | 1.05k | image->colors=2; |
257 | | /* |
258 | | Scan until hex digits. |
259 | | */ |
260 | 1.05k | version=11; |
261 | 1.05k | offset=TellBlob(image); |
262 | 5.74k | while (ReadBlobString(image,buffer) != (char *) NULL) |
263 | 5.38k | { |
264 | 5.38k | if (MagickSscanf(buffer,"static short %1024s = {",name) == 1) |
265 | 635 | version=10; |
266 | 4.75k | else if (MagickSscanf(buffer,"static unsigned char %1024s = {",name) == 1) |
267 | 377 | version=11; |
268 | 4.37k | else if (MagickSscanf(buffer,"static char %1024s = {",name) == 1) |
269 | 2.58k | version=11; |
270 | 1.78k | else |
271 | 1.78k | { |
272 | 1.78k | offset=TellBlob(image); |
273 | 1.78k | continue; |
274 | 1.78k | } |
275 | 3.59k | p=(unsigned char *) strrchr(name,'_'); |
276 | 3.59k | if (p == (unsigned char *) NULL) |
277 | 3.32k | p=(unsigned char *) name; |
278 | 271 | else |
279 | 271 | p++; |
280 | 3.59k | if (LocaleCompare("bits[]",(char *) p) == 0) |
281 | 690 | break; |
282 | 3.59k | } |
283 | | /* |
284 | | Initialize image structure. |
285 | | */ |
286 | 1.05k | if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) |
287 | 1.05k | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
288 | | /* |
289 | | Initialize colormap. |
290 | | */ |
291 | 1.05k | image->colormap[0].red=(MagickRealType) QuantumRange; |
292 | 1.05k | image->colormap[0].green=(MagickRealType) QuantumRange; |
293 | 1.05k | image->colormap[0].blue=(MagickRealType) QuantumRange; |
294 | 1.05k | image->colormap[1].red=0.0; |
295 | 1.05k | image->colormap[1].green=0.0; |
296 | 1.05k | image->colormap[1].blue=0.0; |
297 | 1.05k | if (image_info->ping != MagickFalse) |
298 | 23 | { |
299 | 23 | (void) CloseBlob(image); |
300 | 23 | return(GetFirstImageInList(image)); |
301 | 23 | } |
302 | 1.02k | status=SetImageExtent(image,image->columns,image->rows,exception); |
303 | 1.02k | if (status == MagickFalse) |
304 | 207 | return(DestroyImageList(image)); |
305 | 822 | p=(unsigned char *) strrchr(buffer,'{'); |
306 | 822 | if (p != (unsigned char *) NULL) |
307 | 21 | (void) SeekBlob(image,offset+((char *) p-buffer)+1,SEEK_SET); |
308 | | /* |
309 | | Initialize hex values. |
310 | | */ |
311 | 211k | for (i=0; i < (ssize_t) (sizeof(hex_digits)/sizeof(*hex_digits)); i++) |
312 | 210k | hex_digits[i]=(-1); |
313 | 822 | hex_digits[(int) '0']=0; |
314 | 822 | hex_digits[(int) '1']=1; |
315 | 822 | hex_digits[(int) '2']=2; |
316 | 822 | hex_digits[(int) '3']=3; |
317 | 822 | hex_digits[(int) '4']=4; |
318 | 822 | hex_digits[(int) '5']=5; |
319 | 822 | hex_digits[(int) '6']=6; |
320 | 822 | hex_digits[(int) '7']=7; |
321 | 822 | hex_digits[(int) '8']=8; |
322 | 822 | hex_digits[(int) '9']=9; |
323 | 822 | hex_digits[(int) 'A']=10; |
324 | 822 | hex_digits[(int) 'B']=11; |
325 | 822 | hex_digits[(int) 'C']=12; |
326 | 822 | hex_digits[(int) 'D']=13; |
327 | 822 | hex_digits[(int) 'E']=14; |
328 | 822 | hex_digits[(int) 'F']=15; |
329 | 822 | hex_digits[(int) 'a']=10; |
330 | 822 | hex_digits[(int) 'b']=11; |
331 | 822 | hex_digits[(int) 'c']=12; |
332 | 822 | hex_digits[(int) 'd']=13; |
333 | 822 | hex_digits[(int) 'e']=14; |
334 | 822 | hex_digits[(int) 'f']=15; |
335 | 822 | hex_digits[(int) 'x']=0; |
336 | 822 | hex_digits[(int) ' ']=(-1); |
337 | 822 | hex_digits[(int) ',']=(-1); |
338 | 822 | hex_digits[(int) '}']=(-1); |
339 | 822 | hex_digits[(int) '\n']=(-1); |
340 | 822 | hex_digits[(int) '\t']=(-1); |
341 | | /* |
342 | | Read hex image data. |
343 | | */ |
344 | 822 | padding=0; |
345 | 822 | if (((image->columns % 16) != 0) && ((image->columns % 16) < 9) && |
346 | 822 | (version == 10)) |
347 | 253 | padding=1; |
348 | 822 | bytes_per_line=(unsigned int) (image->columns+7)/8+padding; |
349 | 822 | length=(unsigned int) image->rows; |
350 | 822 | data=(unsigned char *) AcquireQuantumMemory(length,bytes_per_line* |
351 | 822 | sizeof(*data)); |
352 | 822 | if (data == (unsigned char *) NULL) |
353 | 822 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
354 | 822 | p=data; |
355 | 822 | if (version == 10) |
356 | 50.6k | for (i=0; i < (ssize_t) (bytes_per_line*image->rows); (i+=2)) |
357 | 50.4k | { |
358 | 50.4k | c=XBMInteger(image,hex_digits); |
359 | 50.4k | if (c < 0) |
360 | 176 | { |
361 | 176 | data=(unsigned char *) RelinquishMagickMemory(data); |
362 | 176 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
363 | 0 | } |
364 | 50.2k | *p++=(unsigned char) c; |
365 | 50.2k | if ((padding == 0) || (((i+2) % bytes_per_line) != 0)) |
366 | 44.8k | *p++=(unsigned char) (c >> 8); |
367 | 50.2k | } |
368 | 379 | else |
369 | 2.41k | for (i=0; i < (ssize_t) (bytes_per_line*image->rows); i++) |
370 | 2.31k | { |
371 | 2.31k | c=XBMInteger(image,hex_digits); |
372 | 2.31k | if (c < 0) |
373 | 276 | { |
374 | 276 | data=(unsigned char *) RelinquishMagickMemory(data); |
375 | 276 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
376 | 0 | } |
377 | 2.03k | *p++=(unsigned char) c; |
378 | 2.03k | } |
379 | 370 | if (EOFBlob(image) != MagickFalse) |
380 | 0 | { |
381 | 0 | data=(unsigned char *) RelinquishMagickMemory(data); |
382 | 0 | ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); |
383 | 0 | } |
384 | | /* |
385 | | Convert X bitmap image to pixel packets. |
386 | | */ |
387 | 370 | p=data; |
388 | 13.3k | for (y=0; y < (ssize_t) image->rows; y++) |
389 | 12.9k | { |
390 | 12.9k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
391 | 12.9k | if (q == (Quantum *) NULL) |
392 | 0 | break; |
393 | 12.9k | bit=0; |
394 | 12.9k | byte=0; |
395 | 726k | for (x=0; x < (ssize_t) image->columns; x++) |
396 | 713k | { |
397 | 713k | if (bit == 0) |
398 | 95.5k | byte=(unsigned int) (*p++); |
399 | 713k | SetPixelIndex(image,(Quantum) ((byte & 0x01) != 0 ? 0x01 : 0x00),q); |
400 | 713k | bit++; |
401 | 713k | byte>>=1; |
402 | 713k | if (bit == 8) |
403 | 85.1k | bit=0; |
404 | 713k | q+=(ptrdiff_t) GetPixelChannels(image); |
405 | 713k | } |
406 | 12.9k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
407 | 0 | break; |
408 | 12.9k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
409 | 12.9k | image->rows); |
410 | 12.9k | if (status == MagickFalse) |
411 | 0 | break; |
412 | 12.9k | } |
413 | 370 | data=(unsigned char *) RelinquishMagickMemory(data); |
414 | 370 | (void) SyncImage(image,exception); |
415 | 370 | if (CloseBlob(image) == MagickFalse) |
416 | 0 | status=MagickFalse; |
417 | 370 | if (status == MagickFalse) |
418 | 0 | return(DestroyImageList(image)); |
419 | 370 | return(GetFirstImageInList(image)); |
420 | 370 | } |
421 | | |
422 | | /* |
423 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
424 | | % % |
425 | | % % |
426 | | % % |
427 | | % R e g i s t e r X B M I m a g e % |
428 | | % % |
429 | | % % |
430 | | % % |
431 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
432 | | % |
433 | | % RegisterXBMImage() adds attributes for the XBM image format to |
434 | | % the list of supported formats. The attributes include the image format |
435 | | % tag, a method to read and/or write the format, whether the format |
436 | | % supports the saving of more than one frame to the same file or blob, |
437 | | % whether the format supports native in-memory I/O, and a brief |
438 | | % description of the format. |
439 | | % |
440 | | % The format of the RegisterXBMImage method is: |
441 | | % |
442 | | % size_t RegisterXBMImage(void) |
443 | | % |
444 | | */ |
445 | | ModuleExport size_t RegisterXBMImage(void) |
446 | 10 | { |
447 | 10 | MagickInfo |
448 | 10 | *entry; |
449 | | |
450 | 10 | entry=AcquireMagickInfo("XBM","XBM", |
451 | 10 | "X Windows system bitmap (black and white)"); |
452 | 10 | entry->decoder=(DecodeImageHandler *) ReadXBMImage; |
453 | 10 | entry->encoder=(EncodeImageHandler *) WriteXBMImage; |
454 | 10 | entry->magick=(IsImageFormatHandler *) IsXBM; |
455 | 10 | entry->flags|=CoderDecoderSeekableStreamFlag; |
456 | 10 | entry->flags^=CoderAdjoinFlag; |
457 | 10 | (void) RegisterMagickInfo(entry); |
458 | 10 | return(MagickImageCoderSignature); |
459 | 10 | } |
460 | | |
461 | | /* |
462 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
463 | | % % |
464 | | % % |
465 | | % % |
466 | | % U n r e g i s t e r X B M I m a g e % |
467 | | % % |
468 | | % % |
469 | | % % |
470 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
471 | | % |
472 | | % UnregisterXBMImage() removes format registrations made by the |
473 | | % XBM module from the list of supported formats. |
474 | | % |
475 | | % The format of the UnregisterXBMImage method is: |
476 | | % |
477 | | % UnregisterXBMImage(void) |
478 | | % |
479 | | */ |
480 | | ModuleExport void UnregisterXBMImage(void) |
481 | 0 | { |
482 | 0 | (void) UnregisterMagickInfo("XBM"); |
483 | 0 | } |
484 | | |
485 | | /* |
486 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
487 | | % % |
488 | | % % |
489 | | % % |
490 | | % W r i t e X B M I m a g e % |
491 | | % % |
492 | | % % |
493 | | % % |
494 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
495 | | % |
496 | | % WriteXBMImage() writes an image to a file in the X bitmap format. |
497 | | % |
498 | | % The format of the WriteXBMImage method is: |
499 | | % |
500 | | % MagickBooleanType WriteXBMImage(const ImageInfo *image_info, |
501 | | % Image *image,ExceptionInfo *exception) |
502 | | % |
503 | | % A description of each parameter follows. |
504 | | % |
505 | | % o image_info: the image info. |
506 | | % |
507 | | % o image: The image. |
508 | | % |
509 | | % o exception: return any errors or warnings in this structure. |
510 | | % |
511 | | */ |
512 | | static MagickBooleanType WriteXBMImage(const ImageInfo *image_info,Image *image, |
513 | | ExceptionInfo *exception) |
514 | 370 | { |
515 | 370 | char |
516 | 370 | basename[MagickPathExtent], |
517 | 370 | buffer[MagickPathExtent]; |
518 | | |
519 | 370 | MagickBooleanType |
520 | 370 | status; |
521 | | |
522 | 370 | const Quantum |
523 | 370 | *p; |
524 | | |
525 | 370 | ssize_t |
526 | 370 | x; |
527 | | |
528 | 370 | size_t |
529 | 370 | bit, |
530 | 370 | byte; |
531 | | |
532 | 370 | ssize_t |
533 | 370 | count, |
534 | 370 | y; |
535 | | |
536 | | /* |
537 | | Open output image file. |
538 | | */ |
539 | 370 | assert(image_info != (const ImageInfo *) NULL); |
540 | 370 | assert(image_info->signature == MagickCoreSignature); |
541 | 370 | assert(image != (Image *) NULL); |
542 | 370 | assert(image->signature == MagickCoreSignature); |
543 | 370 | assert(exception != (ExceptionInfo *) NULL); |
544 | 370 | assert(exception->signature == MagickCoreSignature); |
545 | 370 | if (image->debug != MagickFalse) |
546 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
547 | 370 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
548 | 370 | if (status == MagickFalse) |
549 | 0 | return(status); |
550 | 370 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
551 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
552 | | /* |
553 | | Write X bitmap header. |
554 | | */ |
555 | 370 | GetPathComponent(image->filename,BasePath,basename); |
556 | 370 | (void) FormatLocaleString(buffer,MagickPathExtent,"#define %s_width %.20g\n", |
557 | 370 | basename,(double) image->columns); |
558 | 370 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
559 | 370 | (void) FormatLocaleString(buffer,MagickPathExtent,"#define %s_height %.20g\n", |
560 | 370 | basename,(double) image->rows); |
561 | 370 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
562 | 370 | (void) FormatLocaleString(buffer,MagickPathExtent, |
563 | 370 | "static char %s_bits[] = {\n",basename); |
564 | 370 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
565 | 370 | (void) CopyMagickString(buffer," ",MagickPathExtent); |
566 | 370 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
567 | | /* |
568 | | Convert MIFF to X bitmap pixels. |
569 | | */ |
570 | 370 | (void) SetImageType(image,BilevelType,exception); |
571 | 370 | bit=0; |
572 | 370 | byte=0; |
573 | 370 | count=0; |
574 | 370 | x=0; |
575 | 370 | y=0; |
576 | 370 | (void) CopyMagickString(buffer," ",MagickPathExtent); |
577 | 370 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
578 | 13.3k | for (y=0; y < (ssize_t) image->rows; y++) |
579 | 12.9k | { |
580 | 12.9k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
581 | 12.9k | if (p == (const Quantum *) NULL) |
582 | 0 | break; |
583 | 726k | for (x=0; x < (ssize_t) image->columns; x++) |
584 | 713k | { |
585 | 713k | byte>>=1; |
586 | 713k | if (GetPixelLuma(image,p) < ((double) QuantumRange/2)) |
587 | 122k | byte|=0x80; |
588 | 713k | bit++; |
589 | 713k | if (bit == 8) |
590 | 85.1k | { |
591 | | /* |
592 | | Write a bitmap byte to the image file. |
593 | | */ |
594 | 85.1k | (void) FormatLocaleString(buffer,MagickPathExtent,"0x%02X, ", |
595 | 85.1k | (unsigned int) (byte & 0xff)); |
596 | 85.1k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
597 | 85.1k | count++; |
598 | 85.1k | if (count == 12) |
599 | 6.29k | { |
600 | 6.29k | (void) CopyMagickString(buffer,"\n ",MagickPathExtent); |
601 | 6.29k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
602 | 6.29k | count=0; |
603 | 6.29k | }; |
604 | 85.1k | bit=0; |
605 | 85.1k | byte=0; |
606 | 85.1k | } |
607 | 713k | p+=(ptrdiff_t) GetPixelChannels(image); |
608 | 713k | } |
609 | 12.9k | if (bit != 0) |
610 | 10.4k | { |
611 | | /* |
612 | | Write a bitmap byte to the image file. |
613 | | */ |
614 | 10.4k | byte>>=(8-bit); |
615 | 10.4k | (void) FormatLocaleString(buffer,MagickPathExtent,"0x%02X, ", |
616 | 10.4k | (unsigned int) (byte & 0xff)); |
617 | 10.4k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
618 | 10.4k | count++; |
619 | 10.4k | if (count == 12) |
620 | 1.54k | { |
621 | 1.54k | (void) CopyMagickString(buffer,"\n ",MagickPathExtent); |
622 | 1.54k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
623 | 1.54k | count=0; |
624 | 1.54k | }; |
625 | 10.4k | bit=0; |
626 | 10.4k | byte=0; |
627 | 10.4k | }; |
628 | 12.9k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
629 | 12.9k | image->rows); |
630 | 12.9k | if (status == MagickFalse) |
631 | 0 | break; |
632 | 12.9k | } |
633 | 370 | (void) CopyMagickString(buffer,"};\n",MagickPathExtent); |
634 | 370 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
635 | 370 | if (CloseBlob(image) == MagickFalse) |
636 | 0 | status=MagickFalse; |
637 | 370 | return(status); |
638 | 370 | } |