Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            M   M   AAA   PPPP                               %
      7 %                            MM MM  A   A  P   P                              %
      8 %                            M M M  AAAAA  PPPP                               %
      9 %                            M   M  A   A  P                                  %
     10 %                            M   M  A   A  P                                  %
     11 %                                                                             %
     12 %                                                                             %
     13 %                  Read/Write Image Colormaps as an Image File.               %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2019 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 /*
     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.h"
     49 #include "MagickCore/color-private.h"
     50 #include "MagickCore/colormap.h"
     51 #include "MagickCore/colormap-private.h"
     52 #include "MagickCore/colorspace.h"
     53 #include "MagickCore/colorspace-private.h"
     54 #include "MagickCore/exception.h"
     55 #include "MagickCore/exception-private.h"
     56 #include "MagickCore/histogram.h"
     57 #include "MagickCore/image.h"
     58 #include "MagickCore/image-private.h"
     59 #include "MagickCore/list.h"
     60 #include "MagickCore/magick.h"
     61 #include "MagickCore/memory_.h"
     62 #include "MagickCore/pixel-accessor.h"
     63 #include "MagickCore/quantum-private.h"
     64 #include "MagickCore/static.h"
     65 #include "MagickCore/statistic.h"
     66 #include "MagickCore/string_.h"
     67 #include "MagickCore/module.h"
     68 
     69 /*
     71   Forward declarations.
     72 */
     73 static MagickBooleanType
     74   WriteMAPImage(const ImageInfo *,Image *,ExceptionInfo *);
     75 
     76 /*
     78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     79 %                                                                             %
     80 %                                                                             %
     81 %                                                                             %
     82 %   R e a d M A P I m a g e                                                   %
     83 %                                                                             %
     84 %                                                                             %
     85 %                                                                             %
     86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     87 %
     88 %  ReadMAPImage() reads an image of raw RGB colormap and colormap index
     89 %  bytes and returns it.  It allocates the memory necessary for the new Image
     90 %  structure and returns a pointer to the new image.
     91 %
     92 %  The format of the ReadMAPImage method is:
     93 %
     94 %      Image *ReadMAPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     95 %
     96 %  A description of each parameter follows:
     97 %
     98 %    o image_info: the image info.
     99 %
    100 %    o exception: return any errors or warnings in this structure.
    101 %
    102 */
    103 static Image *ReadMAPImage(const ImageInfo *image_info,ExceptionInfo *exception)
    104 {
    105   Image
    106     *image;
    107 
    108   MagickBooleanType
    109     status;
    110 
    111   Quantum
    112     index;
    113 
    114   register ssize_t
    115     x;
    116 
    117   register Quantum
    118     *q;
    119 
    120   register ssize_t
    121     i;
    122 
    123   register unsigned char
    124     *p;
    125 
    126   size_t
    127     depth,
    128     packet_size,
    129     quantum;
    130 
    131   ssize_t
    132     count,
    133     y;
    134 
    135   unsigned char
    136     *colormap,
    137     *pixels;
    138 
    139   /*
    140     Open image file.
    141   */
    142   assert(image_info != (const ImageInfo *) NULL);
    143   assert(image_info->signature == MagickCoreSignature);
    144   if (image_info->debug != MagickFalse)
    145     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    146       image_info->filename);
    147   assert(exception != (ExceptionInfo *) NULL);
    148   assert(exception->signature == MagickCoreSignature);
    149   image=AcquireImage(image_info,exception);
    150   if ((image->columns == 0) || (image->rows == 0))
    151     ThrowReaderException(OptionError,"MustSpecifyImageSize");
    152   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    153   if (status == MagickFalse)
    154     {
    155       image=DestroyImageList(image);
    156       return((Image *) NULL);
    157     }
    158   /*
    159     Initialize image structure.
    160   */
    161   image->storage_class=PseudoClass;
    162   status=AcquireImageColormap(image,(size_t)
    163     (image->offset != 0 ? image->offset : 256),exception);
    164   if (status == MagickFalse)
    165     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    166   depth=GetImageQuantumDepth(image,MagickTrue);
    167   packet_size=(size_t) (depth/8);
    168   pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
    169     sizeof(*pixels));
    170   packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
    171   colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
    172     sizeof(*colormap));
    173   if ((pixels == (unsigned char *) NULL) ||
    174       (colormap == (unsigned char *) NULL))
    175     {
    176       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    177       colormap=(unsigned char *) RelinquishMagickMemory(colormap);
    178       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    179     }
    180   /*
    181     Read image colormap.
    182   */
    183   count=ReadBlob(image,packet_size*image->colors,colormap);
    184   if (count != (ssize_t) (packet_size*image->colors))
    185     {
    186       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    187       colormap=(unsigned char *) RelinquishMagickMemory(colormap);
    188       ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    189     }
    190   p=colormap;
    191   if (image->depth <= 8)
    192     for (i=0; i < (ssize_t) image->colors; i++)
    193     {
    194       image->colormap[i].red=ScaleCharToQuantum(*p++);
    195       image->colormap[i].green=ScaleCharToQuantum(*p++);
    196       image->colormap[i].blue=ScaleCharToQuantum(*p++);
    197     }
    198   else
    199     for (i=0; i < (ssize_t) image->colors; i++)
    200     {
    201       quantum=(*p++ << 8);
    202       quantum|=(*p++);
    203       image->colormap[i].red=(Quantum) quantum;
    204       quantum=(*p++ << 8);
    205       quantum|=(*p++);
    206       image->colormap[i].green=(Quantum) quantum;
    207       quantum=(*p++ << 8);
    208       quantum|=(*p++);
    209       image->colormap[i].blue=(Quantum) quantum;
    210     }
    211   colormap=(unsigned char *) RelinquishMagickMemory(colormap);
    212   if (image_info->ping != MagickFalse)
    213     {
    214       (void) CloseBlob(image);
    215       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    216       return(GetFirstImageInList(image));
    217     }
    218   status=SetImageExtent(image,image->columns,image->rows,exception);
    219   if (status == MagickFalse)
    220     {
    221       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    222       return(DestroyImageList(image));
    223     }
    224   /*
    225     Read image pixels.
    226   */
    227   packet_size=(size_t) (depth/8);
    228   for (y=0; y < (ssize_t) image->rows; y++)
    229   {
    230     p=pixels;
    231     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    232     if (q == (Quantum *) NULL)
    233       break;
    234     count=ReadBlob(image,(size_t) packet_size*image->columns,pixels);
    235     if (count != (ssize_t) (packet_size*image->columns))
    236       break;
    237     for (x=0; x < (ssize_t) image->columns; x++)
    238     {
    239       index=ConstrainColormapIndex(image,*p,exception);
    240       p++;
    241       if (image->colors > 256)
    242         {
    243           index=ConstrainColormapIndex(image,((size_t) index << 8)+(*p),
    244             exception);
    245           p++;
    246         }
    247       SetPixelIndex(image,index,q);
    248       SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
    249       q+=GetPixelChannels(image);
    250     }
    251     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    252       break;
    253   }
    254   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    255   if (y < (ssize_t) image->rows)
    256     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    257       image->filename);
    258   (void) CloseBlob(image);
    259   return(GetFirstImageInList(image));
    260 }
    261 
    262 /*
    264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    265 %                                                                             %
    266 %                                                                             %
    267 %                                                                             %
    268 %   R e g i s t e r M A P I m a g e                                           %
    269 %                                                                             %
    270 %                                                                             %
    271 %                                                                             %
    272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    273 %
    274 %  RegisterMAPImage() adds attributes for the MAP image format to
    275 %  the list of supported formats.  The attributes include the image format
    276 %  tag, a method to read and/or write the format, whether the format
    277 %  supports the saving of more than one frame to the same file or blob,
    278 %  whether the format supports native in-memory I/O, and a brief
    279 %  description of the format.
    280 %
    281 %  The format of the RegisterMAPImage method is:
    282 %
    283 %      size_t RegisterMAPImage(void)
    284 %
    285 */
    286 ModuleExport size_t RegisterMAPImage(void)
    287 {
    288   MagickInfo
    289     *entry;
    290 
    291   entry=AcquireMagickInfo("MAP","MAP","Colormap intensities and indices");
    292   entry->decoder=(DecodeImageHandler *) ReadMAPImage;
    293   entry->encoder=(EncodeImageHandler *) WriteMAPImage;
    294   entry->flags^=CoderAdjoinFlag;
    295   entry->format_type=ExplicitFormatType;
    296   entry->flags|=CoderRawSupportFlag;
    297   entry->flags|=CoderEndianSupportFlag;
    298   (void) RegisterMagickInfo(entry);
    299   return(MagickImageCoderSignature);
    300 }
    301 
    302 /*
    304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    305 %                                                                             %
    306 %                                                                             %
    307 %                                                                             %
    308 %   U n r e g i s t e r M A P I m a g e                                       %
    309 %                                                                             %
    310 %                                                                             %
    311 %                                                                             %
    312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    313 %
    314 %  UnregisterMAPImage() removes format registrations made by the
    315 %  MAP module from the list of supported formats.
    316 %
    317 %  The format of the UnregisterMAPImage method is:
    318 %
    319 %      UnregisterMAPImage(void)
    320 %
    321 */
    322 ModuleExport void UnregisterMAPImage(void)
    323 {
    324   (void) UnregisterMagickInfo("MAP");
    325 }
    326 
    327 /*
    329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    330 %                                                                             %
    331 %                                                                             %
    332 %                                                                             %
    333 %   W r i t e M A P I m a g e                                                 %
    334 %                                                                             %
    335 %                                                                             %
    336 %                                                                             %
    337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    338 %
    339 %  WriteMAPImage() writes an image to a file as red, green, and blue
    340 %  colormap bytes followed by the colormap indexes.
    341 %
    342 %  The format of the WriteMAPImage method is:
    343 %
    344 %      MagickBooleanType WriteMAPImage(const ImageInfo *image_info,
    345 %        Image *image,ExceptionInfo *exception)
    346 %
    347 %  A description of each parameter follows.
    348 %
    349 %    o image_info: the image info.
    350 %
    351 %    o image:  The image.
    352 %
    353 %    o exception: return any errors or warnings in this structure.
    354 %
    355 */
    356 static MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image,
    357   ExceptionInfo *exception)
    358 {
    359   MagickBooleanType
    360     status;
    361 
    362   register const Quantum
    363     *p;
    364 
    365   register ssize_t
    366     i,
    367     x;
    368 
    369   register unsigned char
    370     *q;
    371 
    372   size_t
    373     depth,
    374     packet_size;
    375 
    376   ssize_t
    377     y;
    378 
    379   unsigned char
    380     *colormap,
    381     *pixels;
    382 
    383   /*
    384     Open output image file.
    385   */
    386   assert(image_info != (const ImageInfo *) NULL);
    387   assert(image_info->signature == MagickCoreSignature);
    388   assert(image != (Image *) NULL);
    389   assert(image->signature == MagickCoreSignature);
    390   if (image->debug != MagickFalse)
    391     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    392   assert(exception != (ExceptionInfo *) NULL);
    393   assert(exception->signature == MagickCoreSignature);
    394   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    395   if (status == MagickFalse)
    396     return(status);
    397   (void) TransformImageColorspace(image,sRGBColorspace,exception);
    398   /*
    399     Allocate colormap.
    400   */
    401   if (SetImageType(image,PaletteType,exception) == MagickFalse)
    402     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    403   depth=GetImageQuantumDepth(image,MagickTrue);
    404   packet_size=(size_t) (depth/8);
    405   pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
    406     sizeof(*pixels));
    407   packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
    408   colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
    409     sizeof(*colormap));
    410   if ((pixels == (unsigned char *) NULL) ||
    411       (colormap == (unsigned char *) NULL))
    412     {
    413       if (colormap != (unsigned char *) NULL)
    414         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
    415       if (pixels != (unsigned char *) NULL)
    416         pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    417       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    418     }
    419   /*
    420     Write colormap to file.
    421   */
    422   q=colormap;
    423   if (image->colors <= 256)
    424     for (i=0; i < (ssize_t) image->colors; i++)
    425     {
    426       *q++=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
    427       *q++=(unsigned char) ScaleQuantumToChar(image->colormap[i].green);
    428       *q++=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
    429     }
    430   else
    431     for (i=0; i < (ssize_t) image->colors; i++)
    432     {
    433       *q++=(unsigned char) (ScaleQuantumToShort(image->colormap[i].red) >> 8);
    434       *q++=(unsigned char) (ScaleQuantumToShort(image->colormap[i].red) & 0xff);
    435       *q++=(unsigned char) (ScaleQuantumToShort(image->colormap[i].green) >> 8);
    436       *q++=(unsigned char) (ScaleQuantumToShort(image->colormap[i].green) &
    437         0xff);
    438       *q++=(unsigned char) (ScaleQuantumToShort(image->colormap[i].blue) >> 8);
    439       *q++=(unsigned char) (ScaleQuantumToShort(image->colormap[i].blue) &
    440         0xff);
    441     }
    442   (void) WriteBlob(image,packet_size*image->colors,colormap);
    443   colormap=(unsigned char *) RelinquishMagickMemory(colormap);
    444   /*
    445     Write image pixels to file.
    446   */
    447   for (y=0; y < (ssize_t) image->rows; y++)
    448   {
    449     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    450     if (p == (const Quantum *) NULL)
    451       break;
    452     q=pixels;
    453     for (x=0; x < (ssize_t) image->columns; x++)
    454     {
    455       if (image->colors > 256)
    456         *q++=(unsigned char) ((size_t) GetPixelIndex(image,p) >> 8);
    457       *q++=(unsigned char) GetPixelIndex(image,p);
    458       p+=GetPixelChannels(image);
    459     }
    460     (void) WriteBlob(image,(size_t) (q-pixels),pixels);
    461   }
    462   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    463   (void) CloseBlob(image);
    464   return(status);
    465 }
    466