Coverage Report

Created: 2026-07-20 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/tga.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            TTTTT   GGGG   AAA                               %
7
%                              T    G      A   A                              %
8
%                              T    G  GG  AAAAA                              %
9
%                              T    G   G  A   A                              %
10
%                              T     GGG   A   A                              %
11
%                                                                             %
12
%                                                                             %
13
%                    Read/Write Truevision Targa Image Format                 %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1992                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 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/license/                                         %
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 "MagickCore/studio.h"
43
#include "MagickCore/artifact.h"
44
#include "MagickCore/attribute.h"
45
#include "MagickCore/blob.h"
46
#include "MagickCore/blob-private.h"
47
#include "MagickCore/cache.h"
48
#include "MagickCore/color-private.h"
49
#include "MagickCore/colormap.h"
50
#include "MagickCore/colormap-private.h"
51
#include "MagickCore/colorspace.h"
52
#include "MagickCore/colorspace-private.h"
53
#include "MagickCore/exception.h"
54
#include "MagickCore/exception-private.h"
55
#include "MagickCore/image.h"
56
#include "MagickCore/image-private.h"
57
#include "MagickCore/list.h"
58
#include "MagickCore/magick.h"
59
#include "MagickCore/memory_.h"
60
#include "MagickCore/module.h"
61
#include "MagickCore/monitor.h"
62
#include "MagickCore/monitor-private.h"
63
#include "MagickCore/option.h"
64
#include "MagickCore/pixel-accessor.h"
65
#include "MagickCore/property.h"
66
#include "MagickCore/quantum-private.h"
67
#include "MagickCore/static.h"
68
#include "MagickCore/string_.h"
69
#include "coders/coders-private.h"
70
71
/*
72
  Enumerated declarations.
73
*/
74
typedef enum
75
{
76
  TGAColormap = 1,
77
  TGARGB = 2,
78
  TGAMonochrome = 3,
79
  TGARLEColormap = 9,
80
  TGARLERGB = 10,
81
  TGARLEMonochrome = 11
82
} TGAImageType;
83
84
/*
85
  Typedef declarations.
86
*/
87
typedef struct _TGAInfo
88
{
89
  TGAImageType
90
    image_type;
91
92
  unsigned char
93
    id_length,
94
    colormap_type;
95
96
  unsigned short
97
    colormap_index,
98
    colormap_length;
99
100
  unsigned char
101
    colormap_size;
102
103
  unsigned short
104
    x_origin,
105
    y_origin,
106
    width,
107
    height;
108
109
  unsigned char
110
    bits_per_pixel,
111
    attributes;
112
} TGAInfo;
113

114
/*
115
  Forward declarations.
116
*/
117
static MagickBooleanType
118
  WriteTGAImage(const ImageInfo *,Image *,ExceptionInfo *);
119

120
/*
121
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122
%                                                                             %
123
%                                                                             %
124
%                                                                             %
125
%   R e a d T G A I m a g e                                                   %
126
%                                                                             %
127
%                                                                             %
128
%                                                                             %
129
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130
%
131
%  ReadTGAImage() reads a Truevision TGA image file and returns it.
132
%  It allocates the memory necessary for the new Image structure and returns
133
%  a pointer to the new image.
134
%
135
%  The format of the ReadTGAImage method is:
136
%
137
%      Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
138
%
139
%  A description of each parameter follows:
140
%
141
%    o image_info: the image info.
142
%
143
%    o exception: return any errors or warnings in this structure.
144
%
145
*/
146
static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
147
1.02k
{
148
1.02k
  const char
149
1.02k
    *option;
150
151
1.02k
  Image
152
1.02k
    *image;
153
154
1.02k
  MagickBooleanType
155
1.02k
    flip_x = MagickFalse,
156
1.02k
    flip_y = MagickFalse,
157
1.02k
    status;
158
159
1.02k
  PixelInfo
160
1.02k
    pixel;
161
162
1.02k
  Quantum
163
1.02k
    index,
164
1.02k
    *q;
165
166
1.02k
  size_t
167
1.02k
    base,
168
1.02k
    flag,
169
1.02k
    skip;
170
171
1.02k
  ssize_t
172
1.02k
    count,
173
1.02k
    i,
174
1.02k
    offset,
175
1.02k
    offset_stepsize,
176
1.02k
    x,
177
1.02k
    y;
178
179
1.02k
  TGAInfo
180
1.02k
    tga_info;
181
182
1.02k
  unsigned char
183
1.02k
    j,
184
1.02k
    k,
185
1.02k
    pixels[4],
186
1.02k
    runlength;
187
188
  /*
189
    Open image file.
190
  */
191
1.02k
  assert(image_info != (const ImageInfo *) NULL);
192
1.02k
  assert(image_info->signature == MagickCoreSignature);
193
1.02k
  assert(exception != (ExceptionInfo *) NULL);
194
1.02k
  assert(exception->signature == MagickCoreSignature);
195
1.02k
  if (IsEventLogging() != MagickFalse)
196
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
197
0
      image_info->filename);
198
1.02k
  image=AcquireImage(image_info,exception);
199
1.02k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
200
1.02k
  if (status == MagickFalse)
201
0
    {
202
0
      image=DestroyImageList(image);
203
0
      return((Image *) NULL);
204
0
    }
205
  /*
206
    Read TGA header information.
207
  */
208
1.02k
  count=ReadBlob(image,1,&tga_info.id_length);
209
1.02k
  tga_info.colormap_type=(unsigned char) ReadBlobByte(image);
210
1.02k
  tga_info.image_type=(TGAImageType) ReadBlobByte(image);
