~ubuntu-branches/ubuntu/intrepid/graphicsmagick/intrepid

« back to all changes in this revision

Viewing changes to coders/tga.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2006-05-06 16:28:08 UTC
  • Revision ID: james.westby@ubuntu.com-20060506162808-vt2ni3r5nytcszms
Tags: upstream-1.1.7
ImportĀ upstreamĀ versionĀ 1.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
% Copyright (C) 2003, 2004 GraphicsMagick Group
 
3
% Copyright (C) 2002 ImageMagick Studio
 
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
 
5
%
 
6
% This program is covered by multiple licenses, which are described in
 
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
 
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
 
9
%
 
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
11
%                                                                             %
 
12
%                                                                             %
 
13
%                                                                             %
 
14
%                            TTTTT   GGGG   AAA                               %
 
15
%                              T    G      A   A                              %
 
16
%                              T    G  GG  AAAAA                              %
 
17
%                              T    G   G  A   A                              %
 
18
%                              T     GGG   A   A                              %
 
19
%                                                                             %
 
20
%                                                                             %
 
21
%                   Read/Write Truevision Targa Image Format.                 %
 
22
%                                                                             %
 
23
%                                                                             %
 
24
%                              Software Design                                %
 
25
%                                John Cristy                                  %
 
26
%                                 July 1992                                   %
 
27
%                                                                             %
 
28
%                                                                             %
 
29
%                                                                             %
 
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
31
%
 
32
%
 
33
*/
 
34
 
 
35
/*
 
36
  Include declarations.
 
37
*/
 
38
#include "magick/studio.h"
 
39
#include "magick/attribute.h"
 
40
#include "magick/blob.h"
 
41
#include "magick/cache.h"
 
42
#include "magick/color.h"
 
43
#include "magick/log.h"
 
44
#include "magick/magick.h"
 
45
#include "magick/monitor.h"
 
46
#include "magick/utility.h"
 
47
 
 
48
/*
 
49
  Forward declarations.
 
50
*/
 
51
static unsigned int
 
52
  WriteTGAImage(const ImageInfo *,Image *);
 
53
 
 
54
/*
 
55
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
56
%                                                                             %
 
57
%                                                                             %
 
58
%                                                                             %
 
59
%   R e a d T G A I m a g e                                                   %
 
60
%                                                                             %
 
61
%                                                                             %
 
62
%                                                                             %
 
63
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
64
%
 
65
%  Method ReadTGAImage reads a Truevision TGA image file and returns it.
 
66
%  It allocates the memory necessary for the new Image structure and returns
 
67
%  a pointer to the new image.
 
68
%
 
69
%  The format of the ReadTGAImage method is:
 
70
%
 
71
%      Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
72
%
 
73
%  A description of each parameter follows:
 
74
%
 
75
%    o image:  Method ReadTGAImage returns a pointer to the image after
 
76
%      reading.  A null image is returned if there is a memory shortage or
 
77
%      if the image cannot be read.
 
78
%
 
79
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
80
%
 
81
%    o exception: return any errors or warnings in this structure.
 
82
%
 
83
%
 
84
*/
 
