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