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