85
static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
86
{
 
87
#define TGAColormap 1          /* Colormapped image data */
 
88
#define TGARGB 2               /* Truecolor image data */
 
89
#define TGAMonochrome 3        /* Monochrome image data */
 
90
#define TGARLEColormap  9      /* Colormapped image data (encoded) */
 
91
#define TGARLERGB  10          /* Truecolor image data (encoded) */
 
92
#define TGARLEMonochrome  11   /* Monochrome image data (encoded) */
 
93
 
 
94
  typedef struct _TGAInfo
 
95
  {
 
96
    unsigned char
 
97
    id_length,       /* Size of Image ID field */
 
98
      colormap_type,   /* Color map type */
 
99
      image_type;      /* Image type code */
 
100
 
 
101
    unsigned short
 
102
    colormap_index,  /* Color map origin */
 
103
      colormap_length; /* Color map length */
 
104
 
 
105
    unsigned char
 
106
    colormap_size;   /* Color map entry depth */
 
107
 
 
108
    unsigned short
 
109
    x_origin,          /* X origin of image */
 
110
      y_origin,        /* Y orgin of image */
 
111
      width,           /* Width of image */
 
112
      height;          /* Height of image */
 
113
 
 
114
    unsigned char
 
115
    bits_per_pixel,  /* Image pixel size */
 
116
      attributes;      /* Image descriptor byte */
 
117
  } TGAInfo;
 
118
 
 
119
  Image
 
120
    *image;
 
121
 
 
122
  IndexPacket
 
123
    index;
 
124
 
 
125
  long
 
126
    y;
 
127
 
 
128
  PixelPacket
 
129
    pixel;
 
130
 
 
131
  register IndexPacket
 
132
    *indexes;
 
133
 
 
134
  register long
 
135
    i,
 
136
    x;
 
137
 
 
138
  register PixelPacket
 
139
    *q;
 
140
 
 
141
  size_t
 
142
    count;
 
143
 
 
144
  TGAInfo
 
145
    tga_info;
 
146
 
 
147
  unsigned char
 
148
    runlength;
 
149
 
 
150
  unsigned int
 
151
    alpha_bits,
 
152
    status;
 
153
 
 
154
  unsigned long
 
155
    base,
 
156
    flag,
 
157
    offset,
 
158
    real,
 
159
    skip;
 
160
 
 
161
  unsigned int
 
162
    is_grayscale=False;
 
163
 
 
164
  /*
 
165
    Open image file.
 
166
  */
 
167
  assert(image_info != (const ImageInfo *) NULL);
 
168
  assert(image_info->signature == MagickSignature);
 
169
  assert(exception != (ExceptionInfo *) NULL);
 
170
  assert(exception->signature == MagickSignature);
 
171
  image=AllocateImage(image_info);
 
172
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
 
173
  if (status == False)
 
174
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
 
175
  /*
 
176
    Read TGA header information.
 
177
  */
 
178
  count=ReadBlob(image,1,(char *) &tga_info.id_length);
 
179
  tga_info.colormap_type=ReadBlobByte(image);
 
180
  tga_info.image_type=ReadBlobByte(image);
 
181
  do
 
182
    {
 
183
      if ((count == 0) ||
 
184
          ((tga_info.image_type != TGAColormap) &&
 
185
           (tga_info.image_type != TGARGB) &&
 
186
           (tga_info.image_type != TGAMonochrome) &&
 
187
           (tga_info.image_type != TGARLEColormap) &&
 
188
           (tga_info.image_type != TGARLERGB) &&
 
189
           (tga_info.image_type != TGARLEMonochrome)) ||
 
190
          (((tga_info.image_type == TGAColormap) ||
 
191
            (tga_info.image_type == TGARLEColormap)) &&
 
192
           (tga_info.colormap_type == 0)))
 
193
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
 
194
      tga_info.colormap_index=ReadBlobLSBShort(image);
 
195
      tga_info.colormap_length=ReadBlobLSBShort(image);
 
196
      tga_info.colormap_size=ReadBlobByte(image);
 
197
      tga_info.x_origin=ReadBlobLSBShort(image);
 
198
      tga_info.y_origin=ReadBlobLSBShort(image);
 
199
      tga_info.width=ReadBlobLSBShort(image);
 
200
      tga_info.height=ReadBlobLSBShort(image);
 
201
      tga_info.bits_per_pixel=ReadBlobByte(image);
 
202
      tga_info.attributes=ReadBlobByte(image);
 
203
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
 
204
                            "ImageType=%s CMapType=%u CMapStart=%u CMapLength=%u CMapDepth=%u\n  XOffset=%u YOffset=%u Width=%u Height=%u PixelDepth=%u Attributes=0x%.2x",
 
205
                            ((tga_info.image_type == TGAColormap) ? "Colormapped" :
 
206
                             (tga_info.image_type == TGARGB) ? "TrueColor" :
 
207
                             (tga_info.image_type == TGAMonochrome) ? "Monochrome" :
 
208
                             (tga_info.image_type == TGARLEColormap) ? "Colormapped-RLE" :
 
209
                             (tga_info.image_type == TGARLERGB) ? "Truecolor-RLE" :
 
210
                             (tga_info.image_type == TGARLEMonochrome) ? "Monochrome-RLE" :
 
211
                             "Unknown"),
 
212
                            (unsigned int) tga_info.colormap_type,
 
213
                            (unsigned int) tga_info.colormap_index,
 
214
                            (unsigned int) tga_info.colormap_length,
 
215
                            (unsigned int) tga_info.colormap_size,
 
216
                            tga_info.x_origin, tga_info.y_origin, tga_info.width, tga_info.height,
 
217
                            (unsigned int) tga_info.bits_per_pixel,
 
218
                            tga_info.attributes);
 
219
                   
 
220
      /*
 
221
        Initialize image structure.
 
222
      */
 
223
      alpha_bits=(tga_info.attributes & 0x0FU);
 
224
      image->matte=(alpha_bits > 0);
 
225
      image->columns=tga_info.width;
 
226
      image->rows=tga_info.height;
 
227
      if ((tga_info.image_type != TGAColormap) && (tga_info.image_type != TGARLEColormap))
 
228
        {
 
229
          /*
 
230
            TrueColor Quantum Depth
 
231
          */
 
232
          image->depth=((tga_info.bits_per_pixel <= 8) ? 8 :
 
233
                        (tga_info.bits_per_pixel <= 16) ? 5 :
 
234
                        (tga_info.bits_per_pixel == 24) ? 8 :
 
235
                        (tga_info.bits_per_pixel == 32) ? 8 : 8);
 
236
        }
 
237
      else
 
238
        {
 
239
          /*
 
240
            ColorMapped Palette Entry Quantum Depth
 
241
          */
 
242
          image->depth=((tga_info.colormap_size <= 8) ? 8 :
 
243
                        (tga_info.colormap_size <= 16) ? 5 :
 
244
                        (tga_info.colormap_size == 24) ? 8 :
 
245
                        (tga_info.colormap_size == 32) ? 8 : 8);
 
246
        }
 
247
 
 
248
      image->storage_class=DirectClass;
 
249
 
 
250
      if ((tga_info.image_type == TGAColormap) ||
 
251
          (tga_info.image_type == TGAMonochrome) ||
 
252
          (tga_info.image_type == TGARLEColormap) ||
 
253
          (tga_info.image_type == TGARLEMonochrome))
 
254
        {
 
255
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Setting PseudoClass");
 
256
          image->storage_class=PseudoClass;
 
257
        }
 
258
 
 
259
      if ((tga_info.image_type == TGARLEColormap) ||
 
260
          (tga_info.image_type == TGARLEMonochrome))
 
261
        image->compression=RLECompression;
 
262
 
 
263
      is_grayscale=((tga_info.image_type == TGAMonochrome) ||
 
264
                    (tga_info.image_type == TGARLEMonochrome));
 
265
 
 
266
      if (image->storage_class == PseudoClass)
 
267
        {
 
268
          if (tga_info.colormap_type != 0)
 
269
            {
 
270
              image->colors=tga_info.colormap_length;
 
271
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
 
272
                                    "Using existing colormap with %lu colors.",image->colors);
 
273
 
 
274
            }
 
275
          else
 
276
            {
 
277
              /*
 
278
                Apply grayscale colormap.
 
279
              */
 
280
              image->colors=(0x01U << tga_info.bits_per_pixel);
 
281
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
 
282
                                    "Applying grayscale colormap with %lu colors.",image->colors);
 
283
              if (!AllocateImageColormap(image,image->colors))
 
284
                ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
285
                                     image);
 
