/src/imagemagick/coders/xbm.c
Line | Count | Source |
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/license/ % |
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 | 54.7k | { |
137 | 54.7k | int |
138 | 54.7k | c; |
139 | | |
140 | 54.7k | unsigned int |
141 | 54.7k | value; |
142 | | |
143 | | /* |
144 | | Skip any leading whitespace. |
145 | | */ |
146 | 54.7k | do |
147 | 56.4k | { |
148 | 56.4k | c=ReadBlobByte(image); |
149 | 56.4k | if (c == EOF) |
150 | 243 | return(-1); |
151 | 56.4k | } while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')); |
152 | | /* |
153 | | Evaluate number. |
154 | | */ |
155 | 54.5k | value=0; |
156 | 54.5k | do |
157 | 59.6k | { |
158 | 59.6k | if (value <= (unsigned int) (INT_MAX/16)) |
159 | 59.1k | { |
160 | 59.1k | value*=16; |
161 | 59.1k | c&=0xff; |
162 | 59.1k | if (value <= (unsigned int) ((INT_MAX-1)-hex_digits[c])) |
163 | 58.7k | value+=(unsigned int) hex_digits[c]; |
164 | 59.1k | } |
165 | 59.6k | c=ReadBlobByte(image); |
166 | 59.6k | if (c == EOF) |
167 | 182 | return(-1); |
168 | 59.6k | } while (hex_digits[c & 0xff] >= 0); |
169 | 54.3k | return((int) value); |
170 | 54.5k | } |
171 | | |
172 | | static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception) |
173 | 1.65k | { |
174 | 1.65k | char |
175 | 1.65k | buffer[MagickPathExtent], |
176 | 1.65k | name[MagickPathExtent]; |
177 | | |
178 | 1.65k | Image |
179 | 1.65k | *image; |
180 | | |
181 | 1.65k | int |
182 | 1.65k | c; |
183 | | |
184 | 1.65k | long |
185 | 1.65k | height, |
186 | 1.65k | width; |
187 | | |
188 | 1.65k | MagickBooleanType |
189 | 1.65k | status; |
190 | | |
191 | 1.65k | MagickOffsetType |
192 | 1.65k | offset; |
193 | | |
194 | 1.65k | Quantum |
195 | 1.65k | *q; |
196 | | |
197 | 1.65k | short int |
198 | 1.65k | hex_digits[256]; |
199 | | |
200 | 1.65k | size_t |
201 | 1.65k | bytes_per_line, |
202 | 1.65k | length; |
203 | | |
204 | 1.65k | ssize_t |
205 | 1.65k | i, |
206 | 1.65k | x, |
207 | 1.65k | y; |
208 | | |
209 | 1.65k | unsigned char |
210 | 1.65k | *data, |
211 | 1.65k | *p; |
212 | | |
213 | 1.65k | unsigned int |
214 | 1.65k | bit, |
215 | 1.65k | byte, |
216 | 1.65k | padding, |
217 | 1.65k | version; |
218 | | |
219 | | /* |
220 | | Open image file. |
221 | | */ |
222 | 1.65k | assert(image_info != (const ImageInfo *) NULL); |
223 | 1.65k | assert(image_info->signature == MagickCoreSignature); |
224 | 1.65k | assert(exception != (ExceptionInfo *) NULL); |
225 | 1.65k | assert(exception->signature == MagickCoreSignature); |
226 | 1.65k | if (IsEventLogging() != MagickFalse) |
227 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
228 | 0 | image_info->filename); |
229 | 1.65k | image=AcquireImage(image_info,exception); |
230 | 1.65k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
231 | 1.65k | if (status == MagickFalse) |
232 | 0 | { |
233 | 0 | image=DestroyImageList(image); |
234 | 0 | return((Image *) NULL); |
235 | 0 | } |
236 | | /* |
237 | | Read X bitmap header. |
238 | | */ |
239 | 1.65k | width=0; |
240 | 1.65k | height=0; |
241 | 1.65k | *name='\0'; |
242 | 4.77k | while (ReadBlobString(image,buffer) != (char *) NULL) |
243 | 4.24k | if (MagickSscanf(buffer,"#define %1024s %ld",name,&width) == 2) |
244 | 2.20k | if ((strlen(name) >= 6) && |
245 | 1.79k | (LocaleCompare(name+strlen(name)-6,"_width") == 0)) |
246 | 1.13k | break; |
247 | 3.58k | while (ReadBlobString(image,buffer) != (char *) NULL) |
248 | 2.91k | if (MagickSscanf(buffer,"#define %1024s %ld",name,&height) == 2) |
249 | 1.77k | if ((strlen(name) >= 7) && |
250 | 1.25k | (LocaleCompare(name+strlen(name)-7,"_height") == 0)) |
251 | 982 | break; |
252 | 1.65k | if ((width <= 0) || (height <= 0) || (EOFBlob(image) != MagickFalse)) |
253 | 980 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
254 | 980 | image->columns=(size_t) width; |
255 | 980 | image->rows=(size_t) height; |
256 | 980 | image->depth=8; |
257 | 980 | image->storage_class=PseudoClass; |
258 | 980 | image->colors=2; |
259 | | /* |
260 | | Scan until hex digits. |
261 | | */ |
262 | 980 | version=11; |
263 | 980 | offset=TellBlob(image); |
264 | 5.33k | while (ReadBlobString(image,buffer) != (char *) NULL) |
265 | 5.03k | { |
266 | 5.03k | if (MagickSscanf(buffer,"static short %1024s = {",name) == 1) |
267 | 623 | version=10; |
268 | 4.41k | else if (MagickSscanf(buffer,"static unsigned char %1024s = {",name) == 1) |
269 | 231 | version=11; |
270 | 4.18k | else if (MagickSscanf(buffer,"static char %1024s = {",name) == 1) |
271 | 2.78k | version=11; |
272 | 1.39k | else |
273 | 1.39k | { |
274 | 1.39k | offset=TellBlob(image); |
275 | 1.39k | continue; |
276 | 1.39k | } |
277 | 3.63k | p=(unsigned char *) strrchr(name,'_'); |
278 | 3.63k | if (p == (unsigned char *) NULL) |
279 | 3.35k | p=(unsigned char *) name; |
280 | 277 | else |
281 | 277 | p++; |
282 | 3.63k | if (LocaleCompare("bits[]",(char *) p) == 0) |
283 | 681 | break; |
284 | 3.63k | } |
285 | | /* |
286 | | Initialize image structure. |
287 | | */ |
288 | 980 | if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) |
289 | 980 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
290 | | /* |
291 | | Initialize colormap. |
292 | | */ |
293 | 980 | image->colormap[0].red=(MagickRealType) QuantumRange; |
294 | 980 | image->colormap[0].green=(MagickRealType) QuantumRange; |
295 | 980 | image->colormap[0].blue=(MagickRealType) QuantumRange; |
296 | 980 | image->colormap[1].red=0.0; |
297 | 980 | image->colormap[1].green=0.0; |
298 | 980 | image->colormap[1].blue=0.0; |
299 | 980 | if (image_info->ping != MagickFalse) |
300 | 1 | { |
301 | 1 | (void) CloseBlob(image); |
302 | 1 | return(GetFirstImageInList(image)); |
303 | 1 | } |
304 | 979 | status=SetImageExtent(image,image->columns,image->rows,exception); |
305 | 979 | if (status == MagickFalse) |
306 | 185 | return(DestroyImageList(image)); |
307 | 794 | p=(unsigned char *) strrchr(buffer,'{'); |
308 | 794 | if (p != (unsigned char *) NULL) |
309 | 24 | (void) SeekBlob(image,offset+((char *) p-buffer)+1,SEEK_SET); |
310 | | /* |
311 | | Initialize hex values. |
312 | | */ |
313 | 204k | for (i=0; i < (ssize_t) (sizeof(hex_digits)/sizeof(*hex_digits)); i++) |
314 | 203k | hex_digits[i]=(-1); |
315 | 794 | hex_digits[(int) '0']=0; |
316 | 794 | hex_digits[(int) '1']=1; |
317 | 794 | hex_digits[(int) '2']=2; |
318 | 794 | hex_digits[(int) '3']=3; |
319 | 794 | hex_digits[(int) '4']=4; |
320 | 794 | hex_digits[(int) '5']=5; |
321 | 794 | hex_digits[(int) '6']=6; |
322 | 794 | hex_digits[(int) '7']=7; |
323 | 794 | hex_digits[(int) '8']=8; |
324 | 794 | hex_digits[(int) '9']=9; |
325 | 794 | hex_digits[(int) 'A']=10; |
326 | 794 | hex_digits[(int) 'B']=11; |
327 | 794 | hex_digits[(int) 'C']=12; |
328 | 794 | hex_digits[(int) 'D']=13; |
329 | 794 | hex_digits[(int) 'E']=14; |
330 | 794 | hex_digits[(int) 'F']=15; |
331 | 794 | hex_digits[(int) 'a']=10; |
332 | 794 | hex_digits[(int) 'b']=11; |
333 | 794 | hex_digits[(int) 'c']=12; |
334 | 794 | hex_digits[(int) 'd']=13; |
335 | 794 | hex_digits[(int) 'e']=14; |
336 | 794 | hex_digits[(int) 'f']=15; |
337 | 794 | hex_digits[(int) 'x']=0; |
338 | 794 | hex_digits[(int) ' ']=(-1); |
339 | 794 | hex_digits[(int) ',']=(-1); |
340 | 794 | hex_digits[(int) '}']=(-1); |
341 | 794 | hex_digits[(int) '\n']=(-1); |
342 | 794 | hex_digits[(int) '\t']=(-1); |
343 | | /* |
344 | | Read hex image data. |
345 | | */ |
346 | 794 | padding=0; |
347 | 794 | if (((image->columns % 16) != 0) && ((image->columns % 16) < 9) && |
348 | 566 | (version == 10)) |
349 | 239 | padding=1; |
350 | 794 | bytes_per_line=(image->columns+7)/8+padding; |
351 | 794 | if (HeapOverflowSanityCheckGetSize(bytes_per_line,image->rows,&length) != MagickFalse) |
352 | 794 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
353 | 794 | data=(unsigned char *) AcquireQuantumMemory(length,sizeof(*data)); |
354 | 794 | if (data == (unsigned char *) NULL) |
355 | 794 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
356 | 794 | p=data; |
357 | 794 | if (version == 10) |
358 | 52.5k | for (i=0; i < (ssize_t) length; i+=2) |
359 | 52.3k | { |
360 | 52.3k | c=XBMInteger(image,hex_digits); |
361 | 52.3k | if (c < 0) |
362 | 176 | { |
363 | 176 | data=(unsigned char *) RelinquishMagickMemory(data); |
364 | 176 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
365 | 0 | } |
366 | 52.1k | *p++=(unsigned char) c; |
367 | 52.1k | if ((padding == 0) || (((i+2) % bytes_per_line) != 0)) |
368 | 46.7k | *p++=(unsigned char) (c >> 8); |
369 | 52.1k | } |
370 | 361 | else |
371 | 2.53k | for (i=0; i < (ssize_t) length; i++) |
372 | 2.43k | { |
373 | 2.43k | c=XBMInteger(image,hex_digits); |
374 | 2.43k | if (c < 0) |
375 | 261 | { |
376 | 261 | data=(unsigned char *) RelinquishMagickMemory(data); |
377 | 261 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
378 | 0 | } |
379 | 2.17k | *p++=(unsigned char) c; |
380 | 2.17k | } |
381 | 357 | if (EOFBlob(image) != MagickFalse) |
382 | 0 | { |
383 | 0 | data=(unsigned char *) RelinquishMagickMemory(data); |
384 | 0 | ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); |
385 | 0 | } |
386 | | /* |
387 | | Convert X bitmap image to pixel packets. |
388 | | */ |
389 | 357 | p=data; |
390 | 13.8k | for (y=0; y < (ssize_t) image->rows; y++) |
391 | 13.4k | { |
392 | 13.4k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
393 | 13.4k | if (q == (Quantum *) NULL) |
394 | 0 | break; |
395 | 13.4k | bit=0; |
396 | 13.4k | byte=0; |
397 | 754k | for (x=0; x < (ssize_t) image->columns; x++) |
398 | 740k | { |
399 | 740k | if (bit == 0) |
400 | 99.1k | byte=(unsigned int) (*p++); |
401 | 740k | SetPixelIndex(image,(Quantum) ((byte & 0x01) != 0 ? 0x01 : 0x00),q); |
402 | 740k | bit++; |
403 | 740k | byte>>=1; |
404 | 740k | if (bit == 8) |
405 | 88.0k | bit=0; |
406 | 740k | q+=(ptrdiff_t) GetPixelChannels(image); |
407 | 740k | } |
408 | 13.4k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
409 | 0 | break; |
410 | 13.4k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
411 | 13.4k | image->rows); |
412 | 13.4k | if (status == MagickFalse) |
413 | 0 | break; |
414 | 13.4k | } |
415 | 357 | data=(unsigned char *) RelinquishMagickMemory(data); |
416 | 357 | (void) SyncImage(image,exception); |
417 | 357 | if (CloseBlob(image) == MagickFalse) |
418 | 0 | status=MagickFalse; |
419 | 357 | if (status == MagickFalse) |
420 | 0 | return(DestroyImageList(image)); |
421 | 357 | return(GetFirstImageInList(image)); |
422 | 357 | } |
423 | | |
424 | | /* |
425 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
426 | | % % |
427 | | % % |
428 | | % % |
429 | | % R e g i s t e r X B M I m a g e % |
430 | | % % |
431 | | % % |
432 | | % % |
433 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
434 | | % |
435 | | % RegisterXBMImage() adds attributes for the XBM image format to |
436 | | % the list of supported formats. The attributes include the image format |
437 | | % tag, a method to read and/or write the format, whether the format |
438 | | % supports the saving of more than one frame to the same file or blob, |
439 | | % whether the format supports native in-memory I/O, and a brief |
440 | | % description of the format. |
441 | | % |
442 | | % The format of the RegisterXBMImage method is: |
443 | | % |
444 | | % size_t RegisterXBMImage(void) |
445 | | % |
446 | | */ |
447 | | ModuleExport size_t RegisterXBMImage(void) |
448 | 9 | { |
449 | 9 | MagickInfo |
450 | 9 | *entry; |
451 | | |
452 | 9 | entry=AcquireMagickInfo("XBM","XBM", |
453 | 9 | "X Windows system bitmap (black and white)"); |
454 | 9 | entry->decoder=(DecodeImageHandler *) ReadXBMImage; |
455 | 9 | entry->encoder=(EncodeImageHandler *) WriteXBMImage; |
456 | 9 | entry->magick=(IsImageFormatHandler *) IsXBM; |
457 | 9 | entry->flags|=CoderDecoderSeekableStreamFlag; |
458 | 9 | entry->flags^=CoderAdjoinFlag; |
459 | 9 | (void) RegisterMagickInfo(entry); |
460 | 9 | return(MagickImageCoderSignature); |
461 | 9 | } |
462 | | |
463 | | /* |
464 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
465 | | % % |
466 | | % % |
467 | | % % |
468 | | % U n r e g i s t e r X B M I m a g e % |
469 | | % % |
470 | | % % |
471 | | % % |
472 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
473 | | % |
474 | | % UnregisterXBMImage() removes format registrations made by the |
475 | | % XBM module from the list of supported formats. |
476 | | % |
477 | | % The format of the UnregisterXBMImage method is: |
478 | | % |
479 | | % UnregisterXBMImage(void) |
480 | | % |
481 | | */ |
482 | | ModuleExport void UnregisterXBMImage(void) |
483 | 0 | { |
484 | 0 | (void) UnregisterMagickInfo("XBM"); |
485 | 0 | } |
486 | | |
487 | | /* |
488 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
489 | | % % |
490 | | % % |
491 | | % % |
492 | | % W r i t e X B M I m a g e % |
493 | | % % |
494 | | % % |
495 | | % % |
496 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
497 | | % |
498 | | % WriteXBMImage() writes an image to a file in the X bitmap format. |
499 | | % |
500 | | % The format of the WriteXBMImage method is: |
501 | | % |
502 | | % MagickBooleanType WriteXBMImage(const ImageInfo *image_info, |
503 | | % Image *image,ExceptionInfo *exception) |
504 | | % |
505 | | % A description of each parameter follows. |
506 | | % |
507 | | % o image_info: the image info. |
508 | | % |
509 | | % o image: The image. |
510 | | % |
511 | | % o exception: return any errors or warnings in this structure. |
512 | | % |
513 | | */ |
514 | | static MagickBooleanType WriteXBMImage(const ImageInfo *image_info,Image *image, |
515 | | ExceptionInfo *exception) |
516 | 357 | { |
517 | 357 | char |
518 | 357 | basename[MagickPathExtent], |
519 | 357 | buffer[MagickPathExtent]; |
520 | | |
521 | 357 | MagickBooleanType |
522 | 357 | status; |
523 | | |
524 | 357 | const Quantum |
525 | 357 | *p; |
526 | | |
527 | 357 | ssize_t |
528 | 357 | x; |
529 | | |
530 | 357 | size_t |
531 | 357 | bit, |
532 | 357 | byte; |
533 | | |
534 | 357 | ssize_t |
535 | 357 | count, |
536 | 357 | y; |
537 | | |
538 | | /* |
539 | | Open output image file. |
540 | | */ |
541 | 357 | assert(image_info != (const ImageInfo *) NULL); |
542 | 357 | assert(image_info->signature == MagickCoreSignature); |
543 | 357 | assert(image != (Image *) NULL); |
544 | 357 | assert(image->signature == MagickCoreSignature); |
545 | 357 | assert(exception != (ExceptionInfo *) NULL); |
546 | 357 | assert(exception->signature == MagickCoreSignature); |
547 | 357 | if (image->debug != MagickFalse) |
548 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
549 | 357 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
550 | 357 | if (status == MagickFalse) |
551 | 0 | return(status); |
552 | 357 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
553 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
554 | | /* |
555 | | Write X bitmap header. |
556 | | */ |
557 | 357 | GetPathComponent(image->filename,BasePath,basename); |
558 | 357 | (void) FormatLocaleString(buffer,MagickPathExtent,"#define %s_width %.20g\n", |
559 | 357 | basename,(double) image->columns); |
560 | 357 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
561 | 357 | (void) FormatLocaleString(buffer,MagickPathExtent,"#define %s_height %.20g\n", |
562 | 357 | basename,(double) image->rows); |
563 | 357 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
564 | 357 | (void) FormatLocaleString(buffer,MagickPathExtent, |
565 | 357 | "static char %s_bits[] = {\n",basename); |
566 | 357 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
567 | 357 | (void) CopyMagickString(buffer," ",MagickPathExtent); |
568 | 357 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
569 | | /* |
570 | | Convert MIFF to X bitmap pixels. |
571 | | */ |
572 | 357 | (void) SetImageType(image,BilevelType,exception); |
573 | 357 | bit=0; |
574 | 357 | byte=0; |
575 | 357 | count=0; |
576 | 357 | x=0; |
577 | 357 | y=0; |
578 | 357 | (void) CopyMagickString(buffer," ",MagickPathExtent); |
579 | 357 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
580 | 13.8k | for (y=0; y < (ssize_t) image->rows; y++) |
581 | 13.4k | { |
582 | 13.4k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
583 | 13.4k | if (p == (const Quantum *) NULL) |
584 | 0 | break; |
585 | 754k | for (x=0; x < (ssize_t) image->columns; x++) |
586 | 740k | { |
587 | 740k | byte>>=1; |
588 | 740k | if (GetPixelLuma(image,p) < ((double) QuantumRange/2)) |
589 | 127k | byte|=0x80; |
590 | 740k | bit++; |
591 | 740k | if (bit == 8) |
592 | 88.0k | { |
593 | | /* |
594 | | Write a bitmap byte to the image file. |
595 | | */ |
596 | 88.0k | (void) FormatLocaleString(buffer,MagickPathExtent,"0x%02X, ", |
597 | 88.0k | (unsigned int) (byte & 0xff)); |
598 | 88.0k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
599 | 88.0k | count++; |
600 | 88.0k | if (count == 12) |
601 | 6.36k | { |
602 | 6.36k | (void) CopyMagickString(buffer,"\n ",MagickPathExtent); |
603 | 6.36k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
604 | 6.36k | count=0; |
605 | 6.36k | }; |
606 | 88.0k | bit=0; |
607 | 88.0k | byte=0; |
608 | 88.0k | } |
609 | 740k | p+=(ptrdiff_t) GetPixelChannels(image); |
610 | 740k | } |
611 | 13.4k | if (bit != 0) |
612 | 11.0k | { |
613 | | /* |
614 | | Write a bitmap byte to the image file. |
615 | | */ |
616 | 11.0k | byte>>=(8-bit); |
617 | 11.0k | (void) FormatLocaleString(buffer,MagickPathExtent,"0x%02X, ", |
618 | 11.0k | (unsigned int) (byte & 0xff)); |
619 | 11.0k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
620 | 11.0k | count++; |
621 | 11.0k | if (count == 12) |
622 | 1.76k | { |
623 | 1.76k | (void) CopyMagickString(buffer,"\n ",MagickPathExtent); |
624 | 1.76k | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
625 | 1.76k | count=0; |
626 | 1.76k | }; |
627 | 11.0k | bit=0; |
628 | 11.0k | byte=0; |
629 | 11.0k | }; |
630 | 13.4k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
631 | 13.4k | image->rows); |
632 | 13.4k | if (status == MagickFalse) |
633 | 0 | break; |
634 | 13.4k | } |
635 | 357 | (void) CopyMagickString(buffer,"};\n",MagickPathExtent); |
636 | 357 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
637 | 357 | if (CloseBlob(image) == MagickFalse) |
638 | 0 | status=MagickFalse; |
639 | 357 | return(status); |
640 | 357 | } |