211
1.02k
  if ((count != 1) ||
212
1.02k
      ((tga_info.image_type != TGAColormap) &&
213
798
       (tga_info.image_type != TGARGB) &&
214
558
       (tga_info.image_type != TGAMonochrome) &&
215
507
       (tga_info.image_type != TGARLEColormap) &&
216
401
       (tga_info.image_type != TGARLERGB) &&
217
110
       (tga_info.image_type != TGARLEMonochrome)) ||
218
999
      (((tga_info.image_type == TGAColormap) ||
219
776
       (tga_info.image_type == TGARLEColormap)) &&
220
329
       (tga_info.colormap_type == 0)))
221
998
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
222
998
  tga_info.colormap_index=ReadBlobLSBShort(image);
223
998
  tga_info.colormap_length=ReadBlobLSBShort(image);
224
998
  tga_info.colormap_size=(unsigned char) ReadBlobByte(image);
225
998
  tga_info.x_origin=ReadBlobLSBShort(image);
226
998
  tga_info.y_origin=ReadBlobLSBShort(image);
227
998
  tga_info.width=(unsigned short) ReadBlobLSBShort(image);
228
998
  tga_info.height=(unsigned short) ReadBlobLSBShort(image);
229
998
  tga_info.bits_per_pixel=(unsigned char) ReadBlobByte(image);
230
998
  tga_info.attributes=(unsigned char) ReadBlobByte(image);
231
998
  if (EOFBlob(image) != MagickFalse)
232
973
    ThrowReaderException(CorruptImageError,"UnableToReadImageData");
233
973
  if ((((tga_info.bits_per_pixel < 1) || (tga_info.bits_per_pixel >= 17)) &&
234
89
       (tga_info.bits_per_pixel != 24) && (tga_info.bits_per_pixel != 32)))
235
960
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
236
  /*
237
    Initialize image structure.
238
  */
239
960
  image->columns=tga_info.width;
240
960
  image->rows=tga_info.height;
241
960
  if ((tga_info.image_type != TGAMonochrome) &&
242
910
      (tga_info.image_type != TGARLEMonochrome))
243
823
    {
244
823
      unsigned int
245
823
        alpha_bits;
246
247
823
      alpha_bits=(tga_info.attributes & 0x0FU);
248
823
      image->alpha_trait=(alpha_bits > 0) || (tga_info.bits_per_pixel == 32) ||
249
595
        (tga_info.colormap_size == 32) ?  BlendPixelTrait : UndefinedPixelTrait;
250
823
    }
251
960
  if ((tga_info.image_type != TGAColormap) &&
252
754
      (tga_info.image_type != TGARLEColormap))
253
653
    image->depth=(size_t) ((tga_info.bits_per_pixel <= 8) ? 8 :
254
653
      (tga_info.bits_per_pixel <= 16) ? 5 : 8);
255
307
  else
256
307
    image->depth=(size_t) ((tga_info.colormap_size <= 8) ? 8 :
257
307
      (tga_info.colormap_size <= 16) ? 5 : 8);
258
960
  if ((tga_info.image_type == TGAColormap) ||
259
754
      (tga_info.image_type == TGARLEColormap))
260
307
    image->storage_class=PseudoClass;
261
960
  if ((tga_info.image_type == TGAMonochrome) ||
262
910
      (tga_info.image_type == TGARLEMonochrome))
263
137
    (void) SetImageColorspace(image,GRAYColorspace,exception);
264
960
  image->compression=NoCompression;
265
960
  if ((tga_info.image_type == TGARLEColormap) ||
266
859
      (tga_info.image_type == TGARLEMonochrome) ||
267
772
      (tga_info.image_type == TGARLERGB))
268
473
    image->compression=RLECompression;
269
960
  if (image->storage_class == PseudoClass)
270
307
    {
271
307
      if (tga_info.colormap_type != 0)
272
307
        image->colors=tga_info.colormap_index+tga_info.colormap_length;
273
0
      else
274
0
        {
275
0
          size_t
276
0
            one;
277
278
0
          one=1;
279
0
          image->colors=one << tga_info.bits_per_pixel;
280
0
          if ((MagickSizeType) image->colors > GetBlobSize(image))
281
0
            ThrowReaderException(CorruptImageError,
282
0
              "InsufficientImageDataInFile");
283
0
          if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
284
0
            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
285
0
        }
286
307
    }
287
960
  if (tga_info.id_length != 0)
288
231
    {
289
231
      char
290
231
        *comment;
291
292
231
      size_t
293
231
        length;
294
295
      /*
296
        TGA image comment.
297
      */
298
231
      length=(size_t) tga_info.id_length;
299
231
      comment=(char *) NULL;
300
231
      if (~length >= (MagickPathExtent-1))
301
231
        comment=(char *) AcquireQuantumMemory(length+MagickPathExtent,
302
231
          sizeof(*comment));
303
231
      if (comment == (char *) NULL)
304
231
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
305
231
      count=ReadBlob(image,length,(unsigned char *) comment);
306
231
      if (count == (ssize_t) length)
307
132
        {
308
132
          comment[length]='\0';
309
132
          (void) SetImageProperty(image,"comment",comment,exception);
310
132
        }
311
231
      comment=DestroyString(comment);
312
231
    }
313
960
  if ((tga_info.attributes & (1UL << 4)) == 0)
314
576
    {
315
576
      if ((tga_info.attributes & (1UL << 5)) == 0)
316
421
        {
317
421
          image->orientation=BottomLeftOrientation;
318
421
          flip_y=MagickTrue;
319
421
        }
320
155
      else
321
155
        image->orientation=TopLeftOrientation;
322
576
    }
323
384
  else
324
384
    {
325
384
      if ((tga_info.attributes & (1UL << 5)) == 0)
326
109
        {
327
109
          image->orientation=BottomRightOrientation;
328
109
          flip_x=MagickTrue;
329
109
          flip_y=MagickTrue;
330
109
        }
331
275
      else
332
275
        {
333
275
          image->orientation=TopRightOrientation;
334
275
          flip_x=MagickTrue;
335
275
        }
336
384
    }