286
            }
 
287
        }
 
288
 
 
289
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
 
290
                            "StorageClass=%s Matte=%s Depth=%lu Grayscale=%s",
 
291
                            ((image->storage_class == DirectClass) ? "DirectClass" : "PseduoClass"),
 
292
                            (image->matte ? "True" : "False"), image->depth,
 
293
                            (is_grayscale ? "True" : "False"));
 
294
    
 
295
      if (tga_info.id_length != 0)
 
296
        {
 
297
          char
 
298
            *comment;
 
299
 
 
300
          /*
 
301
            TGA image comment.
 
302
          */
 
303
          comment=MagickAllocateMemory(char *,tga_info.id_length+1);
 
304
          if (comment == (char *) NULL)
 
305
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
306
                                 image);
 
307
          (void) ReadBlob(image,tga_info.id_length,comment);
 
308
          comment[tga_info.id_length]='\0';
 
309
          (void) SetImageAttribute(image,"comment",comment);
 
310
          MagickFreeMemory(comment);
 
311
        }
 
312
      (void) memset(&pixel,0,sizeof(PixelPacket));
 
313
      pixel.opacity=TransparentOpacity;
 
314
      if (tga_info.colormap_type != 0)
 
315
        {
 
316
          /*
 
317
            Read TGA raster colormap.
 
318
          */
 
319
          if (!AllocateImageColormap(image,image->colors))
 
320
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
321
                                 image);
 
322
          for (i=0; i < (long) image->colors; i++)
 
323
            {
 
324
              switch (tga_info.colormap_size)
 
325
                {
 
326
                case 8:
 
327
                default:
 
328
                  {
 
329
                    /*
 
330
                      Gray scale.
 
331
                    */
 
332
                    pixel.red=ScaleCharToQuantum(ReadBlobByte(image));
 
333
                    pixel.green=pixel.red;
 
334
                    pixel.blue=pixel.red;
 
335
                    break;
 
336
                  }
 
337
                case 15:
 
338
                case 16:
 
339
                  {
 
340
                    /*
 
341
                      5 bits each of red green and blue.
 
342
                    */
 
343
                    unsigned int
 
344
                      packet;
 
345
 
 
346
                    packet = ReadBlobByte(image);
 
347
                    packet |= (((unsigned int) ReadBlobByte(image)) << 8);
 
348
 
 
349
                    pixel.red=(packet >> 10) & 0x1f;
 
350
                    pixel.red=ScaleCharToQuantum(ScaleColor5to8(pixel.red));
 
351
                    pixel.green=(packet >> 5) & 0x1f;
 
352
                    pixel.green=ScaleCharToQuantum(ScaleColor5to8(pixel.green));
 
353
                    pixel.blue=packet & 0x1f;
 
354
                    pixel.blue=ScaleCharToQuantum(ScaleColor5to8(pixel.blue));
 
355
                    break;
 
356
                  }
 
357
                case 24:
 
358
                case 32:
 
359
                  {
 
360
                    /*
 
361
                      8 bits each of blue, green and red.
 
362
                    */
 
363
                    pixel.blue=ScaleCharToQuantum(ReadBlobByte(image));
 
364
                    pixel.green=ScaleCharToQuantum(ReadBlobByte(image));
 
365
                    pixel.red=ScaleCharToQuantum(ReadBlobByte(image));
 
366
                    break;
 
367
                  }
 
368
                }
 
369
              image->colormap[i]=pixel;
 
370
            }
 
