Coverage Report

Created: 2026-11-12 07:35

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