337
960
  option=GetImageOption(image_info,"tga:preserve-orientation");
338
960
  if (IsStringTrue(option) != MagickFalse)
339
0
    {
340
0
      flip_x=MagickFalse;
341
0
      flip_y=MagickFalse;
342
0
    }
343
960
  else
344
960
    image->orientation=TopLeftOrientation;
345
960
  if (image_info->ping != MagickFalse)
346
0
    {
347
0
      (void) CloseBlob(image);
348
0
      return(image);
349
0
    }
350
960
  status=SetImageExtent(image,image->columns,image->rows,exception);
351
960
  if (status == MagickFalse)
352
48
    return(DestroyImageList(image));
353
912
  GetPixelInfo(image,&pixel);
354
912
  if (tga_info.colormap_type != 0)
355
736
    {
356
      /*
357
        Read TGA raster colormap.
358
      */
359
736
      if (image->colors < tga_info.colormap_index)
360
437
        image->colors=tga_info.colormap_index;
361
736
      if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
362
734
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
363
11.8M
      for (i=0; i < (ssize_t) tga_info.colormap_index; i++)
364
11.8M
        image->colormap[i]=pixel;
365
1.58M
      for ( ; i < (ssize_t) image->colors; i++)
366
1.57M
      {
367
1.57M
        switch (tga_info.colormap_size)
368
1.57M
        {
369
0
          case 8:
370
655k
          default:
371
655k
          {
372
            /*
373
              Gray scale.
374
            */
375
655k
            pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
376
655k
              ReadBlobByte(image));
377
655k
            pixel.green=pixel.red;
378
655k
            pixel.blue=pixel.red;
379
655k
            break;
380
0
          }
381
191k
          case 15:
382
276k
          case 16:
383
276k
          {
384
276k
            QuantumAny
385
276k
              range;
386
387
            /*
388
              5 bits each of red green and blue.
389
            */
390
276k
            j=(unsigned char) ReadBlobByte(image);
391
276k
            k=(unsigned char) ReadBlobByte(image);
392
276k
            range=GetQuantumRange(5UL);
393
276k
            pixel.red=(MagickRealType) ScaleAnyToQuantum(1UL*(k & 0x7c) >> 2,
394
276k
              range);
395
276k
            pixel.green=(MagickRealType) ScaleAnyToQuantum((1UL*(k & 0x03)
396
276k
              << 3)+(1UL*(j & 0xe0) >> 5),range);
397
276k
            pixel.blue=(MagickRealType) ScaleAnyToQuantum(1UL*(j & 0x1f),range);
398
276k
            break;
399
191k
          }
400
261k
          case 24:
401
261k
          {
402
            /*
403
              8 bits each of blue, green and red.
404
            */
405
261k
            pixel.blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
406
261k
              ReadBlobByte(image));
407
261k
            pixel.green=(MagickRealType) ScaleCharToQuantum((unsigned char)
408
261k
              ReadBlobByte(image));
409
261k
            pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
410
261k
              ReadBlobByte(image));
411
261k
            break;
412
191k
          }
413
386k
          case 32:
414
386k
          {
415
            /*
416
              8 bits each of blue, green, red, and alpha.
417
            */
418
386k
            pixel.blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
419
386k
              ReadBlobByte(image));
420
386k
            pixel.green=(MagickRealType) ScaleCharToQuantum((unsigned char)
421
386k
              ReadBlobByte(image));
422
386k
            pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
423
386k
              ReadBlobByte(image));
424
386k
            pixel.alpha=(MagickRealType) ScaleCharToQuantum((unsigned char)
425
386k
              ReadBlobByte(image));
426
386k
            break;
427
191k
          }
428
1.57M
        }
429
1.57M
        image->colormap[i]=pixel;
430
1.57M
      }
431
734
    }
432
  /*
433
    Convert TGA pixels to pixel packets.
434
  */
435
910
  base=0;
436
910
  flag=0;
437
910
  skip=MagickFalse;
438
910
  index=0;
439
910
  runlength=0;
440
910
  offset=0;
441
910
  offset_stepsize=1;
442
910
  if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 2)
443
100
    offset_stepsize=2;
444
51.6k
  for (y=0; y < (ssize_t) image->rows; y++)