371
        }
 
372
      if (image_info->ping && (image_info->subrange != 0))
 
373
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
 
374
          break;
 
375
      /*
 
376
        Convert TGA pixels to pixel packets.
 
377
      */
 
378
      base=0;
 
379
      flag=0;
 
380
      skip=False;
 
381
      real=0;
 
382
      index=0;
 
383
      runlength=0;
 
384
      offset=0;
 
385
      pixel.opacity=OpaqueOpacity;
 
386
      for (y=0; y < (long) image->rows; y++)
 
387
        {
 
388
          real=offset;
 
389
          if (((unsigned char) (tga_info.attributes & 0x20) >> 5) == 0)
 
390
            real=image->rows-real-1;
 
391
          q=SetImagePixels(image,0,(long) real,image->columns,1);
 
392
          if (q == (PixelPacket *) NULL)
 
393
            break;
 
394
          indexes=GetIndexes(image);
 
395
          for (x=0; x < (long) image->columns; x++)
 
396
            {
 
397
              if ((tga_info.image_type == TGARLEColormap) ||
 
398
                  (tga_info.image_type == TGARLERGB) ||
 
399
                  (tga_info.image_type == TGARLEMonochrome))
 
400
                {
 
401
                  if (runlength != 0)
 
402
                    {
 
403
                      runlength--;
 
404
                      skip=flag != 0;
 
405
                    }
 
406
                  else
 
407
                    {
 
408
                      count=ReadBlob(image,1,(char *) &runlength);
 
409
                      if (count == 0)
 
410
                        ThrowReaderException(CorruptImageError,UnableToReadImageData,image);
 
411
                      flag=runlength & 0x80;
 
412
                      if (flag != 0)
 
413
                        runlength-=128;
 
414
                      skip=False;
 
415
                    }
 
416
                }
 
417
              if (!skip)
 
418
                switch (tga_info.bits_per_pixel)
 
419
                  {
 
420
                  case 8:
 
421
                  default:
 
422
                    {
 
423
                      /*
 
424
                        Gray scale.
 
425
                      */
 
426
                      index=ReadBlobByte(image);
 
427
                      if (image->storage_class == PseudoClass)
 
428
                        {
 
429
                          VerifyColormapIndex(image,index);
 
430
                          pixel=image->colormap[index];
 
431
                        }
 
432
                      else
 
433
                        {
 
434
                          pixel.blue=pixel.green=pixel.red=ScaleCharToQuantum(index);
 
435
                        }
 
436
                      break;
 
437
                    }
 
438
                  case 15:
 
439
                  case 16:
 
440
                    {
 
441
                      /*
 
442
                        5 bits each of red green and blue.
 
443
                      */
 
444
                      unsigned int
 
445
                        packet;
 
446
 
 
447
                      packet = ReadBlobByte(image);
 
448
                      packet |= (((unsigned int) ReadBlobByte(image)) << 8);
 
449
 
 
450
                      pixel.red=(packet >> 10) & 0x1f;
 
451
                      pixel.red=ScaleCharToQuantum(ScaleColor5to8(pixel.red));
 
452
                      pixel.green=(packet >> 5) & 0x1f;
 
453
                      pixel.green=ScaleCharToQuantum(ScaleColor5to8(pixel.green));
 
454
                      pixel.blue=packet & 0x1f;
 
455
                      pixel.blue=ScaleCharToQuantum(ScaleColor5to8(pixel.blue));
 
456
                      if (image->matte)
 
457
                        {
 
458
                          if ((packet >> 15) & 0x01)
 
459
                            pixel.opacity=OpaqueOpacity;
 
460
                          else
 
461
                            pixel.opacity=TransparentOpacity;
 
462
                        }
 
463
                
 
464
                      if (image->storage_class == PseudoClass)
 
465
                        {
 
466
                          index=(IndexPacket) (packet & 0x7fff);
 
467
                          VerifyColormapIndex(image,index);
 
468
                        }
 
469
                      break;
 
470
                    }
 
471
                  case 24:
 
472
                    /*
 
473
                      8 bits each of blue green and red.
 
474
                    */
 
475
                    pixel.blue=ScaleCharToQuantum(ReadBlobByte(image));
 
476
                    pixel.green=ScaleCharToQuantum(ReadBlobByte(image));
 
477
                    pixel.red=ScaleCharToQuantum(ReadBlobByte(image));
 
478
                    break;
 
479
                  case 32:
 
480
                    {
 
481
                      /*
 
482
                        8 bits each of blue green and red.
 
483
                      */
 
484
                      pixel.blue=ScaleCharToQuantum(ReadBlobByte(image));
 
485
                      pixel.green=ScaleCharToQuantum(ReadBlobByte(image));
 
486
                      pixel.red=ScaleCharToQuantum(ReadBlobByte(image));
 
487
                      pixel.opacity=ScaleCharToQuantum(255-ReadBlobByte(image));
 
488
                      break;
 
489
                    }
 
490
                  }
 
491
              if (status == False)
 
492
                ThrowReaderException(CorruptImageError,UnableToReadImageData,image);
 
493
              if (image->storage_class == PseudoClass)
 
494
                indexes[x]=index;
 
495
              *q++=pixel;
 
496
            }
 
497
          if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 4)
 
