]> granicus.if.org Git - imagemagick/commitdiff
Implementation of a TIM2 coder (#1571)
authorRamiro Balado <baladoramiro+github@gmail.com>
Sat, 13 Jul 2019 13:25:38 +0000 (15:25 +0200)
committerImageMagick <urban-warrior@users.noreply.github.com>
Sat, 13 Jul 2019 13:25:38 +0000 (09:25 -0400)
* Added ScaleColor4to8 and converse functions

* Implementation mostly done

* Build setup

* reordered processing of clut and pixels

* Added support for Shuffled CLUTs

* Revert "Added ScaleColor4to8 and converse functions"

This reverts commit b0bd8a59ccd775fb17fc3d1db312806bf6146d93.

* Added more exceptions thrown when header is incorrect

* created enums and compacted rgb read functions

* Added alpha channel and changed alpha scaling

* Added support for format_type==1

* New define for assigning clut colors

* Changed names to avoid namespace conflicts

* Fixed alpha channel of RGB24 encoding

* Incorporated sanity check into the switch

MagickCore/static.h
coders/Make.com
coders/Makefile.am
coders/coders-list.h
coders/coders.h
coders/tim2.c [new file with mode: 0644]
coders/tim2.h [new file with mode: 0644]
tests/validate.h

index ebd17674538a24faa3f8ce6be653341db3ebad58..c07449c9b7f3ef0c6d0d7d61ee49e6bd190992fb 100644 (file)
@@ -169,6 +169,7 @@ extern ModuleExport size_t
   RegisterTIFFImage(void),
   RegisterTILEImage(void),
   RegisterTIMImage(void),
+  RegisterTIM2Image(void),
   RegisterTTFImage(void),
   RegisterTXTImage(void),
   RegisterUILImage(void),
@@ -334,6 +335,7 @@ extern ModuleExport void
   UnregisterTIFFImage(void),
   UnregisterTILEImage(void),
   UnregisterTIMImage(void),
+  UnregisterTIM2Image(void),
   UnregisterTTFImage(void),
   UnregisterTXTImage(void),
   UnregisterUILImage(void),
index 62421209a53178f87d9613d69e6aa42a7a6c4b1b..9bc596702ee1a199a539df94bbb31a84cbb4f370 100755 (executable)
@@ -121,6 +121,7 @@ $call Make thumbnail.c
 $call Make tiff.c
 $call Make tile.c
 $call Make tim.c
+$call Make tim2.c
 $call Make ttf.c
 $call Make txt.c
 $call Make uil.c
@@ -155,7 +156,7 @@ $library/create libCoders.olb aai,art,avs,bgr,bmp,braille,clip,clipboard,cip, -
   jnx,json,hdr,label,cals,caption,palm,mac,magick,map,mat,matte,pango,rgf, -
   meta,miff,mpc,mpr,msl,mpeg,mono,mtv,mvg,null,otb,pattern,pcd,pcl,pcx,pdb, -
   pdf,pes,pict,pix,plasma,png,pnm,preview,ps,ps2,ps3,psd,pwp,raw,rgb,rla,rle, -
-  sct,sfw,sgi,stegano,sun,svg,tga,thumbnail,tiff,tile,tim,ttf,txt,uil,url, -
+  sct,sfw,sgi,stegano,sun,svg,tga,thumbnail,tiff,tile,tim,tim2,ttf,txt,uil,url, -
   uyvy,vicar,vid,viff,wbmp,webp,wmf,wpg,x,xbm,xc,xcf,xpm,xps,xwd,ycbcr,yuv, -
   mask,screenshot,vips,sixel,xtrn, -
   cin,magick,scr,[-.magickcore]compress,[-.magickcore]prervicccm
index 0a72efa5edc44739a7e2db2d9e2a5943c0532760..b71e33675d026b731474795d679948d114c6d39b 100644 (file)
@@ -190,6 +190,7 @@ MAGICKCORE_CODER_SRCS = \
        coders/thumbnail.c \
        coders/tile.c \
        coders/tim.c \
+       coders/tim2.c \
        coders/ttf.c \
        coders/txt.c \
        coders/uil.c \
@@ -338,6 +339,7 @@ CODERS_NOINST_HDRS = \
        coders/tiff.h \
        coders/tile.h \
        coders/tim.h \
+       coders/tim2.h \
        coders/ttf.h \
        coders/txt.h \
        coders/uil.h \
@@ -455,6 +457,7 @@ coders_LTLIBRARIES = \
        coders/thumbnail.la \
        coders/tile.la \
        coders/tim.la \
+       coders/tim2.la \
        coders/ttf.la \
        coders/txt.la \
        coders/uil.la \
@@ -1123,6 +1126,12 @@ coders_tim_la_CPPFLAGS     = $(MAGICK_CODER_CPPFLAGS)
 coders_tim_la_LDFLAGS      = $(MODULECOMMONFLAGS)
 coders_tim_la_LIBADD       = $(MAGICKCORE_LIBS)
 
+# TIM2 coder module
+coders_tim2_la_SOURCES      = coders/tim2.c
+coders_tim2_la_CPPFLAGS     = $(MAGICK_CODER_CPPFLAGS)
+coders_tim2_la_LDFLAGS      = $(MODULECOMMONFLAGS)
+coders_tim2_la_LIBADD       = $(MAGICKCORE_LIBS)
+
 # TTF coder module
 coders_ttf_la_SOURCES      = coders/ttf.c
 coders_ttf_la_CPPFLAGS     = $(MAGICK_CODER_CPPFLAGS)
index b005230c176c18f6e8425521150da9074f142705..68086d300ac82f48f53ffe635f72d757aa90c20d 100644 (file)
@@ -150,6 +150,7 @@ AddMagickCoder(THUMBNAIL)
 #endif
 AddMagickCoder(TILE)
 AddMagickCoder(TIM)
+AddMagickCoder(TIM2)
 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
   AddMagickCoder(TTF)
 #endif
index 45c44ba9bba40083b5fac8ba16cebe99e3a19212..c93350f480ec2e5735592b1cb9d05ba10d08d18a 100644 (file)
 #endif
 #include "coders/tile.h"
 #include "coders/tim.h"
+#include "coders/tim2.h"
 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
   #include "coders/ttf.h"
 #endif
diff --git a/coders/tim2.c b/coders/tim2.c
new file mode 100644 (file)
index 0000000..df19874
--- /dev/null
@@ -0,0 +1,746 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                          TTTTT  IIIII  M   M   222                          %
+%                            T      I    MM MM  2   2                         %
+%                            T      I    M M M     2                          %
+%                            T      I    M   M    2                           %
+%                            T    IIIII  M   M  22222                         %
+%                                                                             %
+%                                                                             %
+%                          Read PSX TIM2 Image Format                         %
+%                                                                             %
+%                               Software Design                               %
+%                             Ramiro Balado Ordax                             %
+%                                   May 2019                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 2019-2019 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    https://imagemagick.org/script/license.php                               %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+\f
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/channel.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/static.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/module.h"
+\f
+/*
+ Typedef declarations
+*/
+typedef struct _TIM2FileHeader
+{
+  uint32_t
+    magic_num;
+  uint8_t
+    format_vers,
+    format_type;
+  uint16_t
+    image_count;
+  char
+    reserved[8];
+} TIM2FileHeader;
+
+typedef struct _TIM2ImageHeader
+{
+  uint32_t
+    total_size,
+    clut_size,
+    image_size;
+  uint16_t
+    header_size,
+    clut_color_count;
+  uint8_t
+    img_format,
+    mipmap_count,
+    clut_type,
+    bpp_type;
+  uint16_t
+    width,
+    height;
+  uint64_t
+    GsTex0,
+    GsTex1;
+  uint32_t
+    GsRegs,
+    GsTexClut;
+} TIM2ImageHeader;
+
+enum CSM {
+  CSM1=0,
+  CSM2=1,
+};
+
+enum TIM2ColorEncoding{
+  RGBA32=0,
+  RGB24=1,
+  RGBA16=2,
+};
+enum TIM2IndexEncoding{
+  IDTEX8=3,
+  IDTEX4=4,
+};
+\f
+/*
+  Static functions
+*/
+static inline TIM2ImageHeader ReadTIM2ImageHeader(Image *image)
+{
+  TIM2ImageHeader
+    tim2_image_header;
+
+  tim2_image_header.total_size =ReadBlobLSBLong(image);
+  tim2_image_header.clut_size  =ReadBlobLSBLong(image);
+  tim2_image_header.image_size =ReadBlobLSBLong(image);
+  tim2_image_header.header_size=ReadBlobLSBShort(image);
+
+  tim2_image_header.clut_color_count=ReadBlobLSBShort(image);
+  tim2_image_header.img_format  =ReadBlobByte(image);
+  tim2_image_header.mipmap_count=ReadBlobByte(image);
+  tim2_image_header.clut_type   =ReadBlobByte(image);
+  tim2_image_header.bpp_type    =ReadBlobByte(image);
+
+  tim2_image_header.width =ReadBlobLSBShort(image);
+  tim2_image_header.height=ReadBlobLSBShort(image);
+
+  tim2_image_header.GsTex0=ReadBlobMSBLongLong(image);
+  tim2_image_header.GsTex1=ReadBlobMSBLongLong(image);
+  tim2_image_header.GsRegs   =ReadBlobMSBLong(image);
+  tim2_image_header.GsTexClut=ReadBlobMSBLong(image);
+
+  return tim2_image_header;
+}
+
+static inline Quantum GetChannelValue(uint32_t word,uint8_t channel, enum TIM2ColorEncoding ce){
+  switch(ce)
+  {
+    case RGBA16:
+      // Documentation specifies padding with zeros for converting from 5 to 8 bits.
+      return ScaleCharToQuantum((word>>channel*5 & ~(~0x0<<5))<<3);
+    case RGB24:
+    case RGBA32:
+      return ScaleCharToQuantum(word>>channel*8 & ~(~0x0<<8));
+    default:
+      return -1;
+  }
+}
+
+static inline Quantum GetAlpha(uint32_t word, enum TIM2ColorEncoding ce){
+  switch(ce)
+  {
+    case RGBA16:
+      return ScaleCharToQuantum((word>>3*5&0x1F)==0?0:0xFF);
+    case RGBA32:
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)? a:b)
+#endif
+      // 0x80 -> 1.0 alpha. Multiply by 2 and clamp to 0xFF
+      return ScaleCharToQuantum(MIN((word>>3*8&0xFF)<<1,0xFF));
+    default:
+      return 0xFF;
+  }
+}
+
+static inline void deshufflePalette(Image *image,PixelInfo* oldColormap){
+  const uint8_t
+    pages=image->colors/32,//Pages per CLUT
+    blocks=4,//Blocks per page
+    colors=8;//Colors per block
+  size_t
+    i=0;
+
+  (void) memcpy(oldColormap,image->colormap,(size_t)image->colors*sizeof(*oldColormap));
+
+  /*
+   * Swap the 2nd and 3rd block in each page
+   */
+  for(int page=0; page<pages; page++){
+    memcpy(&(image->colormap[i+1*colors]),&(oldColormap[i+2*colors]),colors*sizeof(PixelInfo));
+    memcpy(&(image->colormap[i+2*colors]),&(oldColormap[i+1*colors]),colors*sizeof(PixelInfo));
+
+    i+=blocks*colors;
+  }
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  R e a d T I M 2 I m a g e                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadTIM2Image() reads a PS2 TIM image file and returns it.  It
+%  allocates the memory necessary for the new Image structure and returns a
+%  pointer to the new image.
+%
+%  The format of the ReadTIM2Image method is:
+%
+%      Image *ReadTIM2Image(const ImageInfo *image_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static Image *ReadTIM2Image(const ImageInfo *image_info, ExceptionInfo *exception)
+{
+  TIM2FileHeader
+    tim2_file_header;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+
+  ssize_t
+    count,
+    str_read;
+
+  /*
+   * Open image file.
+   */
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickCoreSignature);
+
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickCoreSignature);
+  image=AcquireImage(image_info,exception);
+  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
+  if (status == MagickFalse)
+    {
+      image=DestroyImageList(image);
+      return((Image *) NULL);
+    }
+  /*
+   * Verify TIM2 magic number.
+   */
+  tim2_file_header.magic_num=ReadBlobMSBLong(image);
+  if (tim2_file_header.magic_num != 0x54494D32) /*"TIM2"*/
+    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+
+  /*
+   * #### Read File Header ####
+   */
+  tim2_file_header.format_vers=ReadBlobByte(image);
+  if(tim2_file_header.format_vers!=0x04)
+    ThrowReaderException(CoderError,"ImageTypeNotSupported");
+
+  tim2_file_header.format_type=ReadBlobByte(image);
+  tim2_file_header.image_count=ReadBlobLSBShort(image);
+  ReadBlobStream(image,8,&(tim2_file_header.reserved),&str_read);
+
+
+  /*
+   * Jump to first image header
+   */
+  switch(tim2_file_header.format_type)
+  {
+    case 0x00:
+      SeekBlob(image,16,SEEK_SET);break;
+    case 0x01:
+      SeekBlob(image,128,SEEK_SET);break;
+    default:
+      ThrowReaderException(CoderError,"ImageTypeNotSupported");
+  }
+
+  /*
+   * Process each image. Only one image supported for now
+   */
+  if(tim2_file_header.image_count!=1)
+    ThrowReaderException(CoderError,"NumberOfImagesIsNotSupported");
+
+  for(int i=0;i<tim2_file_header.image_count;++i)
+  {
+    TIM2ImageHeader
+      tim2_image_header;
+
+    MagickOffsetType ImgDataOffset=TellBlob(image);
+
+    enum CSM csm;
+
+    char
+      clut_depth=0,
+      has_clut=0,
+      bits_per_pixel=0;
+
+    /*
+     * #### Read Image Header ####
+     */
+    tim2_image_header=ReadTIM2ImageHeader(image);
+
+    /*
+     * ### Process Image Header ###
+     */
+
+    if(tim2_image_header.mipmap_count!=1)
+      ThrowReaderException(CoderError,"NumberOfImagesIsNotSupported");
+
+    image->columns=tim2_image_header.width;
+    image->rows=tim2_image_header.height;
+
+    has_clut=tim2_image_header.clut_type!=0;
+    if(has_clut){
+      
+      // CLUT bits per color
+      switch((int) tim2_image_header.clut_type&0x0F)//Low 4 bits
+      {
+        case 1: clut_depth=16;break;
+        case 2: clut_depth=24;break;
+        case 3: clut_depth=32;break;
+        default:
+          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+          break;
+      }
+    }
+
+    // Bits per pixel.
+    switch ((int) tim2_image_header.bpp_type)
+    {
+      case 1: bits_per_pixel=16;break;
+      case 2: bits_per_pixel=24;break;
+      case 3: bits_per_pixel=32;break;
+      case 4: bits_per_pixel=4;break;// Implies CLUT
+      case 5: bits_per_pixel=8;break;// Implies CLUT
+      default:
+        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+        break;
+    }
+
+    image->depth=has_clut?clut_depth:bits_per_pixel;
+    if(image->depth==16 || image->depth==32)
+      SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
+    else
+      SetImageAlphaChannel(image,OffAlphaChannel,exception);
+
+    SeekBlob(image,ImgDataOffset,SEEK_SET);
+    SeekBlob(image,tim2_image_header.header_size,SEEK_CUR);
+
+
+    {
+      /*
+       * ### Read Image Data ###
+       */
+      unsigned char
+        *tim2_image_data;
+      size_t
+        bits_per_line,
+        bytes_per_line,
+        y;
+
+      register ssize_t
+        x;
+
+      register Quantum
+        *q;
+      register unsigned char
+        *p;
+
+      tim2_image_data=(unsigned char*) AcquireMagickMemory(tim2_image_header.image_size);
+      if (tim2_image_data == (unsigned char *) NULL)
+        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+      count=ReadBlob(image,tim2_image_header.image_size,tim2_image_data);
+      if (count!=(ssize_t)tim2_image_header.image_size)
+      {
+        tim2_image_data=(unsigned char *) RelinquishMagickMemory(tim2_image_data);
+        ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
+      }
+      
+
+      /*
+       * ### Process Image Data ###
+       */
+      status=SetImageExtent(image,image->columns,image->rows,exception);
+      if (status == MagickFalse)
+        return(DestroyImageList(image));
+      status=ResetImagePixels(image,exception);
+      if (status == MagickFalse)
+        return(DestroyImageList(image));
+
+      p=tim2_image_data;
+      bits_per_line=image->columns*bits_per_pixel;
+      bytes_per_line=bits_per_line/8 + ((bits_per_line%8==0)?0:1);
+
+      if(has_clut)
+      {
+#define SyncNewPixels(image,exception,y) \
+if(SyncAuthenticPixels(image,exception) == MagickFalse) break; \
+if(image->previous == (Image *) NULL) \
+{ \
+  status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows); \
+  if(status == MagickFalse) break; \
+}
+
+        image->colors=tim2_image_header.clut_color_count;
+        if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
+          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+
+        switch (bits_per_pixel)
+        {
+          case 4:
+          {
+            for (y=0; y<(ssize_t) image->rows; y++)
+            {
+              q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              p=tim2_image_data+y*bytes_per_line;
+              for (x=0; x < ((ssize_t) image->columns-1); x+=2)
+              {
+                SetPixelIndex(image,(*p >> 0) & 0x0F,q);
+                q+=GetPixelChannels(image);
+                SetPixelIndex(image,(*p >> 4) & 0x0F,q);
+                p++;
+                q+=GetPixelChannels(image);
+              }
+              if ((image->columns % 2) != 0)
+              {
+                SetPixelIndex(image,(*p >> 4) & 0x0F,q);
+                p++;
+                q+=GetPixelChannels(image);
+              }
+              SyncNewPixels(image,exception,y);
+            }
+            break;
+          }
+
+          case 8:
+          {
+            for (y=0;y<(ssize_t) image->rows; y++)
+            {
+              q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              p=tim2_image_data+y*bytes_per_line;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                SetPixelIndex(image,*p,q);
+                p++;
+                q+=GetPixelChannels(image);
+              }
+              SyncNewPixels(image,exception,y);
+            }
+            break;
+          }
+        }
+      }
+      else //has_clut==false
+      {
+
+#define SetPixelAllChannels(image,word,q,enc) \
+SetPixelRed  (image,GetChannelValue(word,0,enc),q); \
+SetPixelGreen(image,GetChannelValue(word,1,enc),q); \
+SetPixelBlue (image,GetChannelValue(word,2,enc),q);
+
+        uint32_t word;
+        switch (bits_per_pixel)
+        {
+          case 16:
+          {
+            for (y=0; y<(ssize_t) image->rows; y++)
+            {
+              p=tim2_image_data+y*bytes_per_line;
+              q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                word = ((uint32_t)* p   )<<0*8 |
+                       ((uint32_t)*(p+1))<<1*8;
+
+                SetPixelAllChannels(image,word,q,RGBA16);
+                SetPixelAlpha(image,GetAlpha(word,RGBA16),q);
+                q+=GetPixelChannels(image);
+                p+=sizeof(uint16_t);
+              }
+              SyncNewPixels(image,exception,y);
+            }
+            break;
+          }
+
+          case 24:
+          {
+            for (y = 0; y<(ssize_t) image->rows; y++)
+            {
+              p=tim2_image_data+y*bytes_per_line;
+              q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                word = (uint32_t)(* p   )<<0*8 |
+                       (uint32_t)(*(p+1))<<1*8 |
+                       (uint32_t)(*(p+2))<<2*8;
+
+                SetPixelAllChannels(image,word,q,RGB24);
+                q+=GetPixelChannels(image);
+                p+=3;
+              }
+              SyncNewPixels(image,exception,y);
+            }
+            break;
+          }
+
+          case 32:
+          {  
+            for (y = 0; y<(ssize_t) image->rows; y++)
+            {
+              p=tim2_image_data+y*bytes_per_line;
+              q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                word = ((uint32_t)* p   )<<0*8 |
+                       ((uint32_t)*(p+1))<<1*8 |
+                       ((uint32_t)*(p+2))<<2*8 |
+                       ((uint32_t)*(p+3))<<3*8;
+
+                SetPixelAllChannels(image,word,q,RGBA32);
+                SetPixelAlpha(image,GetAlpha(word,RGBA32),q);
+                q+=GetPixelChannels(image);
+                p+=4;
+              }
+              SyncNewPixels(image,exception,y);
+            }
+            break;
+          }
+
+          default:
+          {
+            tim2_image_data=(unsigned char *) RelinquishMagickMemory(tim2_image_data);
+            ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+          }
+        }
+      }
+
+      tim2_image_data=(unsigned char *) RelinquishMagickMemory(tim2_image_data);
+    }
+
+    if (has_clut)
+    {
+
+      /*
+       * ### Read CLUT Data ###
+       */
+
+      unsigned char
+        *tim2_clut_data;
+      register unsigned char
+        *p;
+
+      tim2_clut_data=(unsigned char *) AcquireMagickMemory(tim2_image_header.clut_size);
+      if (tim2_clut_data == (unsigned char *) NULL)
+        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+
+      count=ReadBlob(image,tim2_image_header.clut_size,tim2_clut_data);
+      if (count != (ssize_t) (tim2_image_header.clut_size))
+        {
+          tim2_clut_data=(unsigned char *) RelinquishMagickMemory(tim2_clut_data);
+          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
+        }
+        
+      /*
+       * ### Process CLUT Data ###
+       */
+      {
+      uint32_t word;
+      p=tim2_clut_data;
+#define AssignAllChannels(image,word,enc) \
+image->colormap[i].red  =GetChannelValue(word,0,enc);\
+image->colormap[i].green=GetChannelValue(word,1,enc);\
+image->colormap[i].blue =GetChannelValue(word,2,enc);
+      switch(clut_depth)
+      {
+        case 16:
+        {
+          for (i=0;i<(ssize_t)image->colors;i++){
+            word = ((uint16_t)* p   )<<0*8 |
+                   ((uint16_t)*(p+1))<<1*8;
+
+            AssignAllChannels(image,word,RGBA16);
+            image->colormap[i].alpha=GetAlpha(word,16);
+            p+=2;
+          }
+          break;
+        }
+
+        case 24:
+        {
+          for (i=0;i<(ssize_t)image->colors;i++){
+            word = ((uint32_t)* p   )<<0*8 |
+                   ((uint32_t)*(p+1))<<1*8 |
+                   ((uint32_t)*(p+2))<<2*8;
+
+            AssignAllChannels(image,word,RGB24);
+            p+=3;
+          }
+          break;
+        }
+
+        case 32:
+        {
+          for (i=0;i<(ssize_t)image->colors;i++){
+            word = ((uint32_t)* p   )<<0*8 |
+                   ((uint32_t)*(p+1))<<1*8 |
+                   ((uint32_t)*(p+2))<<2*8 |
+                   ((uint32_t)*(p+3))<<3*8;
+           
+            AssignAllChannels(image,word,RGBA32);
+            image->colormap[i].alpha=GetAlpha(word,RGBA32);
+            p+=4;
+          }
+          break;
+        }
+      }
+      }
+      tim2_clut_data=(unsigned char *) RelinquishMagickMemory(tim2_clut_data);
+
+      //CSM: CLUT Storage Mode
+      switch ((int) tim2_image_header.clut_type>>4)//High 4 bits
+      {
+        case 0: csm=CSM1;break;
+        case 1: csm=CSM2;break;
+        default:
+          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+          break;
+      }
+
+      if(csm==CSM1){
+        PixelInfo *oldColormap=(PixelInfo *)AcquireQuantumMemory((size_t)(image->colors)+1,sizeof(*image->colormap));
+        if (oldColormap == (PixelInfo *) NULL)
+          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+
+        deshufflePalette(image,oldColormap);
+        RelinquishMagickMemory(oldColormap);
+      }
+    }
+
+    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
+      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
+        break;
+
+
+    if (image->storage_class == PseudoClass)
+    if (EOFBlob(image) != MagickFalse)
+    {
+      ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
+        image->filename);
+      break;
+    }
+    /*
+      Proceed to next image.
+    */
+    if (image_info->number_scenes != 0)
+      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
+        break;
+  }
+  
+  (void) CloseBlob(image);
+  if (status == MagickFalse)
+    return(DestroyImageList(image));
+  return(GetFirstImageInList(image));
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e g i s t e r T I M 2 I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RegisterTIM2Image() adds attributes for the TIM2 image format to
+%  the list of supported formats.  The attributes include the image format
+%  tag, a method to read and/or write the format, whether the format
+%  supports the saving of more than one frame to the same file or blob,
+%  whether the format supports native in-memory I/O, and a brief
+%  description of the format.
+%
+%  The format of the RegisterTIM2Image method is:
+%
+%      size_t RegisterTIM2Image(void)
+%
+*/
+ModuleExport size_t RegisterTIM2Image(void)
+{
+  MagickInfo
+    *entry;
+
+  entry=AcquireMagickInfo("TIM2","TM2","PS2 TIM2");
+  entry->decoder=(DecodeImageHandler *) ReadTIM2Image;
+  (void) RegisterMagickInfo(entry);
+  return(MagickImageCoderSignature);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   U n r e g i s t e r T I M 2 I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnregisterTIM2Image() removes format registrations made by the
+%  TIM2 module from the list of supported formats.
+%
+%  The format of the UnregisterTIM2Image method is:
+%
+%      UnregisterTIM2Image(void)
+%
+*/
+ModuleExport void UnregisterTIM2Image(void)
+{
+  (void) UnregisterMagickInfo("TM2");
+}
diff --git a/coders/tim2.h b/coders/tim2.h
new file mode 100644 (file)
index 0000000..7a76b93
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.  You may
+  obtain a copy of the License at
+  
+    https://imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+#include "coders/coders-private.h"
+
+#define MagickTIM2Headers
+
+#define MagickTIM2Aliases \
+  MagickCoderAlias("TIM2","TM2")
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+MagickCoderExports(TIM2)
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
index 3803f4333cfc7f4bc31734bc70f2cd43efae8345..9dcae814ed19193dd68345cbd3f6ecc4eca2874f 100644 (file)
@@ -347,6 +347,7 @@ static const struct ReferenceFormats
     { "TIFF64", UndefinedCompression, 0.0 },
     { "TILE", UndefinedCompression, 0.0 },
     { "TIM", UndefinedCompression, 0.0 },
+    { "TIM2", UndefinedCompression, 0.0 },
     { "TTC", UndefinedCompression, 0.0 },
     { "TTF", UndefinedCompression, 0.0 },
     { "TXT", UndefinedCompression, 0.0 },