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-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.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     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    176   /*
    177     Read image colormap.
    178   */
    179   count=ReadBlob(image,packet_size*image->colors,colormap);
    180   if (count != (ssize_t) (packet_size*image->colors))
    181     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    182   p=colormap;
    183   if (image->depth <= 8)
    184     for (i=0; i < (ssize_t) image->colors; i++)
    185     {
    186       image->colormap[i].red=ScaleCharToQuantum(*p++);
    187       image->colormap[i].green=ScaleCharToQuantum(*p++);
    188       image->colormap[i].blue=ScaleCharToQuantum(*p++);
    189     }
    190   else
    191     for (i=0; i < (ssize_t) image->colors; i++)
    192     {
    193       quantum=(*p++ << 8);
    194       quantum|=(*p++);
    195       image->colormap[i].red=(Quantum) quantum;
    196       quantum=(*p++ << 8);
    197       quantum|=(*p++);
    198       image->colormap[i].green=(Quantum) quantum;
    199       quantum=(*p++ << 8);
    200       quantum|=(*p++);
    201       image->colormap[i].blue=(Quantum) quantum;
    202     }
    203   colormap=(unsigned char *) RelinquishMagickMemory(colormap);
    204   if (image_info->ping != MagickFalse)
    205     {
    206       (void) CloseBlob(image);
    207       return(GetFirstImageInList(image));
    208     }
    209   status=SetImageExtent(image,image->columns,image->rows,exception);
    210   if (status == MagickFalse)
    211     return(DestroyImageList(image));
    212   /*
    213     Read image pixels.
    214   */
    215   packet_size=(size_t) (depth/8);
    216   for (y=0; y < (ssize_t) image->rows; y++)
    217   {
    218     p=pixels;
    219     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    220     if (q == (Quantum *) NULL)
    221       break;
    222     count=ReadBlob(image,(size_t) packet_size*image->columns,pixels);
    223     if (count != (ssize_t) (packet_size*image->columns))
    224       break;
    225     for (x=0; x < (ssize_t) image->columns; x++)
    226     {
    227       index=ConstrainColormapIndex(image,*p,exception);
    228       p++;
    229       if (image->colors > 256)
    230         {
    231           index=ConstrainColormapIndex(image,((size_t) index << 8)+(*p),
    232             exception);
    233           p++;
    234         }
    235       SetPixelIndex(image,index,q);
    236       SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
    237       q+=GetPixelChannels(image);
    238     }
    239     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    240       break;
    241   }
    242   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    243   if (y < (ssize_t) image->rows)
    244     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    245       image->filename);
    246   (void) CloseBlob(image);
    247   return(GetFirstImageInList(image));
    248 }
    249 
    250 /*
    252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    253 %                                                                             %
    254 %                                                                             %
    255 %                                                                             %
    256 %   R e g i s t e r M A P I m a g e                                           %
    257 %                                                                             %
    258 %                                                                             %
    259 %                                                                             %
    260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    261 %
    262 %  RegisterMAPImage() adds attributes for the MAP image format to
    263 %  the list of supported formats.  The attributes include the image format
    264 %  tag, a method to read and/or write the format, whether the format
    265 %  supports the saving of more than one frame to the same file or blob,
    266 %  whether the format supports native in-memory I/O, and a brief
    267 %  description of the format.
    268 %
    269 %  The format of the RegisterMAPImage method is:
    270 %
    271 %      size_t RegisterMAPImage(void)
    272 %
    273 */
    274 ModuleExport size_t RegisterMAPImage(void)
    275 {
    276   MagickInfo
    277     *entry;
    278 
    279   entry=AcquireMagickInfo("MAP","MAP","Colormap intensities and indices");
    280   entry->decoder=(DecodeImageHandler *) ReadMAPImage;
    281   entry->encoder=(EncodeImageHandler *) WriteMAPImage;
    282   entry->flags^=CoderAdjoinFlag;
    283   entry->format_type=ExplicitFormatType;
    284   entry->flags|=CoderRawSupportFlag;
    285   entry->flags|=CoderEndianSupportFlag;
    286   (void) RegisterMagickInfo(entry);
    287   return(MagickImageCoderSignature);
    288 }
    289 
    290 /*
    292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    293 %                                                                             %
    294 %                                                                             %
    295 %                                                                             %
    296 %   U n r e g i s t e r M A P I m a g e                                       %
    297 %                                                                             %
    298 %                                                                             %
    299 %                                                                             %
    300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    301 %
    302 %  UnregisterMAPImage() removes format registrations made by the
    303 %  MAP module from the list of supported formats.
    304 %
    305 %  The format of the UnregisterMAPImage method is:
    306 %
    307 %      UnregisterMAPImage(void)
    308 %
    309 */
    310 ModuleExport void UnregisterMAPImage(void)
    311 {
    312   (void) UnregisterMagickInfo("MAP");
    313 }
    314 
    315 /*
    317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    318 %                                                                             %
    319 %                                                                             %
    320 %                                                                             %
    321 %   W r i t e M A P I m a g e                                                 %
    322 %                                                                             %
    323 %                                                                             %
    324 %                                                                             %
    325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    326 %
    327 %  WriteMAPImage() writes an image to a file as red, green, and blue
    328 %  colormap bytes followed by the colormap indexes.
    329 %
    330 %  The format of the WriteMAPImage method is:
    331 %
    332 %      MagickBooleanType WriteMAPImage(const ImageInfo *image_info,
    333 %        Image *image,ExceptionInfo *exception)
    334 %
    335 %  A description of each parameter follows.
    336 %
    337 %    o image_info: the image info.
    338 %
    339 %    o image:  The image.
    340 %
    341 %    o exception: return any errors or warnings in this structure.
    342 %
    343 */
    344 static MagickBooleanType WriteMAPImage(const ImageInfo *image_info,Image *image,
    345   ExceptionInfo *exception)
    346 {
    347   MagickBooleanType
    348     status;
    349 
    350   register const Quantum
    351     *p;
    352 
    353   register ssize_t
    354     i,
    355     x;
    356 
    357   register unsigned char
    358     *q;
    359 
    360   size_t
    361     depth,
    362     packet_size;
    363 
    364   ssize_t
    365     y;
    366 
    367   unsigned char
    368     *colormap,
    369     *pixels;
    370 
    371   /*
    372     Open output image file.
    373   */
    374   assert(image_info != (const ImageInfo *) NULL);
    375   assert(image_info->signature == MagickCoreSignature);
    376   assert(image != (Image *) NULL);
    377   assert(image->signature == MagickCoreSignature);
    378   if (image->debug != MagickFalse)
    379     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    380   assert(exception != (ExceptionInfo *) NULL);
    381   assert(exception->signature == MagickCoreSignature);
    382   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    383   if (status == MagickFalse)
    384     return(status);
    385   (void) TransformImageColorspace(image,sRGBColorspace,exception);
    386   /*
    387     Allocate colormap.
    388   */
    389   if (IsPaletteImage(image) == MagickFalse)
    390     (void) SetImageType(image,PaletteType,exception);
    391   depth=GetImageQuantumDepth(image,MagickTrue);
    392   packet_size=(size_t) (depth/8);
    393   pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
    394     sizeof(*pixels));
    395   packet_size=(size_t) (image->colors > 256 ? 6UL : 3UL);
    396   colormap=(unsigned char *) AcquireQuantumMemory(image->colors,packet_size*
    397     sizeof(*colormap));
    398   if ((pixels == (unsigned char *) NULL) ||
    399       (colormap == (unsigned char *) NULL))
    400     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    401   /*
    402     Write colormap to file.
    403   */
    404   q=colormap;
    405   if (image->depth <= 8)
    406     for (i=0; i < (ssize_t) image->colors; i++)
    407     {
    408       *q++=(unsigned char) image->colormap[i].red;
    409       *q++=(unsigned char) image->colormap[i].green;
    410       *q++=(unsigned char) image->colormap[i].blue;
    411     }
    412   else
    413     for (i=0; i < (ssize_t) image->colors; i++)
    414     {
    415       *q++=(unsigned char) ((size_t) image->colormap[i].red >> 8);
    416       *q++=(unsigned char) image->colormap[i].red;
    417       *q++=(unsigned char) ((size_t) image->colormap[i].green >> 8);
    418       *q++=(unsigned char) image->colormap[i].green;
    419       *q++=(unsigned char) ((size_t) image->colormap[i].blue >> 8);
    420       *q++=(unsigned char) image->colormap[i].blue;
    421     }
    422   (void) WriteBlob(image,packet_size*image->colors,colormap);
    423   colormap=(unsigned char *) RelinquishMagickMemory(colormap);
    424   /*
    425     Write image pixels to file.
    426   */
    427   for (y=0; y < (ssize_t) image->rows; y++)
    428   {
    429     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    430     if (p == (const Quantum *) NULL)
    431       break;
    432     q=pixels;
    433     for (x=0; x < (ssize_t) image->columns; x++)
    434     {
    435       if (image->colors > 256)
    436         *q++=(unsigned char) ((size_t) GetPixelIndex(image,p) >> 8);
    437       *q++=(unsigned char) GetPixelIndex(image,p);
    438       p+=GetPixelChannels(image);
    439     }
    440     (void) WriteBlob(image,(size_t) (q-pixels),pixels);
    441   }
    442   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    443   (void) CloseBlob(image);
    444   return(status);
    445 }
    446