498
            offset+=4;
 
499
          else
 
500
            if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 2)
 
501
              offset+=2;
 
502
            else
 
503
              offset++;
 
504
          if (offset >= image->rows)
 
505
            {
 
506
              base++;
 
507
              offset=base;
 
508
            }
 
509
          if (!SyncImagePixels(image))
 
510
            break;
 
511
          image->is_grayscale=is_grayscale;
 
512
          if (image->previous == (Image *) NULL)
 
513
            if (QuantumTick(y,image->rows))
 
514
              if (!MagickMonitor(LoadImageText,y,image->rows,exception))
 
515
                break;
 
516
        }
 
517
      if (EOFBlob(image))
 
518
        {
 
519
          ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
 
520
                         image->filename);
 
521
          break;
 
522
        }
 
523
      /*
 
524
        Proceed to next image.
 
525
      */
 
526
      if (image_info->subrange != 0)
 
527
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
 
528
          break;
 
529
      count=ReadBlob(image,1,(char *) &tga_info.id_length);
 
530
      tga_info.colormap_type=ReadBlobByte(image);
 
531
      tga_info.image_type=ReadBlobByte(image);
 
532
      status=((tga_info.image_type == TGAColormap) ||
 
533
              (tga_info.image_type == TGARGB) ||
 
534
              (tga_info.image_type == TGAMonochrome) ||
 
535
              (tga_info.image_type == TGARLEColormap) ||
 
536
              (tga_info.image_type == TGARLERGB) ||
 
537
              (tga_info.image_type == TGARLEMonochrome));
 
538
      if (status == True)
 
539
        {
 
540
          /*
 
541
            Allocate next image structure.
 
542
          */
 
543
          AllocateNextImage(image_info,image);
 
544
          if (image->next == (Image *) NULL)
 
545
            {
 
546
              DestroyImageList(image);
 
547
              return((Image *) NULL);
 
548
            }
 
549
          image=SyncNextImageInList(image);
 
550
          if (!MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),exception))
 
551
            break;
 
552
        }
 
553
    } while (status == True);
 
554
  while (image->previous != (Image *) NULL)
 
555
    image=image->previous;
 
556
  CloseBlob(image);
 
557
  return(image);
 
558
}
 
559
 
 
560
/*
 
561
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
562
%                                                                             %
 
563
%                                                                             %
 
564
%                                                                             %
 
565
%   R e g i s t e r T G A I m a g e                                           %
 
566
%                                                                             %
 
567
%                                                                             %
 
568
%                                                                             %
 
569
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
570
%
 
571
%  Method RegisterTGAImage adds attributes for the TGA image format to
 
572
%  the list of supported formats.  The attributes include the image format
 
573
%  tag, a method to read and/or write the format, whether the format
 
574
%  supports the saving of more than one frame to the same file or blob,
 
575
%  whether the format supports native in-memory I/O, and a brief
 
576
%  description of the format.
 
577
%
 
578
%  The format of the RegisterTGAImage method is:
 
579
%
 
580
%      RegisterTGAImage(void)
 
581
%
 
582
*/
 
583
ModuleExport void RegisterTGAImage(void)
 