445
51.0k
  {
446
51.0k
    ssize_t
447
51.0k
      y_offset=(flip_y == MagickFalse) ? offset : (ssize_t) image->rows-
448
23.8k
        1-offset;
449
450
51.0k
    q=QueueAuthenticPixels(image,0,y_offset,image->columns,1,exception);
451
51.0k
    if (q == (Quantum *) NULL)
452
0
      break;
453
51.0k
    if (flip_x != MagickFalse)
454
24.8k
      q+=(ptrdiff_t) GetPixelChannels(image)*(image->columns-1);
455
4.31M
    for (x=0; x < (ssize_t) image->columns; x++)
456
4.26M
    {
457
4.26M
      if ((tga_info.image_type == TGARLEColormap) ||
458
3.56M
          (tga_info.image_type == TGARLERGB) ||
459
1.30M
          (tga_info.image_type == TGARLEMonochrome))
460
4.13M
        {
461
4.13M
          if (runlength != 0)
462
4.10M
            {
463
4.10M
              runlength--;
464
4.10M
              skip=flag != 0;
465
4.10M
            }
466
35.3k
          else
467
35.3k
            {
468
35.3k
              count=ReadBlob(image,1,&runlength);
469
35.3k
              if (count != 1)
470
35.2k
                ThrowReaderException(CorruptImageError,"UnableToReadImageData");
471
35.2k
              flag=runlength & 0x80;
472
35.2k
              if (flag != 0)
473
30.9k
                runlength-=128;
474
35.2k
              skip=MagickFalse;
475
35.2k
            }
476
4.13M
        }
477
4.26M
      if (skip == MagickFalse)
478
429k
        switch (tga_info.bits_per_pixel)
479
429k
        {
480
404k
          case 1:
481
404k
          {
482
404k
            if ((x & 0x07) == 0)
483
49.6k
              {
484
49.6k
                if (ReadBlob(image,1,pixels) != 1)
485
65
                  ThrowReaderException(CorruptImageError,
486
49.6k
                    "UnableToReadImageData");
487
49.5k
                index=(Quantum) pixels[0];
488
49.5k
              }
489
354k
            else
490
354k
              index=(Quantum) ((size_t) index << 1);
491
404k
            if (tga_info.colormap_type != 0)
492
168k
              pixel=image->colormap[(ssize_t) ConstrainColormapIndex(image,
493
168k
                ((unsigned char) index) & 0x80 ? 1 : 0,exception)];
494
235k
            else
495
235k
              {
496
235k
                pixel.red=(MagickRealType) (((unsigned char) index) & 0x80 ?
497
121k
                  QuantumRange : 0);
498
235k
                pixel.green=pixel.red;
499
235k
                pixel.blue=pixel.red;
500
235k
              }
501
404k
            break;
502
404k
          }
503
117
          case 8:
504
3.28k
          default:
505
3.28k
          {
506
            /*
507
              Gray scale.
508
            */
509
3.28k
            if (ReadBlob(image,1,pixels) != 1)
510
3.19k
              ThrowReaderException(CorruptImageError,"UnableToReadImageData");
511
3.19k
            index=(Quantum) pixels[0];
512
3.19k
            if (tga_info.colormap_type != 0)
513
2.89k
              pixel=image->colormap[(ssize_t) ConstrainColormapIndex(image,
514
2.89k
                (ssize_t) index,exception)];
515
299
            else
516
299
              {
517
299
                pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
518
299
                  index);
519
299
                pixel.green=pixel.red;
520
299
                pixel.blue=pixel.red;
521
299
              }
522
3.19k
            break;
523
3.28k
          }
524
1.66k
          case 15:
525
19.4k
          case 16:
526
19.4k
          {
527
19.4k
            QuantumAny
528
19.4k
              range;
529
530
            /*
531
              5 bits each of RGB.
532
            */
533
19.4k
            if (ReadBlob(image,2,pixels) != 2)
534
19.3k
              ThrowReaderException(CorruptImageError,"UnableToReadImageData");
535
19.3k
            j=pixels[0];
536
19.3k
            k=pixels[1];
537
19.3k
            range=GetQuantumRange(5UL);
538
19.3k
            pixel.red=(MagickRealType) ScaleAnyToQuantum(1UL*(k & 0x7c) >> 2,
539
19.3k
              range);
540
19.3k
            pixel.green=(MagickRealType) ScaleAnyToQuantum((1UL*
541
19.3k
              (k & 0x03) << 3)+(1UL*(j & 0xe0) >> 5),range);
542
19.3k
            pixel.blue=(MagickRealType) ScaleAnyToQuantum(1UL*(j & 0x1f),range);
543
19.3k
            if (image->alpha_trait != UndefinedPixelTrait)
544
1.60k
              pixel.alpha=(MagickRealType) ((k & 0x80) == 0 ? (Quantum)
545
1.17k
                TransparentAlpha : (Quantum) OpaqueAlpha);
546
19.3k
            if (image->storage_class == PseudoClass)
547
924
              index=(Quantum) ConstrainColormapIndex(image,((ssize_t) k << 8)+
548
924
                j,exception);
549
19.3k
            break;
550
19.4k
          }
551
583
          case 24:
552
583
          {
553
            /*
554
              BGR pixels.
555
            */
556
583
            if (ReadBlob(image,3,pixels) != 3)
557
577
              ThrowReaderException(CorruptImageError,"UnableToReadImageData");
558
577
            pixel.blue=(MagickRealType) ScaleCharToQuantum(pixels[0]);
559
577
            pixel.green=(MagickRealType) ScaleCharToQuantum(pixels[1]);
560
577
            pixel.red=(MagickRealType) ScaleCharToQuantum(pixels[2]);
561
577
            break;
562
583
          }
563
1.90k
          case 32:
564
1.90k
          {
565
            /*
566
              BGRA pixels.
567
            */
568
1.90k
            if (ReadBlob(image,4,pixels) != 4)
569
1.88k
              ThrowReaderException(CorruptImageError,"UnableToReadImageData");
570
1.88k
            pixel.blue=(MagickRealType) ScaleCharToQuantum(pixels[0]);
571
1.88k
            pixel.green=(MagickRealType) ScaleCharToQuantum(pixels[1]);
572
1.88k
            pixel.red=(MagickRealType) ScaleCharToQuantum(pixels[2]);
573
1.88k
            pixel.alpha=(MagickRealType) ScaleCharToQuantum(pixels[3]);
574
1.88k
            break;
575
1.90k
          }
576
429k
        }
577
4.26M
      if (status == MagickFalse)
578
4.26M
        ThrowReaderException(CorruptImageError,"UnableToReadImageData");
579
4.26M
      if (image->storage_class == PseudoClass)
580
3.23M
        SetPixelIndex(image,index,q);
581
4.26M
      SetPixelRed(image,ClampToQuantum(pixel.red),q);
582
4.26M
      SetPixelGreen(image,ClampToQuantum(pixel.green),q);
583
4.26M
      SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
584
4.26M
      if (image->alpha_trait != UndefinedPixelTrait)
585
1.47M
        SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
586
4.26M
      if (flip_x != MagickFalse)
587
924k
        q-=GetPixelChannels(image);
588
3.33M
      else
589
3.33M
        q+=(ptrdiff_t) GetPixelChannels(image);
590
4.26M
    }
