blob: 999fa9aa1646ccf403e616e31cc1b85573080231 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1992 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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 "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
46#include "magick/color-private.h"
47#include "magick/colorspace.h"
48#include "magick/exception.h"
49#include "magick/exception-private.h"
50#include "magick/image.h"
51#include "magick/image-private.h"
52#include "magick/list.h"
53#include "magick/magick.h"
54#include "magick/memory_.h"
55#include "magick/monitor.h"
56#include "magick/monitor-private.h"
57#include "magick/quantum-private.h"
58#include "magick/static.h"
59#include "magick/string_.h"
60#include "magick/module.h"
61#include "magick/utility.h"
62
63/*
64 Forward declarations.
65*/
66static MagickBooleanType
67 WriteXBMImage(const ImageInfo *,Image *);
68
69/*
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71% %
72% %
73% %
74% I s X B M %
75% %
76% %
77% %
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79%
80% IsXBM() returns MagickTrue if the image format type, identified by the
81% magick string, is XBM.
82%
83% The format of the IsXBM method is:
84%
85% MagickBooleanType IsXBM(const unsigned char *magick,const size_t length)
86%
87% A description of each parameter follows:
88%
89% o magick: compare image format pattern against these bytes.
90%
91% o length: Specifies the length of the magick string.
92%
93*/
94static MagickBooleanType IsXBM(const unsigned char *magick,const size_t length)
95{
96 if (length < 7)
97 return(MagickFalse);
98 if (memcmp(magick,"#define",7) == 0)
99 return(MagickTrue);
100 return(MagickFalse);
101}
102
103/*
104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105% %
106% %
107% %
108% R e a d X B M I m a g e %
109% %
110% %
111% %
112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113%
114% ReadXBMImage() reads an X11 bitmap image file and returns it. It
115% allocates the memory necessary for the new Image structure and returns a
116% pointer to the new image.
117%
118% The format of the ReadXBMImage method is:
119%
120% Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
121%
122% A description of each parameter follows:
123%
124% o image_info: the image info.
125%
126% o exception: return any errors or warnings in this structure.
127%
128*/
129
130static int XBMInteger(Image *image,short int *hex_digits)
131{
132 int
133 c,
134 flag,
135 value;
136
137 value=0;
138 flag=0;
139 for ( ; ; )
140 {
141 c=ReadBlobByte(image);
142 if (c == EOF)
143 {
144 value=(-1);
145 break;
146 }
147 c&=0xff;
148 if (isxdigit(c) != MagickFalse)
149 {
150 value=(int) ((unsigned long) value << 4)+hex_digits[c];
151 flag++;
152 continue;
153 }
154 if ((hex_digits[c]) < 0 && (flag != 0))
155 break;
156 }
157 return(value);
158}
159
160static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
161{
162 char
163 buffer[MaxTextExtent],
164 name[MaxTextExtent];
165
166 Image
167 *image;
168
169 long
170 y;
171
172 MagickBooleanType
173 status;
174
175 register IndexPacket
176 *indexes;
177
178 register long
179 i,
180 x;
181
182 register PixelPacket
183 *q;
184
185 register unsigned char
186 *p;
187
188 short int
189 hex_digits[256];
190
191 size_t
192 length;
193
194 unsigned char
195 *data;
196
197 unsigned long
198 bit,
199 byte,
200 bytes_per_line,
201 padding,
202 value,
203 version;
204
205 /*
206 Open image file.
207 */
208 assert(image_info != (const ImageInfo *) NULL);
209 assert(image_info->signature == MagickSignature);
210 if (image_info->debug != MagickFalse)
211 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
212 image_info->filename);
213 assert(exception != (ExceptionInfo *) NULL);
214 assert(exception->signature == MagickSignature);
215 image=AcquireImage(image_info);
216 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
217 if (status == MagickFalse)
218 {
219 image=DestroyImageList(image);
220 return((Image *) NULL);
221 }
222 /*
223 Read X bitmap header.
224 */
225 while (ReadBlobString(image,buffer) != (char *) NULL)
226 if (sscanf(buffer,"#define %s %lu",name,&image->columns) == 2)
227 if ((strlen(name) >= 6) &&
228 (LocaleCompare(name+strlen(name)-6,"_width") == 0))
229 break;
230 while (ReadBlobString(image,buffer) != (char *) NULL)
231 if (sscanf(buffer,"#define %s %lu",name,&image->rows) == 2)
232 if ((strlen(name) >= 7) &&
233 (LocaleCompare(name+strlen(name)-7,"_height") == 0))
234 break;
235 image->depth=8;
236 image->storage_class=PseudoClass;
237 image->colors=2;
238 /*
239 Scan until hex digits.
240 */
241 version=11;
242 while (ReadBlobString(image,buffer) != (char *) NULL)
243 {
244 if (sscanf(buffer,"static short %s = {",name) == 1)
245 version=10;
246 else
247 if (sscanf(buffer,"static unsigned char %s = {",name) == 1)
248 version=11;
249 else
250 if (sscanf(buffer,"static char %s = {",name) == 1)
251 version=11;
252 else
253 continue;
254 p=(unsigned char *) strrchr(name,'_');
255 if (p == (unsigned char *) NULL)
256 p=(unsigned char *) name;
257 else
258 p++;
259 if (LocaleCompare("bits[]",(char *) p) == 0)
260 break;
261 }
262 if ((image->columns == 0) || (image->rows == 0) ||
263 (EOFBlob(image) != MagickFalse))
264 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
265 /*
266 Initialize image structure.
267 */
268 if (AcquireImageColormap(image,image->colors) == MagickFalse)
269 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
270 /*
271 Initialize colormap.
272 */
273 image->colormap[0].red=(Quantum) QuantumRange;
274 image->colormap[0].green=(Quantum) QuantumRange;
275 image->colormap[0].blue=(Quantum) QuantumRange;
276 image->colormap[1].red=(Quantum) 0;
277 image->colormap[1].green=(Quantum) 0;
278 image->colormap[1].blue=(Quantum) 0;
279 if (image_info->ping != MagickFalse)
280 {
281 (void) CloseBlob(image);
282 return(GetFirstImageInList(image));
283 }
284 /*
285 Initialize hex values.
286 */
287 hex_digits[(int) '0']=0;
288 hex_digits[(int) '1']=1;
289 hex_digits[(int) '2']=2;
290 hex_digits[(int) '3']=3;
291 hex_digits[(int) '4']=4;
292 hex_digits[(int) '5']=5;
293 hex_digits[(int) '6']=6;
294 hex_digits[(int) '7']=7;
295 hex_digits[(int) '8']=8;
296 hex_digits[(int) '9']=9;
297 hex_digits[(int) 'A']=10;
298 hex_digits[(int) 'B']=11;
299 hex_digits[(int) 'C']=12;
300 hex_digits[(int) 'D']=13;
301 hex_digits[(int) 'E']=14;
302 hex_digits[(int) 'F']=15;
303 hex_digits[(int) 'a']=10;
304 hex_digits[(int) 'b']=11;
305 hex_digits[(int) 'c']=12;
306 hex_digits[(int) 'd']=13;
307 hex_digits[(int) 'e']=14;
308 hex_digits[(int) 'f']=15;
309 hex_digits[(int) 'x']=0;
310 hex_digits[(int) ' ']=(-1);
311 hex_digits[(int) ',']=(-1);
312 hex_digits[(int) '}']=(-1);
313 hex_digits[(int) '\n']=(-1);
314 hex_digits[(int) '\t']=(-1);
315 /*
316 Read hex image data.
317 */
318 padding=0;
319 if (((image->columns % 16) != 0) &&
320 ((image->columns % 16) < 9) && (version == 10))
321 padding=1;
322 bytes_per_line=(image->columns+7)/8+padding;
323 length=(size_t) image->rows;
324 data=(unsigned char *) AcquireQuantumMemory(length,bytes_per_line*
325 sizeof(*data));
326 if (data == (unsigned char *) NULL)
327 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
328 p=data;
329 if (version == 10)
330 for (i=0; i < (long) (bytes_per_line*image->rows); (i+=2))
331 {
332 value=(unsigned long) XBMInteger(image,hex_digits);
333 *p++=(unsigned char) value;
334 if ((padding == 0) || (((i+2) % bytes_per_line) != 0))
335 *p++=(unsigned char) (value >> 8);
336 }
337 else
338 for (i=0; i < (long) (bytes_per_line*image->rows); i++)
339 {
340 value=(unsigned long) XBMInteger(image,hex_digits);
341 *p++=(unsigned char) value;
342 }
343 /*
344 Convert X bitmap image to pixel packets.
345 */
346 p=data;
347 for (y=0; y < (long) image->rows; y++)
348 {
349 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
350 if (q == (PixelPacket *) NULL)
351 break;
352 indexes=GetAuthenticIndexQueue(image);
353 bit=0;
354 byte=0;
355 for (x=0; x < (long) image->columns; x++)
356 {
357 if (bit == 0)
358 byte=(unsigned long) (*p++);
359 indexes[x]=(IndexPacket) ((byte & 0x01) != 0 ? 0x01 : 0x00);
360 bit++;
361 byte>>=1;
362 if (bit == 8)
363 bit=0;
364 }
365 if (SyncAuthenticPixels(image,exception) == MagickFalse)
366 break;
367 status=SetImageProgress(image,LoadImageTag,y,image->rows);
368 if (status == MagickFalse)
369 break;
370 }
371 data=(unsigned char *) RelinquishMagickMemory(data);
372 (void) SyncImage(image);
373 (void) CloseBlob(image);
374 return(GetFirstImageInList(image));
375}
376
377/*
378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379% %
380% %
381% %
382% R e g i s t e r X B M I m a g e %
383% %
384% %
385% %
386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387%
388% RegisterXBMImage() adds attributes for the XBM image format to
389% the list of supported formats. The attributes include the image format
390% tag, a method to read and/or write the format, whether the format
391% supports the saving of more than one frame to the same file or blob,
392% whether the format supports native in-memory I/O, and a brief
393% description of the format.
394%
395% The format of the RegisterXBMImage method is:
396%
397% unsigned long RegisterXBMImage(void)
398%
399*/
400ModuleExport unsigned long RegisterXBMImage(void)
401{
402 MagickInfo
403 *entry;
404
405 entry=SetMagickInfo("XBM");
406 entry->decoder=(DecodeImageHandler *) ReadXBMImage;
407 entry->encoder=(EncodeImageHandler *) WriteXBMImage;
408 entry->magick=(IsImageFormatHandler *) IsXBM;
409 entry->adjoin=MagickFalse;
410 entry->description=ConstantString(
411 "X Windows system bitmap (black and white)");
412 entry->module=ConstantString("XBM");
413 (void) RegisterMagickInfo(entry);
414 return(MagickImageCoderSignature);
415}
416
417/*
418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419% %
420% %
421% %
422% U n r e g i s t e r X B M I m a g e %
423% %
424% %
425% %
426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427%
428% UnregisterXBMImage() removes format registrations made by the
429% XBM module from the list of supported formats.
430%
431% The format of the UnregisterXBMImage method is:
432%
433% UnregisterXBMImage(void)
434%
435*/
436ModuleExport void UnregisterXBMImage(void)
437{
438 (void) UnregisterMagickInfo("XBM");
439}
440
441/*
442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443% %
444% %
445% %
446% W r i t e X B M I m a g e %
447% %
448% %
449% %
450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451%
452% Procedure WriteXBMImage() writes an image to a file in the X bitmap format.
453%
454% The format of the WriteXBMImage method is:
455%
456% MagickBooleanType WriteXBMImage(const ImageInfo *image_info,Image *image)
457%
458% A description of each parameter follows.
459%
460% o image_info: the image info.
461%
462% o image: The image.
463%
464%
465*/
466static MagickBooleanType WriteXBMImage(const ImageInfo *image_info,Image *image)
467{
468 char
469 basename[MaxTextExtent],
470 buffer[MaxTextExtent];
471
472 long
473 y;
474
475 MagickBooleanType
476 status;
477
478 register const PixelPacket
479 *p;
480
481 register long
482 x;
483
484 ssize_t
485 count;
486
487 unsigned long
488 bit,
489 byte;
490
491 /*
492 Open output image file.
493 */
494 assert(image_info != (const ImageInfo *) NULL);
495 assert(image_info->signature == MagickSignature);
496 assert(image != (Image *) NULL);
497 assert(image->signature == MagickSignature);
498 if (image->debug != MagickFalse)
499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
500 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
501 if (status == MagickFalse)
502 return(status);
503 if (image->colorspace != RGBColorspace)
504 (void) TransformImageColorspace(image,RGBColorspace);
505 /*
506 Write X bitmap header.
507 */
508 GetPathComponent(image->filename,BasePath,basename);
509 (void) FormatMagickString(buffer,MaxTextExtent,"#define %s_width %lu\n",
510 basename,image->columns);
511 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
512 (void) FormatMagickString(buffer,MaxTextExtent,"#define %s_height %lu\n",
513 basename,image->rows);
514 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
515 (void) FormatMagickString(buffer,MaxTextExtent,
516 "static char %s_bits[] = {\n",basename);
517 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
518 (void) CopyMagickString(buffer," ",MaxTextExtent);
519 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
520 /*
521 Convert MIFF to X bitmap pixels.
522 */
523 (void) SetImageType(image,BilevelType);
524 bit=0;
525 byte=0;
526 count=0;
527 x=0;
528 y=0;
529 (void) CopyMagickString(buffer," ",MaxTextExtent);
530 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
531 for (y=0; y < (long) image->rows; y++)
532 {
533 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
534 if (p == (const PixelPacket *) NULL)
535 break;
536 for (x=0; x < (long) image->columns; x++)
537 {
538 byte>>=1;
539 if (PixelIntensity(p) < ((MagickRealType) QuantumRange/2.0))
540 byte|=0x80;
541 bit++;
542 if (bit == 8)
543 {
544 /*
545 Write a bitmap byte to the image file.
546 */
547 (void) FormatMagickString(buffer,MaxTextExtent,"0x%02X, ",
548 (unsigned int) (byte & 0xff));
549 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
550 count++;
551 if (count == 12)
552 {
553 (void) CopyMagickString(buffer,"\n ",MaxTextExtent);
554 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
555 count=0;
556 };
557 bit=0;
558 byte=0;
559 }
560 p++;
561 }
562 if (bit != 0)
563 {
564 /*
565 Write a bitmap byte to the image file.
566 */
567 byte>>=(8-bit);
568 (void) FormatMagickString(buffer,MaxTextExtent,"0x%02X, ",
569 (unsigned int) (byte & 0xff));
570 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
571 count++;
572 if (count == 12)
573 {
574 (void) CopyMagickString(buffer,"\n ",MaxTextExtent);
575 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
576 count=0;
577 };
578 bit=0;
579 byte=0;
580 };
581 status=SetImageProgress(image,SaveImageTag,y,image->rows);
582 if (status == MagickFalse)
583 break;
584 }
585 (void) CopyMagickString(buffer,"};\n",MaxTextExtent);
586 (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
587 (void) CloseBlob(image);
588 return(MagickTrue);
589}