584
{
 
585
  MagickInfo
 
586
    *entry;
 
587
 
 
588
  entry=SetMagickInfo("ICB");
 
589
  entry->decoder=(DecoderHandler) ReadTGAImage;
 
590
  entry->encoder=(EncoderHandler) WriteTGAImage;
 
591
  entry->description=AcquireString("Truevision Targa image");
 
592
  entry->module=AcquireString("TGA");
 
593
  (void) RegisterMagickInfo(entry);
 
594
  entry=SetMagickInfo("TGA");
 
595
  entry->decoder=(DecoderHandler) ReadTGAImage;
 
596
  entry->encoder=(EncoderHandler) WriteTGAImage;
 
597
  entry->description=AcquireString("Truevision Targa image");
 
598
  entry->module=AcquireString("TGA");
 
599
  (void) RegisterMagickInfo(entry);
 
600
  entry=SetMagickInfo("VDA");
 
601
  entry->decoder=(DecoderHandler) ReadTGAImage;
 
602
  entry->encoder=(EncoderHandler) WriteTGAImage;
 
603
  entry->description=AcquireString("Truevision Targa image");
 
604
  entry->module=AcquireString("TGA");
 
605
  (void) RegisterMagickInfo(entry);
 
606
  entry=SetMagickInfo("VST");
 
607
  entry->decoder=(DecoderHandler) ReadTGAImage;
 
608
  entry->encoder=(EncoderHandler) WriteTGAImage;
 
609
  entry->description=AcquireString("Truevision Targa image");
 
610
  entry->module=AcquireString("TGA");
 
611
  (void) RegisterMagickInfo(entry);
 
612
}
 
613
 
 
614
/*
 
615
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
616
%                                                                             %
 
617
%                                                                             %
 
618
%                                                                             %
 
619
%   U n r e g i s t e r T G A I m a g e                                       %
 
620
%                                                                             %
 
621
%                                                                             %
 
622
%                                                                             %
 
623
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
624
%
 
625
%  Method UnregisterTGAImage removes format registrations made by the
 
626
%  TGA module from the list of supported formats.
 
627
%
 
628
%  The format of the UnregisterTGAImage method is:
 
629
%
 
630
%      UnregisterTGAImage(void)
 
631
%
 
632
*/
 
633
ModuleExport void UnregisterTGAImage(void)
 
634
{
 
635
  (void) UnregisterMagickInfo("ICB");
 
636
  (void) UnregisterMagickInfo("TGA");
 
637
  (void) UnregisterMagickInfo("VDA");
 
638
  (void) UnregisterMagickInfo("VST");
 
639
}
 
640
 
 
641
/*
 
642
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
643
%                                                                             %
 
644
%                                                                             %
 
645
%                                                                             %
 
646
%   W r i t e T G A I m a g e                                                 %
 
647
%                                                                             %
 
648
%                                                                             %
 
649
%                                                                             %
 
650
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
651
%
 
652
%  Method WriteTGAImage writes a image in the Truevision Targa rasterfile
 
653
%  format.
 
654
%
 
655
%  The format of the WriteTGAImage method is:
 
656
%
 
657
%      unsigned int WriteTGAImage(const ImageInfo *image_info,Image *image)
 
658
%
 
659
%  A description of each parameter follows.
 
660
%
 
661
%    o status: Method WriteTGAImage return True if the image is written.
 
662
%      False is returned is there is a memory shortage or if the image file
 
663
%      fails to write.
 
664
%
 
665
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
666
%
 
667
%    o image:  A pointer to an Image structure.
 
668
%
 
669
%
 
670
*/
 
671
static unsigned int WriteTGAImage(const ImageInfo *image_info,Image *image)
 