591
50.7k
    offset+=offset_stepsize;
592
50.7k
    if (offset >= (ssize_t) image->rows)
593
620
      {
594
620
        base++;
595
620
        offset=(ssize_t) base;
596
620
      }
597
50.7k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
598
0
      break;
599
50.7k
    if (image->previous == (Image *) NULL)
600
50.7k
      {
601
50.7k
        status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
602
50.7k
          image->rows);
603
50.7k
        if (status == MagickFalse)
604
0
          break;
605
50.7k
      }
606
50.7k
  }
607
581
  if (EOFBlob(image) != MagickFalse)
608
0
    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
609
581
      image->filename);
610
581
  if (SeekBlob(image,-26,SEEK_END) >= 18)
611
252
    {
612
      /*
613
        Optional header.
614
      */
615
252
      char
616
252
        signature[18];
617
618
252
      unsigned long
619
252
        extension;
620
621
252
      extension=(unsigned long) ReadBlobLSBLong(image);
622
252
      (void) ReadBlobLSBLong(image);
623
252
      count=ReadBlob(image,18,signature);
624
252
      if ((count == 18) && (extension > 3) &&
625
241
          (LocaleCompare(signature,"TRUEVISION-XFILE.") == 0) &&
626
102
          (SeekBlob(image,(MagickOffsetType) extension,SEEK_SET) == (MagickOffsetType) extension) &&
627
102
          (ReadBlobLSBShort(image) == 495))
628
34
        {
629
          /*
630
            Optional extension.
631
          */
632
34
          char
633
34
            buffer[325];
634
635
34
          (void) ReadBlob(image,41,buffer);
636
34
          buffer[41]='\0';
637
34
          (void) SetImageProperty(image,"tga:author",buffer,exception);
638
34
          (void) ReadBlob(image,324,buffer);
639
34
          buffer[324]='\0';
640
34
          (void) SetImageProperty(image,"tga:comment",buffer,exception);
641
34
          (void) DiscardBlobBytes(image,59);
642
34
          (void) ReadBlob(image,41,buffer);
643
34
          buffer[41]='\0';
644
34
          (void) SetImageProperty(image,"tga:software",buffer,exception);
645
34
          (void) DiscardBlobBytes(image,27);
646
34
          if (((image->alpha_trait & BlendPixelTrait) != 0) &&
647
26
              (ReadBlobByte(image) != 3))
648
24
            image->alpha_trait=UndefinedPixelTrait;
649
34
        }
650
252
    }
651
581
  if (CloseBlob(image) == MagickFalse)
652
0
    status=MagickFalse;
653
581
  if (status == MagickFalse)
654
0
    return(DestroyImageList(image));
655
581
  return(GetFirstImageInList(image));
656
581
}
657

658
/*
659
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
660
%                                                                             %
661
%                                                                             %
662
%                                                                             %
663
%   R e g i s t e r T G A I m a g e                                           %
664
%                                                                             %
665
%                                                                             %
666
%                                                                             %
667
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
668
%
669
%  RegisterTGAImage() adds properties for the TGA image format to
670
%  the list of supported formats.  The properties include the image format
671
%  tag, a method to read and/or write the format, whether the format
672
%  supports the saving of more than one frame to the same file or blob,
673
%  whether the format supports native in-memory I/O, and a brief
674
%  description of the format.
675
%
676
%  The format of the RegisterTGAImage method is:
677
%
678
%      size_t RegisterTGAImage(void)
679
%
680
*/
681
ModuleExport size_t RegisterTGAImage(void)
682
8
{
683
8
  MagickInfo
684
8
    *entry;
685
686
8
  entry=AcquireMagickInfo("TGA","ICB","Truevision Targa image");
687
8
  entry->decoder=(DecodeImageHandler *) ReadTGAImage;
688
8
  entry->encoder=(EncodeImageHandler *) WriteTGAImage;
689
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
690
8
  entry->flags^=CoderAdjoinFlag;
691
8
  (void) RegisterMagickInfo(entry);
692
8
  entry=AcquireMagickInfo("TGA","TGA","Truevision Targa image");
693
8
  entry->decoder=(DecodeImageHandler *) ReadTGAImage;
694
8
  entry->encoder=(EncodeImageHandler *) WriteTGAImage;
695
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
696
8
  entry->flags^=CoderAdjoinFlag;
697
8
  (void) RegisterMagickInfo(entry);
698
8
  entry=AcquireMagickInfo("TGA","VDA","Truevision Targa image");
699
8
  entry->decoder=(DecodeImageHandler *) ReadTGAImage;
700
8
  entry->encoder=(EncodeImageHandler *) WriteTGAImage;
701
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
702
8
  entry->flags^=CoderAdjoinFlag;
703
8
  (void) RegisterMagickInfo(entry);
704
8
  entry=AcquireMagickInfo("TGA","VST","Truevision Targa image");
705
8
  entry->decoder=(DecodeImageHandler *) ReadTGAImage;
706
8
  entry->encoder=(EncodeImageHandler *) WriteTGAImage;
707
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
708
8
  entry->flags^=CoderAdjoinFlag;
709
8
  (void) RegisterMagickInfo(entry);
710
8
  return(MagickImageCoderSignature);
711
8
}
712

713
/*
714
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715
%                                                                             %
716
%                                                                             %
717
%                                                                             %
718
%   U n r e g i s t e r T G A I m a g e                                       %
719
%                                                                             %
720
%                                                                             %
721
%                                                                             %
722
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723
%
724
%  UnregisterTGAImage() removes format registrations made by the
725
%  TGA module from the list of supported formats.
726
%
727
%  The format of the UnregisterTGAImage method is:
728
%
729
%      UnregisterTGAImage(void)
730
%
731
*/
732
ModuleExport void UnregisterTGAImage(void)
733
0
{
734
0
  (void) UnregisterMagickInfo("ICB");
735
0
  (void) UnregisterMagickInfo("TGA");
736
0
  (void) UnregisterMagickInfo("VDA");
737
0
  (void) UnregisterMagickInfo("VST");
738
0
}
739

