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