672
{
 
673
#define TargaColormap 1
 
674
#define TargaRGB 2
 
675
#define TargaMonochrome 3
 
676
#define TargaRLEColormap  9
 
677
#define TargaRLERGB  10
 
678
#define TargaRLEMonochrome  11
 
679
 
 
680
  typedef struct _TargaInfo
 
681
  {
 
682
    unsigned char
 
683
    id_length,
 
684
      colormap_type,
 
685
      image_type;
 
686
 
 
687
    unsigned short
 
688
    colormap_index,
 
689
      colormap_length;
 
690
 
 
691
    unsigned char
 
692
    colormap_size;
 
693
 
 
694
    unsigned short
 
695
    x_origin,
 
696
      y_origin,
 
697
      width,
 
698
      height;
 
699
 
 
700
    unsigned char
 
701
    bits_per_pixel,
 
702
      attributes;
 
703
  } TargaInfo;
 
704
 
 
705
  const ImageAttribute
 
706
    *attribute;
 
707
 
 
708
  long
 
709
    count,
 
710
    y;
 
711
 
 
712
  register const PixelPacket
 
713
    *p;
 
714
 
 
715
  register IndexPacket
 
716
    *indexes;
 
717
 
 
718
  register long
 
719
    x;
 
720
 
 
721
  register long
 
722
    i;
 
723
 
 
724
  register unsigned char
 
725
    *q;
 
726
 
 
727
  TargaInfo
 
728
    targa_info;
 
729
 
 
730
  unsigned char
 
731
    *targa_pixels;
 
732
 
 
733
  unsigned int
 
734
    write_grayscale,
 
735
    status;
 
736
 
 
737
  unsigned long
 
738
    scene;
 
739
 
 
740
  /*
 
741
    Open output image file.
 
742
  */
 
743
  assert(image_info != (const ImageInfo *) NULL);
 
744
  assert(image_info->signature == MagickSignature);
 
745
  assert(image != (Image *) NULL);
 
746
  assert(image->signature == MagickSignature);
 
747
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
 
748
  if (status == False)
 
749
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
 
750
  scene=0;
 
751
  do
 
752
    {
 
753
      write_grayscale=False;
 
754
 
 
755
      /*
 
756
        If requested output is grayscale, then write grayscale.
 
757
      */
 
758
      if ((image_info->type == GrayscaleType) ||
 
759
          (image_info->type == GrayscaleMatteType))
 
760
        write_grayscale=True;
 
761
 
 
762
      /*
 
763
        Convert colorspace to an RGB-compatible type.
 
764
      */
 
765
      (void) TransformColorspace(image,RGBColorspace);
 
766
 
 
767
      /*
 
768
        If some other type has not been requested and the image is
 
769
        grayscale, then write a grayscale image unless the image
 
770
        contains an alpha channel.
 
771
      */
 
772
      if (((image_info->type != TrueColorType) &&
 
773
           (image_info->type != TrueColorMatteType) &&
 
774
           (image_info->type != PaletteType) &&
 
775
           (image->matte == False)) &&
 
776
          IsGrayImage(image,&image->exception))
 
777
        write_grayscale=True;
 
778
 
 
779
      /*
 
780
        If there are too many colors for colormapped output or the
 
781
        image contains an alpha channel, then promote to TrueColor.
 
782
      */
 
783
      if (((write_grayscale == False) &&
 
784
           (image->storage_class == PseudoClass) &&
 
785
           (image->colors > 256)) ||
 
786
          (image->matte == True))
 
787
        {
 
788
          SyncImage(image);
 
789
          image->storage_class=DirectClass;
 
790
        }
 
791
 
 
792
      /*
 
793
        Initialize TGA raster file header.
 
794
      */
 
795
      targa_info.id_length=0;
 
796
      attribute=GetImageAttribute(image,"comment");
 
797
      if (attribute != (const ImageAttribute *) NULL)
 
798
        targa_info.id_length=Min(strlen(attribute->value),255);
 
799
      targa_info.colormap_type=0;
 
800
      targa_info.colormap_index=0;
 
801
      targa_info.colormap_length=0;
 
802
      targa_info.colormap_size=0;
 
803
      targa_info.x_origin=0;
 
804
      targa_info.y_origin=0;
 
805
      targa_info.width=(unsigned short) image->columns;
 
806
      targa_info.height=(unsigned short) image->rows;
 
807
      targa_info.bits_per_pixel=8;
 
808
      targa_info.attributes=0;
 
809
      if (write_grayscale == True)
 
810
        {
 
811
          /*
 
812
            Grayscale without Colormap
 
813
          */
 
814
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
 
815
                                "Writing Grayscale raster ...");
 
816
          targa_info.image_type=TargaMonochrome;
 
817
          targa_info.bits_per_pixel=8;
 
818
          targa_info.colormap_type=0;
 
819
          targa_info.colormap_index=0;
 
820
          targa_info.colormap_length=0;
 
821
          targa_info.colormap_size=0;   
 
822
        }
 
823
      else if (image->storage_class == DirectClass)
 
824
        {
 
825
          /*
 
826
            Full color TGA raster.
 
827
          */
 
828
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
 
829
                                "Writing TrueColor raster ...");
 
830
 
 
831
          targa_info.image_type=TargaRGB;
 
832
          targa_info.bits_per_pixel=24;
 
833
          if (image->matte)
 
834
            {
 
835
              targa_info.bits_per_pixel=32;
 
836
              targa_info.attributes=8;  /* # of alpha bits */
 
837
            }
 
838
        }
 
839
     else
 
840
        {
 
841
          /*
 
842
            Colormapped TGA raster.
 
843
          */
 
844
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
 
845
                                "Writing ColorMapped raster ..." );
 
846
          targa_info.image_type=TargaColormap;
 
847
          targa_info.colormap_type=1;
 
848
          targa_info.colormap_index=0;
 
849
          targa_info.colormap_length=(unsigned short) image->colors;
 
850
          targa_info.colormap_size=24;
 
851
        }
 
852
      /*
 
853
        Write TGA header.
 
854
      */
 
855
      (void) WriteBlobByte(image,targa_info.id_length);
 
856
      (void) WriteBlobByte(image,targa_info.colormap_type);
 
857
      (void) WriteBlobByte(image,targa_info.image_type);
 
858
      (void) WriteBlobLSBShort(image,targa_info.colormap_index);
 