740
/*
741
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
742
%                                                                             %
743
%                                                                             %
744
%                                                                             %
745
%   W r i t e T G A I m a g e                                                 %
746
%                                                                             %
747
%                                                                             %
748
%                                                                             %
749
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750
%
751
%  WriteTGAImage() writes a image in the Truevision Targa rasterfile
752
%  format.
753
%
754
%  The format of the WriteTGAImage method is:
755
%
756
%      MagickBooleanType WriteTGAImage(const ImageInfo *image_info,
757
%        Image *image,ExceptionInfo *exception)
758
%
759
%  A description of each parameter follows.
760
%
761
%    o image_info: the image info.
762
%
763
%    o image:  The image.
764
%
765
*/
766
static inline void WriteTGAPixel(Image *image,TGAImageType image_type,
767
  const Quantum *p,const QuantumAny range,const double midpoint)
768
439k
{
769
439k
  if (image_type == TGAColormap || image_type == TGARLEColormap)
770
30.5k
    (void) WriteBlobByte(image,(unsigned char) ((ssize_t)
771
30.5k
       GetPixelIndex(image,p)));
772
409k
  else
773
409k
    {
774
409k
      if (image_type == TGAMonochrome || image_type == TGARLEMonochrome)
775
36.6k
        (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
776
36.6k
          GetPixelLuma(image,p))));
777
372k
      else
778
372k
        if (image->depth == 5)
779
12.6k
          {
780
12.6k
            unsigned char
781
12.6k
              green,
782
12.6k
              value;
783
784
12.6k
            green=(unsigned char) ScaleQuantumToAny(GetPixelGreen(image,p),
785
12.6k
              range);
786
12.6k
            value=((unsigned char) ScaleQuantumToAny(GetPixelBlue(image,p),
787
12.6k
              range)) | ((green & 0x07) << 5);
788
12.6k
            (void) WriteBlobByte(image,value);
789
12.6k
            value=(((image->alpha_trait != UndefinedPixelTrait) &&
790
10.7k
              ((double) GetPixelAlpha(image,p) > midpoint)) ? 0x80 : 0) |
791
12.6k
              ((unsigned char) ScaleQuantumToAny(GetPixelRed(image,p),range) <<
792
12.6k
              2) | ((green & 0x18) >> 3);
793
12.6k
            (void) WriteBlobByte(image,value);
794
12.6k
          }
795
360k
        else
796
360k
          {
797
360k
            (void) WriteBlobByte(image,ScaleQuantumToChar(
798
360k
              GetPixelBlue(image,p)));
799
360k
            (void) WriteBlobByte(image,ScaleQuantumToChar(
800
360k
              GetPixelGreen(image,p)));
801
360k
            (void) WriteBlobByte(image,ScaleQuantumToChar(
802
360k
              GetPixelRed(image,p)));
803
360k
            if (image->alpha_trait != UndefinedPixelTrait)
804
358k
              (void) WriteBlobByte(image,ScaleQuantumToChar(
805
358k
                GetPixelAlpha(image,p)));
806
360k
          }
807
409k
    }
808
439k
}
809
810
static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image,
811
  ExceptionInfo *exception)
