1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % TTTTT IIIII M M 222 %
7 % T I MM MM 2 2 %
8 % T I M M M 2 %
9 % T I M M 2 %
10 % T IIIII M M 22222 %
11 % %
12 % %
13 % Read PSX TIM2 Image Format %
14 % %
15 % Software Design %
16 % Ramiro Balado Ordax %
17 % May 2019 %
18 % %
19 % %
20 % Copyright 2019-2019 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://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 /*
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/channel.h"
49 #include "MagickCore/exception.h"
50 #include "MagickCore/exception-private.h"
51 #include "MagickCore/image.h"
52 #include "MagickCore/image-private.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/magick.h"
55 #include "MagickCore/memory_.h"
56 #include "MagickCore/monitor.h"
57 #include "MagickCore/monitor-private.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/quantum-private.h"
60 #include "MagickCore/static.h"
61 #include "MagickCore/string_.h"
62 #include "MagickCore/module.h"
63
64
65 /*
66 Typedef declarations
67 */
68 typedef struct _TIM2FileHeader
69 {
70 unsigned int
71 magic_num;
72
73 unsigned char
74 format_vers,
75 format_type;
76
77 unsigned short
78 image_count;
79
80 char
81 reserved[8];
82 } TIM2FileHeader;
83
84 typedef struct _TIM2ImageHeader
85 {
86 unsigned int
87 total_size,
88 clut_size,
89 image_size;
90
91 unsigned short
92 header_size,
93 clut_color_count;
94
95 unsigned char
96 img_format,
97 mipmap_count,
98 clut_type,
99 bpp_type;
100
101 unsigned short
102 width,
103 height;
104
105 MagickSizeType
106 GsTex0,
107 GsTex1;
108
109 unsigned int
110 GsRegs,
111 GsTexClut;
112 } TIM2ImageHeader;
113
114 typedef enum
115 {
116 CSM1=0,
117 CSM2=1,
118 } CSM;
119
120 typedef enum
121 {
122 RGBA32=0,
123 RGB24=1,
124 RGBA16=2,
125 } TIM2ColorEncoding;
126
127
128 /*
129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 % %
131 % %
132 % %
133 % R e a d T I M 2 I m a g e %
134 % %
135 % %
136 % %
137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138 %
139 % ReadTIM2Image() reads a PS2 TIM image file and returns it. It
140 % allocates the memory necessary for the new Image structure and returns a
141 % pointer to the new image.
142 %
143 % The format of the ReadTIM2Image method is:
144 %
145 % Image *ReadTIM2Image(const ImageInfo *image_info,ExceptionInfo *exception)
146 %
147 % A description of each parameter follows:
148 %
149 % o image_info: the image info.
150 %
151 % o exception: return any errors or warnings in this structure.
152 %
153 */
ReadTIM2ImageHeader(Image * image,TIM2ImageHeader * header)154 static inline void ReadTIM2ImageHeader(Image *image,TIM2ImageHeader *header)
155 {
156 header->total_size=ReadBlobLSBLong(image);
157 header->clut_size=ReadBlobLSBLong(image);
158 header->image_size=ReadBlobLSBLong(image);
159 header->header_size=ReadBlobLSBShort(image);
160
161 header->clut_color_count=ReadBlobLSBShort(image);
162 header->img_format=(unsigned char) ReadBlobByte(image);
163 header->mipmap_count=(unsigned char) ReadBlobByte(image);
164 header->clut_type=(unsigned char) ReadBlobByte(image);
165 header->bpp_type=(unsigned char) ReadBlobByte(image);
166
167 header->width=ReadBlobLSBShort(image);
168 header->height=ReadBlobLSBShort(image);
169
170 header->GsTex0=ReadBlobMSBLongLong(image);
171 header->GsTex1=ReadBlobMSBLongLong(image);
172 header->GsRegs=ReadBlobMSBLong(image);
173 header->GsTexClut=ReadBlobMSBLong(image);
174 }
175
GetChannelValue(unsigned int word,unsigned char channel,TIM2ColorEncoding ce)176 static inline Quantum GetChannelValue(unsigned int word,unsigned char channel,
177 TIM2ColorEncoding ce)
178 {
179 switch(ce)
180 {
181 case RGBA16:
182 /* Documentation specifies padding with zeros for converting from 5 to 8 bits. */
183 return ScaleCharToQuantum((word>>channel*5 & ~(~0x0U<<5))<<3);
184 case RGB24:
185 case RGBA32:
186 return ScaleCharToQuantum(word>>channel*8 & ~(~0x0U<<8));
187 default:
188 return -1;
189 }
190 }
191
GetAlpha(unsigned int word,TIM2ColorEncoding ce)192 static inline Quantum GetAlpha(unsigned int word,TIM2ColorEncoding ce)
193 {
194 switch(ce)
195 {
196 case RGBA16:
197 return ScaleCharToQuantum((word>>3*5&0x1F)==0?0:0xFF);
198 case RGBA32:
199 /* 0x80 -> 1.0 alpha. Multiply by 2 and clamp to 0xFF */
200 return ScaleCharToQuantum(MagickMin((word>>3*8&0xFF)<<1,0xFF));
201 default:
202 return 0xFF;
203 }
204 }
205
deshufflePalette(Image * image,PixelInfo * oldColormap)206 static inline void deshufflePalette(Image *image,PixelInfo* oldColormap)
207 {
208 const size_t
209 pages=image->colors/32, /* Pages per CLUT */
210 blocks=4, /* Blocks per page */
211 colors=8; /* Colors per block */
212
213 int
214 page;
215
216 size_t
217 i=0;
218
219 (void) memcpy(oldColormap,image->colormap,(size_t)image->colors*
220 sizeof(*oldColormap));
221
222 /*
223 * Swap the 2nd and 3rd block in each page
224 */
225 for (page=0; page < (ssize_t) pages; page++)
226 {
227 memcpy(&(image->colormap[i+1*colors]),&(oldColormap[i+2*colors]),colors*
228 sizeof(PixelInfo));
229 memcpy(&(image->colormap[i+2*colors]),&(oldColormap[i+1*colors]),colors*
230 sizeof(PixelInfo));
231
232 i+=blocks*colors;
233 }
234 }
235
ReadTIM2ImageData(const ImageInfo * image_info,Image * image,TIM2ImageHeader * header,char clut_depth,char bits_per_pixel,ExceptionInfo * exception)236 static MagickBooleanType ReadTIM2ImageData(const ImageInfo *image_info,
237 Image *image,TIM2ImageHeader *header,char clut_depth,char bits_per_pixel,
238 ExceptionInfo *exception)
239 {
240 MagickBooleanType
241 status;
242
243 ssize_t
244 x;
245
246 Quantum
247 *q;
248
249 unsigned char
250 *p;
251
252 size_t
253 bits_per_line,
254 bytes_per_line;
255
256 ssize_t
257 count,
258 y;
259
260 unsigned char
261 *row_data;
262
263 unsigned int
264 word;
265
266 status=SetImageExtent(image,image->columns,image->rows,exception);
267 if (status == MagickFalse)
268 return(MagickFalse);
269 /*
270 * User data
271 */
272 status=DiscardBlobBytes(image,header->header_size-48);
273 if (status == MagickFalse)
274 return(MagickFalse);
275 /*
276 * Image data
277 */
278 bits_per_line=image->columns*bits_per_pixel;
279 bytes_per_line=bits_per_line/8 + ((bits_per_line%8==0) ? 0 : 1);
280 row_data=(unsigned char*) AcquireQuantumMemory(1,bytes_per_line);
281 if (row_data == (unsigned char *) NULL)
282 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
283 image_info->filename);
284 if (clut_depth != 0)
285 {
286 image->colors=header->clut_color_count;
287 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
288 {
289 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
290 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
291 image_info->filename);
292 }
293 switch (bits_per_pixel)
294 {
295 case 4:
296 {
297 for (y=0; y<(ssize_t) image->rows; y++)
298 {
299 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
300 if (q == (Quantum *) NULL)
301 break;
302 count=ReadBlob(image,bytes_per_line,row_data);
303 if (count != (ssize_t) bytes_per_line)
304 {
305 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
306 ThrowBinaryException(CorruptImageError,
307 "InsufficientImageDataInFile",image_info->filename);
308 }
309 p=row_data;
310 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
311 {
312 SetPixelIndex(image,(*p >> 0) & 0x0F,q);
313 q+=GetPixelChannels(image);
314 SetPixelIndex(image,(*p >> 4) & 0x0F,q);
315 p++;
316 q+=GetPixelChannels(image);
317 }
318 if ((image->columns % 2) != 0)
319 {
320 SetPixelIndex(image,(*p >> 4) & 0x0F,q);
321 p++;
322 q+=GetPixelChannels(image);
323 }
324 if (SyncAuthenticPixels(image,exception) == MagickFalse)
325 break;
326 if (image->previous == (Image *) NULL)
327 {
328 status=SetImageProgress(image,LoadImageTag,
329 (MagickOffsetType) y,image->rows);
330 if (status == MagickFalse)
331 break;
332 }
333 }
334 break;
335 }
336 case 8:
337 {
338 for (y=0;y<(ssize_t) image->rows; y++)
339 {
340 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
341 if (q == (Quantum *) NULL)
342 break;
343 count=ReadBlob(image,bytes_per_line,row_data);
344 if (count != (ssize_t) bytes_per_line)
345 {
346 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
347 ThrowBinaryException(CorruptImageError,
348 "InsufficientImageDataInFile",image_info->filename);
349 }
350 p=row_data;
351 for (x=0; x < (ssize_t) image->columns; x++)
352 {
353 SetPixelIndex(image,*p,q);
354 p++;
355 q+=GetPixelChannels(image);
356 }
357 if (SyncAuthenticPixels(image,exception) == MagickFalse)
358 break;
359 if (image->previous == (Image *) NULL)
360 {
361 status=SetImageProgress(image,LoadImageTag,
362 (MagickOffsetType) y,image->rows);
363 if (status == MagickFalse)
364 break;
365 }
366 }
367 break;
368 }
369 default:
370 {
371 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
372 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
373 image_info->filename);
374 }
375 }
376 }
377 else /* has_clut==false */
378 {
379 switch (bits_per_pixel)
380 {
381 case 16:
382 {
383 for (y=0; y<(ssize_t) image->rows; y++)
384 {
385 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
386 if (q == (Quantum *) NULL)
387 break;
388 count=ReadBlob(image,bytes_per_line,row_data);
389 if (count != (ssize_t) bytes_per_line)
390 {
391 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
392 ThrowBinaryException(CorruptImageError,
393 "InsufficientImageDataInFile",image_info->filename);
394 }
395 p=row_data;
396 for (x=0; x < (ssize_t) image->columns; x++)
397 {
398 word = ((unsigned int)* p )<<0*8 |
399 ((unsigned int)*(p+1))<<1*8;
400
401 SetPixelRed(image,GetChannelValue(word,0,RGBA16),q);
402 SetPixelGreen(image,GetChannelValue(word,1,RGBA16),q);
403 SetPixelBlue(image,GetChannelValue(word,2,RGBA16),q);
404 SetPixelAlpha(image,GetAlpha(word,RGBA16),q);
405 q+=GetPixelChannels(image);
406 p+=sizeof(unsigned short);
407 }
408 if (SyncAuthenticPixels(image,exception) == MagickFalse)
409 break;
410 if (image->previous == (Image *) NULL)
411 {
412 status=SetImageProgress(image,LoadImageTag,
413 (MagickOffsetType) y,image->rows);
414 if (status == MagickFalse)
415 break;
416 }
417 }
418 break;
419 }
420 case 24:
421 {
422 for (y = 0; y<(ssize_t) image->rows; y++)
423 {
424 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
425 if (q == (Quantum *) NULL)
426 break;
427 count=ReadBlob(image,bytes_per_line,row_data);
428 if (count != (ssize_t) bytes_per_line)
429 {
430 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
431 ThrowBinaryException(CorruptImageError,
432 "InsufficientImageDataInFile",image_info->filename);
433 }
434 p=row_data;
435 for (x=0; x < (ssize_t) image->columns; x++)
436 {
437 word = (unsigned int)(* p )<<0*8 |
438 (unsigned int)(*(p+1))<<1*8 |
439 (unsigned int)(*(p+2))<<2*8;
440
441 SetPixelRed(image,GetChannelValue(word,0,RGB24),q);
442 SetPixelGreen(image,GetChannelValue(word,1,RGB24),q);
443 SetPixelBlue(image,GetChannelValue(word,2,RGB24),q);
444 q+=GetPixelChannels(image);
445 p+=3;
446 }
447 if (SyncAuthenticPixels(image,exception) == MagickFalse)
448 break;
449 if (image->previous == (Image *) NULL)
450 {
451 status=SetImageProgress(image,LoadImageTag,
452 (MagickOffsetType) y,image->rows);
453 if (status == MagickFalse)
454 break;
455 }
456 }
457 break;
458 }
459 case 32:
460 {
461 for (y = 0; y<(ssize_t) image->rows; y++)
462 {
463 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
464 if (q == (Quantum *) NULL)
465 break;
466 count=ReadBlob(image,bytes_per_line,row_data);
467 if (count != (ssize_t) bytes_per_line)
468 {
469 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
470 ThrowBinaryException(CorruptImageError,
471 "InsufficientImageDataInFile",image_info->filename);
472 }
473 p=row_data;
474 for (x=0; x < (ssize_t) image->columns; x++)
475 {
476 word = ((unsigned int)* p )<<0*8 |
477 ((unsigned int)*(p+1))<<1*8 |
478 ((unsigned int)*(p+2))<<2*8 |
479 ((unsigned int)*(p+3))<<3*8;
480
481 SetPixelRed(image,GetChannelValue(word,0,RGBA32),q);
482 SetPixelGreen(image,GetChannelValue(word,1,RGBA32),q);
483 SetPixelBlue(image,GetChannelValue(word,2,RGBA32),q);
484 SetPixelAlpha(image,GetAlpha(word,RGBA32),q);
485 q+=GetPixelChannels(image);
486 p+=4;
487 }
488 if (SyncAuthenticPixels(image,exception) == MagickFalse)
489 break;
490 if (image->previous == (Image *) NULL)
491 {
492 status=SetImageProgress(image,LoadImageTag,
493 (MagickOffsetType) y,image->rows);
494 if (status == MagickFalse)
495 break;
496 }
497 }
498 break;
499 }
500 default:
501 {
502 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
503 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
504 image_info->filename);
505 }
506 }
507 }
508 row_data=(unsigned char *) RelinquishMagickMemory(row_data);
509 if ((status != MagickFalse) && (clut_depth != 0))
510 {
511 CSM
512 csm;
513
514 ssize_t
515 i;
516
517 unsigned char
518 *clut_data;
519
520 /*
521 * ### Read CLUT Data ###
522 */
523 clut_data=(unsigned char *) AcquireQuantumMemory(1,header->clut_size);
524 if (clut_data == (unsigned char *) NULL)
525 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
526 image_info->filename);
527 count=ReadBlob(image,header->clut_size,clut_data);
528 if (count != (ssize_t) (header->clut_size))
529 {
530 clut_data=(unsigned char *) RelinquishMagickMemory(clut_data);
531 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
532 image_info->filename);
533 }
534 /*
535 * ### Process CLUT Data ###
536 */
537 p=clut_data;
538 switch(clut_depth)
539 {
540 case 16:
541 {
542 for (i=0; i < (ssize_t) image->colors; i++)
543 {
544 word = ((unsigned short)* p )<<0*8 |
545 ((unsigned short)*(p+1))<<1*8;
546
547 image->colormap[i].red=GetChannelValue(word,0,RGBA16);
548 image->colormap[i].green=GetChannelValue(word,1,RGBA16);
549 image->colormap[i].blue=GetChannelValue(word,2,RGBA16);
550 image->colormap[i].alpha=GetAlpha(word,RGBA16);
551 p+=2;
552 }
553 break;
554 }
555 case 24:
556 {
557 for (i=0; i < (ssize_t) image->colors; i++)
558 {
559 word = ((unsigned int)* p )<<0*8 |
560 ((unsigned int)*(p+1))<<1*8 |
561 ((unsigned int)*(p+2))<<2*8;
562
563 image->colormap[i].red=GetChannelValue(word,0,RGB24);
564 image->colormap[i].green=GetChannelValue(word,1,RGB24);
565 image->colormap[i].blue=GetChannelValue(word,2,RGB24);
566 p+=3;
567 }
568 break;
569 }
570 case 32:
571 {
572 for (i=0; i < (ssize_t) image->colors; i++)
573 {
574 word = ((unsigned int)* p )<<0*8 |
575 ((unsigned int)*(p+1))<<1*8 |
576 ((unsigned int)*(p+2))<<2*8 |
577 ((unsigned int)*(p+3))<<3*8;
578
579 image->colormap[i].red=GetChannelValue(word,0,RGBA32);
580 image->colormap[i].green=GetChannelValue(word,1,RGBA32);
581 image->colormap[i].blue=GetChannelValue(word,2,RGBA32);
582 image->colormap[i].alpha=GetAlpha(word,RGBA32);
583 p+=4;
584 }
585 break;
586 }
587 }
588 clut_data=(unsigned char *) RelinquishMagickMemory(clut_data);
589 /* CSM: CLUT Storage Mode */
590 switch ((int) header->clut_type>>4) /* High 4 bits */
591 {
592 case 0:
593 csm=CSM1;
594 break;
595 case 1:
596 csm=CSM2;
597 break;
598 default:
599 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
600 image_info->filename);
601 break;
602 }
603 if (csm==CSM1)
604 {
605 PixelInfo
606 *oldColormap;
607
608 oldColormap=(PixelInfo *) AcquireQuantumMemory((size_t)(image->colors)+1,
609 sizeof(*image->colormap));
610 if (oldColormap == (PixelInfo *) NULL)
611 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
612 image_info->filename);
613 deshufflePalette(image,oldColormap);
614 RelinquishMagickMemory(oldColormap);
615 }
616 }
617 return(status);
618 }
619
ReadTIM2Image(const ImageInfo * image_info,ExceptionInfo * exception)620 static Image *ReadTIM2Image(const ImageInfo *image_info,ExceptionInfo *exception)
621 {
622 Image
623 *image;
624
625 MagickBooleanType
626 status;
627
628 ssize_t
629 str_read;
630
631 TIM2FileHeader
632 file_header;
633
634 /*
635 * Open image file.
636 */
637 assert(image_info != (const ImageInfo *) NULL);
638 assert(image_info->signature == MagickCoreSignature);
639
640 if (image_info->debug != MagickFalse)
641 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
642 image_info->filename);
643 assert(exception != (ExceptionInfo *) NULL);
644 assert(exception->signature == MagickCoreSignature);
645 image=AcquireImage(image_info,exception);
646 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
647 if (status == MagickFalse)
648 {
649 image=DestroyImageList(image);
650 return((Image *) NULL);
651 }
652 /*
653 * Verify TIM2 magic number.
654 */
655 file_header.magic_num=ReadBlobMSBLong(image);
656 if (file_header.magic_num != 0x54494D32) /* "TIM2" */
657 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
658 /*
659 * #### Read File Header ####
660 */
661 file_header.format_vers=ReadBlobByte(image);
662 if (file_header.format_vers != 0x04)
663 ThrowReaderException(CoderError,"ImageTypeNotSupported");
664 file_header.format_type=ReadBlobByte(image);
665 file_header.image_count=ReadBlobLSBShort(image);
666 ReadBlobStream(image,8,&(file_header.reserved),&str_read);
667 /*
668 * Jump to first image header
669 */
670 switch(file_header.format_type)
671 {
672 case 0x00:
673 if (DiscardBlobBytes(image,16) == MagickFalse)
674 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
675 break;
676 case 0x01:
677 if (DiscardBlobBytes(image,128) == MagickFalse)
678 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
679 break;
680 default:
681 ThrowReaderException(CoderError,"ImageTypeNotSupported");
682 }
683 /*
684 * Process each image. Only one image supported for now
685 */
686 if (file_header.image_count != 1)
687 ThrowReaderException(CoderError,"NumberOfImagesIsNotSupported");
688 for (int i=0; i < file_header.image_count; ++i)
689 {
690 char
691 clut_depth,
692 bits_per_pixel;
693
694 TIM2ImageHeader
695 image_header;
696
697 ReadTIM2ImageHeader(image,&image_header);
698 if (image_header.mipmap_count != 1)
699 ThrowReaderException(CoderError,"NumberOfImagesIsNotSupported");
700 if (image_header.header_size < 48)
701 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
702 if ((MagickSizeType) image_header.image_size > GetBlobSize(image))
703 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
704 if ((MagickSizeType) image_header.clut_size > GetBlobSize(image))
705 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
706 image->columns=image_header.width;
707 image->rows=image_header.height;
708 clut_depth=0;
709 if (image_header.clut_type !=0)
710 {
711 switch((int) image_header.clut_type&0x0F) /* Low 4 bits */
712 {
713 case 1:
714 clut_depth=16;
715 break;
716 case 2:
717 clut_depth=24;
718 break;
719 case 3:
720 clut_depth=32;
721 break;
722 default:
723 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
724 break;
725 }
726 }
727 switch ((int) image_header.bpp_type)
728 {
729 case 1:
730 bits_per_pixel=16;
731 break;
732 case 2:
733 bits_per_pixel=24;
734 break;
735 case 3:
736 bits_per_pixel=32;
737 break;
738 case 4:
739 bits_per_pixel=4; /* Implies CLUT */
740 break;
741 case 5:
742 bits_per_pixel=8; /* Implies CLUT */
743 break;
744 default:
745 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
746 break;
747 }
748 image->depth=(clut_depth != 0) ? clut_depth : bits_per_pixel;
749 if ((image->depth == 16) || (image->depth == 32))
750 image->alpha_trait=BlendPixelTrait;
751 if (image->ping != MagickFalse)
752 {
753 status=ReadTIM2ImageData(image_info,image,&image_header,clut_depth,
754 bits_per_pixel,exception);
755 if (status==MagickFalse)
756 break;
757 }
758 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
759 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
760 break;
761 if ((image->storage_class == PseudoClass) && (EOFBlob(image) != MagickFalse))
762 {
763 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
764 image->filename);
765 break;
766 }
767 /*
768 Proceed to next image.
769 */
770 if (image_info->number_scenes != 0)
771 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
772 break;
773 /*
774 Allocate next image structure.
775 */
776 AcquireNextImage(image_info,image,exception);
777 if (GetNextImageInList(image) == (Image *) NULL)
778 {
779 status=MagickFalse;
780 break;
781 }
782 image=SyncNextImageInList(image);
783 status=SetImageProgress(image,LoadImagesTag,image->scene-1,
784 image->scene);
785 if (status == MagickFalse)
786 break;
787 }
788 (void) CloseBlob(image);
789 if (status == MagickFalse)
790 return(DestroyImageList(image));
791 return(GetFirstImageInList(image));
792 }
793
794
795 /*
796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 % %
798 % %
799 % %
800 % R e g i s t e r T I M 2 I m a g e %
801 % %
802 % %
803 % %
804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805 %
806 % RegisterTIM2Image() adds attributes for the TIM2 image format to
807 % the list of supported formats. The attributes include the image format
808 % tag, a method to read and/or write the format, whether the format
809 % supports the saving of more than one frame to the same file or blob,
810 % whether the format supports native in-memory I/O, and a brief
811 % description of the format.
812 %
813 % The format of the RegisterTIM2Image method is:
814 %
815 % size_t RegisterTIM2Image(void)
816 %
817 */
RegisterTIM2Image(void)818 ModuleExport size_t RegisterTIM2Image(void)
819 {
820 MagickInfo
821 *entry;
822
823 entry=AcquireMagickInfo("TIM2","TM2","PS2 TIM2");
824 entry->decoder=(DecodeImageHandler *) ReadTIM2Image;
825 (void) RegisterMagickInfo(entry);
826 return(MagickImageCoderSignature);
827 }
828
829
830 /*
831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
832 % %
833 % %
834 % %
835 % U n r e g i s t e r T I M 2 I m a g e %
836 % %
837 % %
838 % %
839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
840 %
841 % UnregisterTIM2Image() removes format registrations made by the
842 % TIM2 module from the list of supported formats.
843 %
844 % The format of the UnregisterTIM2Image method is:
845 %
846 % UnregisterTIM2Image(void)
847 %
848 */
UnregisterTIM2Image(void)849 ModuleExport void UnregisterTIM2Image(void)
850 {
851 (void) UnregisterMagickInfo("TM2");
852 }
853