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