812
557
{
813
557
  CompressionType
814
557
    compression;
815
816
557
  const char
817
557
    *comment,
818
557
    *option;
819
820
557
  const double
821
557
    midpoint = (double) QuantumRange/2.0;
822
823
557
  const Quantum
824
557
    *p;
825
826
557
  MagickBooleanType
827
557
    status;
828
829
557
  QuantumAny
830
557
    range;
831
832
557
  size_t
833
557
    channels;
834
835
557
  ssize_t
836
557
    base,
837
557
    count,
838
557
    i,
839
557
    offset,
840
557
    x,
841
557
    y;
842
843
557
  TGAInfo
844
557
    tga_info;
845
846
557
  unsigned char
847
557
    *q;
848
849
  /*
850
    Open output image file.
851
  */
852
557
  assert(image_info != (const ImageInfo *) NULL);
853
557
  assert(image_info->signature == MagickCoreSignature);
854
557
  assert(image != (Image *) NULL);
855
557
  assert(image->signature == MagickCoreSignature);
856
557
  assert(exception != (ExceptionInfo *) NULL);
857
557
  assert(exception->signature == MagickCoreSignature);
858
557
  if (IsEventLogging() != MagickFalse)
859
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
860
557
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
861
557
  if (status == MagickFalse)
862
0
    return(status);
863
  /*
864
    Initialize TGA raster file header.
865
  */
866
557
  if ((image->columns > 65535L) || (image->rows > 65535L))
867
557
    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
868
557
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
869
0
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
870
557
  compression=image->compression;
871
557
  if (image_info->compression != UndefinedCompression)
872
0
    compression=image_info->compression;
873
557
  range=GetQuantumRange(5UL);
874
557
  tga_info.id_length=0;
875
557
  comment=GetImageProperty(image,"comment",exception);
876
557
  if (comment != (const char *) NULL)
877
107
    tga_info.id_length=(unsigned char) MagickMin(strlen(comment),255);
878
557
  tga_info.colormap_type=0;
879
557
  tga_info.colormap_index=0;
880
557
  tga_info.colormap_length=0;
881
557
  tga_info.colormap_size=0;
882
557
  tga_info.x_origin=0;
883
557
  tga_info.y_origin=0;
884
557
  tga_info.width=(unsigned short) image->columns;
885
557
  tga_info.height=(unsigned short) image->rows;
886
557
  tga_info.bits_per_pixel=8;
887
557
  tga_info.attributes=0;
888
557
  if ((image_info->type != TrueColorType) &&
889
557
      (image_info->type != TrueColorAlphaType) &&
890
557
      (image_info->type != PaletteType) &&
891
557
      ((image->alpha_trait & BlendPixelTrait) == 0) &&
892
214
      (IdentifyImageCoderGray(image,exception) != MagickFalse))
893
146
    tga_info.image_type=compression == RLECompression ? TGARLEMonochrome :
894
146
      TGAMonochrome;
895
411
  else
896
411
    if ((image->storage_class == DirectClass) || (image->colors > 256))
897
252
      {
898
        /*
899
          Full color TGA raster.
900
        */
901
252
        tga_info.image_type=compression == RLECompression ? TGARLERGB : TGARGB;
902
252
        if (image_info->depth == 5)
903
0
          {
904
0
            tga_info.bits_per_pixel=16;
905
0
            if (image->alpha_trait != UndefinedPixelTrait)
906
0
              tga_info.attributes=1;  /* # of alpha bits */
907
0
          }
908
252
        else
909
252
          {
910
252
            tga_info.bits_per_pixel=24;
911
252
            if (image->alpha_trait != UndefinedPixelTrait)
912
194
              {
913
194
                tga_info.bits_per_pixel=32;
914
194
                tga_info.attributes=8;  /* # of alpha bits */
915
194
              }
916
252
          }
917
252
      }
918
159
    else
919
159
      {
920
        /*
921
          Colormapped TGA raster.
922
        */
923
159
        tga_info.image_type=compression == RLECompression ? TGARLEColormap :
924
159
          TGAColormap;
925
159
        tga_info.colormap_type=1;
926
159
        tga_info.colormap_length=(unsigned short) image->colors;
927
159
        if (image_info->depth == 5)
928
0
          tga_info.colormap_size=16;
929
159
        else
930
159
          if (image->alpha_trait != UndefinedPixelTrait)
931
149
            tga_info.colormap_size=32;
932
10
          else
933
10
            tga_info.colormap_size=24;
934
159
      }
935
557
  switch (image->orientation)
936
557
  {
937
0
    case BottomRightOrientation:
938
0
    {
939
0
      tga_info.attributes|=0x10;
940
0
      break;
941
0
    }
942
0
    case UndefinedOrientation:
943
557
    case TopLeftOrientation:
944
557
    {
945
557
      tga_info.attributes|=0x20;
946
557
      break;
947
0
    }
948
0
    case TopRightOrientation:
949
0
    {
950
0
      tga_info.attributes|=0x30;
951
0
      break;
952
0
    }
953
0
    default:
954
0
      break;
955
557
  }
956
557
  if ((image->columns > 65535) || (image->rows > 65535))
957
557
    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
958
  /*
959
    Write TGA header.
960
  */
961
557
  (void) WriteBlobByte(image,tga_info.id_length);
962
557
  (void) WriteBlobByte(image,tga_info.colormap_type);
963
557
  (void) WriteBlobByte(image,(unsigned char) tga_info.image_type);
964
557
  (void) WriteBlobLSBShort(image,tga_info.colormap_index);
965
557
  (void) WriteBlobLSBShort(image,tga_info.colormap_length);
966
557
  (void) WriteBlobByte(image,tga_info.colormap_size);
967
557
  (void) WriteBlobLSBShort(image,tga_info.x_origin);
968
557
  (void) WriteBlobLSBShort(image,tga_info.y_origin);
969
557
  (void) WriteBlobLSBShort(image,tga_info.width);
970
557
  (void) WriteBlobLSBShort(image,tga_info.height);
971
557
  (void) WriteBlobByte(image,tga_info.bits_per_pixel);
972
557
  (void) WriteBlobByte(image,tga_info.attributes);
973
557
  if (tga_info.id_length != 0)
974
89
    (void) WriteBlob(image,tga_info.id_length,(unsigned char *) comment);
975
557
  if (tga_info.colormap_type != 0)
976
159
    {
977
159
      unsigned char
978
159
        green,
979
159
        *targa_colormap;
980
981
      /*
982
        Dump colormap to file (blue, green, red byte order).
983
      */
984
159
      targa_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
985
159
        tga_info.colormap_length,(tga_info.colormap_size/8)*
986
159
        sizeof(*targa_colormap));
987
159
      if (targa_colormap == (unsigned char *) NULL)
988
159
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
989
159
      q=targa_colormap;
990
15.9k
      for (i=0; i < (ssize_t) image->colors; i++)
991
15.8k
      {
992
15.8k
        if (image_info->depth == 5)
993
0
          {
994
0
            green=(unsigned char) ScaleQuantumToAny(ClampToQuantum(
995
0
              image->colormap[i].green),range);
996
0
            *q++=((unsigned char) ScaleQuantumToAny(ClampToQuantum(
997
0
              image->colormap[i].blue),range)) | ((green & 0x07) << 5);
998
0
            *q++=(((image->alpha_trait != UndefinedPixelTrait) && ((double)
999
0
              ClampToQuantum(image->colormap[i].alpha) > midpoint)) ?
1000
0
              0x80 : 0) | ((unsigned char) ScaleQuantumToAny(ClampToQuantum(
1001
0
              image->colormap[i].red),range) << 2) | ((green & 0x18) >> 3);
1002
0
          }
1003
15.8k
        else
1004
15.8k
          {
1005
15.8k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
1006
15.8k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
1007
15.8k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
1008
15.8k
            if (image->alpha_trait != UndefinedPixelTrait)
1009
15.1k
              *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].alpha));
1010
15.8k
          }
1011
15.8k
      }
1012
159
      (void) WriteBlob(image,(size_t) ((tga_info.colormap_size/8)*
1013
159
        tga_info.colormap_length),targa_colormap);
