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