859
      (void) WriteBlobLSBShort(image,targa_info.colormap_length);
 
860
      (void) WriteBlobByte(image,targa_info.colormap_size);
 
861
      (void) WriteBlobLSBShort(image,targa_info.x_origin);
 
862
      (void) WriteBlobLSBShort(image,targa_info.y_origin);
 
863
      (void) WriteBlobLSBShort(image,targa_info.width);
 
864
      (void) WriteBlobLSBShort(image,targa_info.height);
 
865
      (void) WriteBlobByte(image,targa_info.bits_per_pixel);
 
866
      (void) WriteBlobByte(image,targa_info.attributes);
 
867
      if (targa_info.id_length != 0)
 
868
        (void) WriteBlob(image,targa_info.id_length,attribute->value);
 
869
      if (targa_info.image_type == TargaColormap)
 
870
        {
 
871
          unsigned char
 
872
            *targa_colormap;
 
873
 
 
874
          /*
 
875
            Dump colormap to file (blue, green, red byte order).
 
876
          */
 
877
          targa_colormap=MagickAllocateMemory(unsigned char *,
 
878
                                              3*targa_info.colormap_length);
 
879
          if (targa_colormap == (unsigned char *) NULL)
 
880
            ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
 
881
                                 image);
 
882
          q=targa_colormap;
 
883
          for (i=0; i < (long) image->colors; i++)
 
884
            {
 
885
              *q++=ScaleQuantumToChar(image->colormap[i].blue);
 
886
              *q++=ScaleQuantumToChar(image->colormap[i].green);
 
887
              *q++=ScaleQuantumToChar(image->colormap[i].red);
 
888
            }
 
889
          (void) WriteBlob(image,3*targa_info.colormap_length,
 
890
                           (char *) targa_colormap);
 
891
          MagickFreeMemory(targa_colormap);
 
892
        }
 
893
      /*
 
894
        Convert MIFF to TGA raster pixels.
 
895
      */
 
896
      count=(long) ((targa_info.bits_per_pixel*targa_info.width) >> 3);
 
897
      targa_pixels=MagickAllocateMemory(unsigned char *,count);
 
898
      if (targa_pixels == (unsigned char *) NULL)
 
899
        ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
 
900
      for (y=(long) (image->rows-1); y >= 0; y--)
 
901
        {
 
902
          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
 
903
          if (p == (const PixelPacket *) NULL)
 
904
            break;
 
905
          q=targa_pixels;
 
906
          indexes=GetIndexes(image);
 
907
          for (x=0; x < (long) image->columns; x++)
 
908
            {
 
909
              if (targa_info.image_type == TargaColormap)
 
910
                {
 
911
                  /* Colormapped */
 
912
                  *q++=*indexes;
 
913
                  indexes++;
 
914
                }
 
915
              else if (targa_info.image_type == TargaMonochrome)
 
916
                {
 
917
                  /* Grayscale */
 
918
                  if (image->storage_class == PseudoClass)
 
919
                    {
 
920
                      if (image->is_grayscale)
 
921
                        *q++=ScaleQuantumToChar(image->colormap[*indexes].red);
 
922
                      else
 
923
                        *q++=PixelIntensityToQuantum(&image->colormap[*indexes]);
 
924
                      indexes++;
 
925
                    }
 
926
                  else
 
927
                    {
 
928
                      if (image->is_grayscale)
 
929
                        *q++=ScaleQuantumToChar(p->red);
 
930
                      else
 
931
                        *q++=PixelIntensityToQuantum(p);
 
932
                    }
 
933
                }
 
934
              else
 
935
                {
 
936
                  /* TrueColor RGB */
 
937
                  *q++=ScaleQuantumToChar(p->blue);
 
938
                  *q++=ScaleQuantumToChar(p->green);
 
939
                  *q++=ScaleQuantumToChar(p->red);
 
940
                  if (image->matte)
 
941
                    *q++=ScaleQuantumToChar(MaxRGB-p->opacity);
 
942
                }
 
943
              p++;
 
944
            }
 
945
          (void) WriteBlob(image,q-targa_pixels,(char *) targa_pixels);
 
946
          if (image->previous == (Image *) NULL)
 
947
            if (QuantumTick(y,image->rows))
 
948
              if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
 
949
                break;
 
950
        }
 
951
      MagickFreeMemory(targa_pixels);
 
952
      if (image->next == (Image *) NULL)
 
953
        break;
 
954
      image=SyncNextImageInList(image);
 
955
      if (!MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),&image->exception))
 
956
        break;
 
957
    } while (image_info->adjoin);
 
958
  if (image_info->adjoin)
 
959
    while (image->previous != (Image *) NULL)
 
960
      image=image->previous;
 
961
  CloseBlob(image);
 
962
  return(True);
 
963
}