1014
159
      targa_colormap=(unsigned char *) RelinquishMagickMemory(targa_colormap);
1015
159
    }
1016
  /*
1017
    Convert MIFF to TGA raster pixels.
1018
  */
1019
557
  base=0;
1020
557
  offset=0;
1021
557
  channels=GetPixelChannels(image);
1022
46.8k
  for (y=0; y < (ssize_t) image->rows; y++)
1023
46.2k
  {
1024
46.2k
    p=GetVirtualPixels(image,0,offset,image->columns,1,exception);
1025
46.2k
    if (p == (const Quantum *) NULL)
1026
0
      break;
1027
46.2k
    if (compression == RLECompression)
1028
44.1k
      {
1029
44.1k
        x=0;
1030
44.1k
        count=0;
1031
301k
        while (x < (ssize_t) image->columns)
1032
257k
        {
1033
257k
          i=1;
1034
3.54M
          while ((i < 128) && (count + i < 128) &&
1035
3.52M
                 ((x + i) < (ssize_t) image->columns))
1036
3.47M
          {
1037
3.47M
            if (tga_info.image_type == TGARLEColormap)
1038
134k
              {
1039
134k
                if (GetPixelIndex(image,p+(i*(ssize_t) channels)) !=
1040
134k
                    GetPixelIndex(image,p+((i-1)*(ssize_t) channels)))
1041
26.1k
                  break;
1042
134k
              }
1043
3.34M
            else
1044
3.34M
              if (tga_info.image_type == TGARLEMonochrome)
1045
2.28M
                {
1046
2.28M
                  if (GetPixelLuma(image,p+(i*(ssize_t) channels)) !=
1047
2.28M
                      GetPixelLuma(image,p+((i-1)*(ssize_t) channels)))
1048
335
                    break;
1049
2.28M
                }
1050
1.06M
              else
1051
1.06M
                {
1052
1.06M
                  if ((GetPixelBlue(image,p+(i*(ssize_t) channels)) !=
1053
1.06M
                       GetPixelBlue(image,p+((i-1)*(ssize_t) channels))) ||
1054
899k
                      (GetPixelGreen(image,p+(i*(ssize_t) channels)) !=
1055
899k
                       GetPixelGreen(image,p+((i-1)*(ssize_t) channels))) ||
1056
898k
                      (GetPixelRed(image,p+(i*(ssize_t) channels)) !=
1057
898k
                       GetPixelRed(image,p+((i-1)*(ssize_t) channels))))
1058
163k
                    break;
1059
897k
                  if ((image->alpha_trait != UndefinedPixelTrait) &&
1060
878k
                      (GetPixelAlpha(image,p+(i*(ssize_t) channels)) !=
1061
878k
                       GetPixelAlpha(image,p+(i-1)*(ssize_t) channels)))
1062
198
                    break;
1063
897k
                }
1064
3.28M
            i++;
1065
3.28M
          }
1066
257k
          if (i < 3)
1067
217k
            {
1068
217k
              count+=i;
1069
217k
              p+=(ptrdiff_t) (i*(ssize_t) channels);
1070
217k
            }
1071
257k
          if ((i >= 3) || (count == 128) ||
1072
216k
              ((x + i) == (ssize_t) image->columns))
1073
71.1k
            {
1074
71.1k
              if (count > 0)
1075
35.0k
                {
1076
35.0k
                  (void) WriteBlobByte(image,(unsigned char) (--count));
1077
316k
                  while (count >= 0)
1078
281k
                  {
1079
281k
                    WriteTGAPixel(image,tga_info.image_type,p-
1080
281k
                      ((count+1)*(ssize_t) channels),range,midpoint);
1081
281k
                    count--;
1082
281k
                  }
1083
35.0k
                  count=0;
1084
35.0k
                }
1085
71.1k
            }
1086
257k
          if (i >= 3)
1087
39.5k
            {
1088
39.5k
              (void) WriteBlobByte(image,(unsigned char) ((i-1) | 0x80));
1089
39.5k
              WriteTGAPixel(image,tga_info.image_type,p,range,midpoint);
1090
39.5k
              p+=(ptrdiff_t) (i*(ssize_t) channels);
1091
39.5k
            }
1092
257k
          x+=i;
1093
257k
        }
1094
44.1k
      }
1095
2.08k
    else
1096
121k
      for (x=0; x < (ssize_t) image->columns; x++)
1097
119k
      {
1098
119k
        WriteTGAPixel(image,tga_info.image_type,p,range,midpoint);
1099
119k
        p+=(ptrdiff_t) channels;
1100
119k
      }
1101
46.2k
     if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 2)
1102
0
       offset+=2;
1103
46.2k
     else
1104
46.2k
       offset++;
1105
46.2k
      if (offset >= (ssize_t) image->rows)
1106
557
        {
1107
557
          base++;
1108
557
          offset=base;
1109
557
        }
1110
46.2k
    if (image->previous == (Image *) NULL)
1111
46.2k
      {
1112
46.2k
        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1113
46.2k
          image->rows);
1114
46.2k
        if (status == MagickFalse)
1115
0
          break;
1116
46.2k
      }
1117
46.2k
  }
1118
  /*
1119
    Optional footer.
1120
  */
1121
557
  option=GetImageOption(image_info,"tga:write-footer");
1122
557
  if (IsStringTrue(option) != MagickFalse)
1123
0
    {
1124
0
      WriteBlobLong(image,0);
1125
0
      WriteBlobLong(image,0);
1126
0
      WriteBlobString(image,"TRUEVISION-XFILE.");
1127
0
      WriteBlobByte(image,0);
1128
0
    }
1129
557
  if (CloseBlob(image) == MagickFalse)
1130
0
    status=MagickFalse;
1131
557
  return(status);
1132
557
}