Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            TTTTT  IIIII  M   M                              %
      7 %                              T      I    MM MM                              %
      8 %                              T      I    M M M                              %
      9 %                              T      I    M   M                              %
     10 %                              T    IIIII  M   M                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                           Read PSX TIM Image 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/blob.h"
     45 #include "MagickCore/blob-private.h"
     46 #include "MagickCore/cache.h"
     47 #include "MagickCore/colormap.h"
     48 #include "MagickCore/exception.h"
     49 #include "MagickCore/exception-private.h"
     50 #include "MagickCore/image.h"
     51 #include "MagickCore/image-private.h"
     52 #include "MagickCore/list.h"
     53 #include "MagickCore/magick.h"
     54 #include "MagickCore/memory_.h"
     55 #include "MagickCore/monitor.h"
     56 #include "MagickCore/monitor-private.h"
     57 #include "MagickCore/pixel-accessor.h"
     58 #include "MagickCore/quantum-private.h"
     59 #include "MagickCore/static.h"
     60 #include "MagickCore/string_.h"
     61 #include "MagickCore/module.h"
     62 
     63 /*
     65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     66 %                                                                             %
     67 %                                                                             %
     68 %                                                                             %
     69 %  R e a d T I M I m a g e                                                    %
     70 %                                                                             %
     71 %                                                                             %
     72 %                                                                             %
     73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     74 %
     75 %  ReadTIMImage() reads a PSX TIM image file and returns it.  It
     76 %  allocates the memory necessary for the new Image structure and returns a
     77 %  pointer to the new image.
     78 %
     79 %  Contributed by os (at) scee.sony.co.uk.
     80 %
     81 %  The format of the ReadTIMImage method is:
     82 %
     83 %      Image *ReadTIMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     84 %
     85 %  A description of each parameter follows:
     86 %
     87 %    o image_info: the image info.
     88 %
     89 %    o exception: return any errors or warnings in this structure.
     90 %
     91 */
     92 static Image *ReadTIMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     93 {
     94   typedef struct _TIMInfo
     95   {
     96     size_t
     97       id,
     98       flag;
     99   } TIMInfo;
    100 
    101   TIMInfo
    102     tim_info;
    103 
    104   Image
    105     *image;
    106 
    107   int
    108     bits_per_pixel,
    109     has_clut;
    110 
    111   MagickBooleanType
    112     status;
    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     bytes_per_line,
    128     height,
    129     image_size,
    130     pixel_mode,
    131     width;
    132 
    133   ssize_t
    134     count,
    135     y;
    136 
    137   unsigned char
    138     *tim_data,
    139     *tim_pixels;
    140 
    141   unsigned short
    142     word;
    143 
    144   /*
    145     Open image file.
    146   */
    147   assert(image_info != (const ImageInfo *) NULL);
    148   assert(image_info->signature == MagickCoreSignature);
    149   if (image_info->debug != MagickFalse)
    150     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    151       image_info->filename);
    152   assert(exception != (ExceptionInfo *) NULL);
    153   assert(exception->signature == MagickCoreSignature);
    154   image=AcquireImage(image_info,exception);
    155   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    156   if (status == MagickFalse)
    157     {
    158       image=DestroyImageList(image);
    159       return((Image *) NULL);
    160     }
    161   /*
    162     Determine if this a TIM file.
    163   */
    164   tim_info.id=ReadBlobLSBLong(image);
    165   do
    166   {
    167     /*
    168       Verify TIM identifier.
    169     */
    170     if (tim_info.id != 0x00000010)
    171       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    172     tim_info.flag=ReadBlobLSBLong(image);
    173     has_clut=tim_info.flag & (1 << 3) ? 1 : 0;
    174     pixel_mode=tim_info.flag & 0x07;
    175     switch ((int) pixel_mode)
    176     {
    177       case 0: bits_per_pixel=4; break;
    178       case 1: bits_per_pixel=8; break;
    179       case 2: bits_per_pixel=16; break;
    180       case 3: bits_per_pixel=24; break;
    181       default: bits_per_pixel=4; break;
    182     }
    183     image->depth=8;
    184     if (has_clut)
    185       {
    186         unsigned char
    187           *tim_colormap;
    188 
    189         /*
    190           Read TIM raster colormap.
    191         */
    192         (void)ReadBlobLSBLong(image);
    193         (void)ReadBlobLSBShort(image);
    194         (void)ReadBlobLSBShort(image);
    195         width=ReadBlobLSBShort(image);
    196         height=ReadBlobLSBShort(image);
    197         image->columns=width;
    198         image->rows=height;
    199         if (AcquireImageColormap(image,pixel_mode == 1 ? 256UL : 16UL,exception) == MagickFalse)
    200           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    201         tim_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
    202           2UL*sizeof(*tim_colormap));
    203         if (tim_colormap == (unsigned char *) NULL)
    204           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    205         count=ReadBlob(image,2*image->colors,tim_colormap);
    206         if (count != (ssize_t) (2*image->colors))
    207           ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    208         p=tim_colormap;
    209         for (i=0; i < (ssize_t) image->colors; i++)
    210         {
    211           word=(*p++);
    212           word|=(unsigned short) (*p++ << 8);
    213           image->colormap[i].blue=ScaleCharToQuantum(
    214             ScaleColor5to8(1UL*(word >> 10) & 0x1f));
    215           image->colormap[i].green=ScaleCharToQuantum(
    216             ScaleColor5to8(1UL*(word >> 5) & 0x1f));
    217           image->colormap[i].red=ScaleCharToQuantum(
    218             ScaleColor5to8(1UL*word & 0x1f));
    219         }
    220         tim_colormap=(unsigned char *) RelinquishMagickMemory(tim_colormap);
    221       }
    222     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
    223       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    224         break;
    225     status=SetImageExtent(image,image->columns,image->rows,exception);
    226     if (status == MagickFalse)
    227       return(DestroyImageList(image));
    228     /*
    229       Read image data.
    230     */
    231     (void) ReadBlobLSBLong(image);
    232     (void) ReadBlobLSBShort(image);
    233     (void) ReadBlobLSBShort(image);
    234     width=ReadBlobLSBShort(image);
    235     height=ReadBlobLSBShort(image);
    236     image_size=2*width*height;
    237     bytes_per_line=width*2;
    238     width=(width*16)/bits_per_pixel;
    239     tim_data=(unsigned char *) AcquireQuantumMemory(image_size,
    240       sizeof(*tim_data));
    241     if (tim_data == (unsigned char *) NULL)
    242       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    243     count=ReadBlob(image,image_size,tim_data);
    244     if (count != (ssize_t) (image_size))
    245       ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
    246     tim_pixels=tim_data;
    247     /*
    248       Initialize image structure.
    249     */
    250     image->columns=width;
    251     image->rows=height;
    252     /*
    253       Convert TIM raster image to pixel packets.
    254     */
    255     switch (bits_per_pixel)
    256     {
    257       case 4:
    258       {
    259         /*
    260           Convert PseudoColor scanline.
    261         */
    262         for (y=(ssize_t) image->rows-1; y >= 0; y--)
    263         {
    264           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    265           if (q == (Quantum *) NULL)
    266             break;
    267           p=tim_pixels+y*bytes_per_line;
    268           for (x=0; x < ((ssize_t) image->columns-1); x+=2)
    269           {
    270             SetPixelIndex(image,(*p) & 0x0f,q);
    271             q+=GetPixelChannels(image);
    272             SetPixelIndex(image,(*p >> 4) & 0x0f,q);
    273             p++;
    274             q+=GetPixelChannels(image);
    275           }
    276           if ((image->columns % 2) != 0)
    277             {
    278               SetPixelIndex(image,(*p >> 4) & 0x0f,q);
    279               p++;
    280               q+=GetPixelChannels(image);
    281             }
    282           if (SyncAuthenticPixels(image,exception) == MagickFalse)
    283             break;
    284           if (image->previous == (Image *) NULL)
    285             {
    286               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    287                 image->rows);
    288               if (status == MagickFalse)
    289                 break;
    290             }
    291         }
    292         break;
    293       }
    294       case 8:
    295       {
    296         /*
    297           Convert PseudoColor scanline.
    298         */
    299         for (y=(ssize_t) image->rows-1; y >= 0; y--)
    300         {
    301           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    302           if (q == (Quantum *) NULL)
    303             break;
    304           p=tim_pixels+y*bytes_per_line;
    305           for (x=0; x < (ssize_t) image->columns; x++)
    306           {
    307             SetPixelIndex(image,*p++,q);
    308             q+=GetPixelChannels(image);
    309           }
    310           if (SyncAuthenticPixels(image,exception) == MagickFalse)
    311             break;
    312           if (image->previous == (Image *) NULL)
    313             {
    314               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    315                 image->rows);
    316               if (status == MagickFalse)
    317                 break;
    318             }
    319         }
    320         break;
    321       }
    322       case 16:
    323       {
    324         /*
    325           Convert DirectColor scanline.
    326         */
    327         for (y=(ssize_t) image->rows-1; y >= 0; y--)
    328         {
    329           p=tim_pixels+y*bytes_per_line;
    330           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    331           if (q == (Quantum *) NULL)
    332             break;
    333           for (x=0; x < (ssize_t) image->columns; x++)
    334           {
    335             word=(*p++);
    336             word|=(*p++ << 8);
    337             SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
    338               (1UL*word >> 10) & 0x1f)),q);
    339             SetPixelGreen(image,ScaleCharToQuantum(ScaleColor5to8(
    340               (1UL*word >> 5) & 0x1f)),q);
    341             SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
    342               (1UL*word >> 0) & 0x1f)),q);
    343             q+=GetPixelChannels(image);
    344           }
    345           if (SyncAuthenticPixels(image,exception) == MagickFalse)
    346             break;
    347           if (image->previous == (Image *) NULL)
    348             {
    349               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    350                 image->rows);
    351               if (status == MagickFalse)
    352                 break;
    353             }
    354         }
    355         break;
    356       }
    357       case 24:
    358       {
    359         /*
    360           Convert DirectColor scanline.
    361         */
    362         for (y=(ssize_t) image->rows-1; y >= 0; y--)
    363         {
    364           p=tim_pixels+y*bytes_per_line;
    365           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    366           if (q == (Quantum *) NULL)
    367             break;
    368           for (x=0; x < (ssize_t) image->columns; x++)
    369           {
    370             SetPixelRed(image,ScaleCharToQuantum(*p++),q);
    371             SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
    372             SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
    373             q+=GetPixelChannels(image);
    374           }
    375           if (SyncAuthenticPixels(image,exception) == MagickFalse)
    376             break;
    377           if (image->previous == (Image *) NULL)
    378             {
    379               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    380                 image->rows);
    381               if (status == MagickFalse)
    382                 break;
    383             }
    384         }
    385         break;
    386       }
    387       default:
    388         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    389     }
    390     if (image->storage_class == PseudoClass)
    391       (void) SyncImage(image,exception);
    392     tim_pixels=(unsigned char *) RelinquishMagickMemory(tim_pixels);
    393     if (EOFBlob(image) != MagickFalse)
    394       {
    395         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    396           image->filename);
    397         break;
    398       }
    399     /*
    400       Proceed to next image.
    401     */
    402     tim_info.id=ReadBlobLSBLong(image);
    403     if (tim_info.id == 0x00000010)
    404       {
    405         /*
    406           Allocate next image structure.
    407         */
    408         AcquireNextImage(image_info,image,exception);
    409         if (GetNextImageInList(image) == (Image *) NULL)
    410           {
    411             image=DestroyImageList(image);
    412             return((Image *) NULL);
    413           }
    414         image=SyncNextImageInList(image);
    415         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
    416           GetBlobSize(image));
    417         if (status == MagickFalse)
    418           break;
    419       }
    420   } while (tim_info.id == 0x00000010);
    421   (void) CloseBlob(image);
    422   return(GetFirstImageInList(image));
    423 }
    424 
    425 /*
    427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    428 %                                                                             %
    429 %                                                                             %
    430 %                                                                             %
    431 %   R e g i s t e r T I M I m a g e                                           %
    432 %                                                                             %
    433 %                                                                             %
    434 %                                                                             %
    435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    436 %
    437 %  RegisterTIMImage() adds attributes for the TIM image format to
    438 %  the list of supported formats.  The attributes include the image format
    439 %  tag, a method to read and/or write the format, whether the format
    440 %  supports the saving of more than one frame to the same file or blob,
    441 %  whether the format supports native in-memory I/O, and a brief
    442 %  description of the format.
    443 %
    444 %  The format of the RegisterTIMImage method is:
    445 %
    446 %      size_t RegisterTIMImage(void)
    447 %
    448 */
    449 ModuleExport size_t RegisterTIMImage(void)
    450 {
    451   MagickInfo
    452     *entry;
    453 
    454   entry=AcquireMagickInfo("TIM","TIM","PSX TIM");
    455   entry->decoder=(DecodeImageHandler *) ReadTIMImage;
    456   (void) RegisterMagickInfo(entry);
    457   return(MagickImageCoderSignature);
    458 }
    459 
    460 /*
    462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    463 %                                                                             %
    464 %                                                                             %
    465 %                                                                             %
    466 %   U n r e g i s t e r T I M I m a g e                                       %
    467 %                                                                             %
    468 %                                                                             %
    469 %                                                                             %
    470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    471 %
    472 %  UnregisterTIMImage() removes format registrations made by the
    473 %  TIM module from the list of supported formats.
    474 %
    475 %  The format of the UnregisterTIMImage method is:
    476 %
    477 %      UnregisterTIMImage(void)
    478 %
    479 */
    480 ModuleExport void UnregisterTIMImage(void)
    481 {
    482   (void) UnregisterMagickInfo("TIM");
    483 }
    484