Coverage Report

Created: 2026-05-24 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/avs.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                             AAA   V   V  SSSSS                              %
15
%                            A   A  V   V  SS                                 %
16
%                            AAAAA  V   V   SSS                               %
17
%                            A   A   V V      SS                              %
18
%                            A   A    V    SSSSS                              %
19
%                                                                             %
20
%                                                                             %
21
%                        Read/Write AVS X Image Format.                       %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
27
%                                                                             %
28
%                                                                             %
29
%                                                                             %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31
%
32
%
33
*/
34

35
/*
36
  Include declarations.
37
*/
38
#include "magick/studio.h"
39
#include "magick/blob.h"
40
#include "magick/log.h"
41
#include "magick/magick.h"
42
#include "magick/monitor.h"
43
#include "magick/pixel_cache.h"
44
#include "magick/utility.h"
45
#include "magick/static.h"
46

47
/*
48
  Forward declarations.
49
*/
50
static unsigned int
51
  WriteAVSImage(const ImageInfo *,Image *);
52

53
/*
54
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55
%                                                                             %
56
%                                                                             %
57
%                                                                             %
58
%   R e a d A V S I m a g e                                                   %
59
%                                                                             %
60
%                                                                             %
61
%                                                                             %
62
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63
%
64
%  Method ReadAVSImage reads an AVS X image file and returns it.  It
65
%  allocates the memory necessary for the new Image structure and returns a
66
%  pointer to the new image.  Note that these files often have the extension
67
%  'X' which conflicts with our X11 support coder.
68
%
69
%  The format of the ReadAVSImage method is:
70
%
71
%      Image *ReadAVSImage(const ImageInfo *image_info,ExceptionInfo *exception)
72
%
73
%  A description of each parameter follows:
74
%
75
%    o image:  Method ReadAVSImage returns a pointer to the image after
76
%      reading. A null image is returned if there is a memory shortage or if
77
%      the image cannot be read.
78
%
79
%    o image_info: Specifies a pointer to a ImageInfo structure.
80
%
81
%    o exception: return any errors or warnings in this structure.
82
%
83
%
84
*/
85
561
#define AVS_WIDTH_LIMIT 65536UL  /* Artificially limit width to 64K pixels */
86
539
#define AVS_HEIGHT_LIMIT 65536UL /* Artificially limit height to 64K pixels */
87
#define ThrowAVSReaderException(code_,reason_,image_)           \
88
404
  {                                                             \
89
404
    MagickFreeResourceLimitedMemory(unsigned char *,pixels);    \
90
404
    ThrowReaderException(code_,reason_,image_);                 \
91
0
  }
92
static Image *ReadAVSImage(const ImageInfo *image_info,ExceptionInfo *exception)
93
570
{
94
570
  Image
95
570
    *image;
96
97
570
  long
98
570
    y;
99
100
570
  register long
101
570
    x;
102
103
570
  register PixelPacket
104
570
    *q;
105
106
570
  register unsigned char
107
570
    *p;
108
109
570
  unsigned char
110
570
    *pixels = (unsigned char *) NULL;
111
112
570
  unsigned int
113
570
    status;
114
115
570
  magick_uint32_t
116
570
    height,
117
570
    width;
118
119
  /*
120
    Open image file.
121
  */
122
570
  assert(image_info != (const ImageInfo *) NULL);
123
570
  assert(image_info->signature == MagickSignature);
124
570
  assert(exception != (ExceptionInfo *) NULL);
125
570
  assert(exception->signature == MagickSignature);
126
570
  image=AllocateImage(image_info);
127
570
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
128
570
  if (status == MagickFail)
129
570
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
130
  /*
131
    Read AVS image.
132
  */
133
570
  width=ReadBlobMSBLong(image);
134
570
  height=ReadBlobMSBLong(image);
135
570
  if (EOFBlob(image))
136
561
    ThrowAVSReaderException(CorruptImageError,UnexpectedEndOfFile,image);
137
138
561
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
139
561
                        "AVS dimensions %ux%u",(unsigned)width,(unsigned)height);
140
141
  /*
142
    Impose a maximum width and height limit in order to avoid
143
    incredibly huge allocations.
144
  */
145
561
  if ((width > AVS_WIDTH_LIMIT) || (height > AVS_HEIGHT_LIMIT))
146
512
    ThrowAVSReaderException(CoderError,ImageColumnOrRowSizeIsNotSupported,image);
147
148
512
  do
149
512
  {
150
    /*
151
      Convert AVS raster image to pixel packets.
152
    */
153
512
    size_t
154
512
      row_bytes;
155
156
512
    image->columns=width;
157
512
    image->rows=height;
158
512
    image->depth=8;
159
512
    if (image_info->ping && (image_info->subrange != 0))
160
0
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
161
0
        break;
162
512
    if (CheckImagePixelLimits(image, exception) != MagickPass)
163
470
      ThrowAVSReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
164
470
    pixels=MagickAllocateResourceLimitedArray(unsigned char *,image->columns,4);
165
470
    if (pixels == (unsigned char *) NULL)
166
470
      ThrowAVSReaderException(ResourceLimitError,MemoryAllocationFailed,image);
167
470
    row_bytes=(size_t) 4*image->columns;
168
108k
    for (y=0; y < (long) image->rows; y++)
169
107k
    {
170
107k
      if (ReadBlob(image,row_bytes,pixels) != row_bytes)
171
107k
        ThrowAVSReaderException(CorruptImageError,UnexpectedEndOfFile,image);
172
107k
      p=pixels;
173
107k
      q=SetImagePixels(image,0,y,image->columns,1);
174
107k
      if (q == (PixelPacket *) NULL)
175
0
        {
176
0
          status=MagickFail;
177
0
          break;
178
0
        }
179
11.2M
      for (x=0; x < (long) image->columns; x++)
180
11.1M
      {
181
11.1M
        q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*p++));
182
11.1M
        q->red=ScaleCharToQuantum(*p++);
183
11.1M
        q->green=ScaleCharToQuantum(*p++);
184
11.1M
        q->blue=ScaleCharToQuantum(*p++);
185
11.1M
        image->matte|=(q->opacity != OpaqueOpacity);
186
11.1M
        q++;
187
11.1M
      }
188
107k
      if (!SyncImagePixels(image))
189
0
        {
190
0
          status=MagickFail;
191
0
          break;
192
0
        }
193
107k
      if (image->previous == (Image *) NULL)
194
107k
        if (QuantumTick(y,image->rows))
195
16.1k
          if (!MagickMonitorFormatted(y,image->rows,exception,
196
16.1k
                                      LoadImageText,image->filename,
197
16.1k
                                      image->columns,image->rows))
198
0
            {
199
0
              status=MagickFail;
200
0
              break;
201
0
            }
202
107k
    }
203
166
    MagickFreeResourceLimitedMemory(unsigned char *,pixels);
204
205
166
    if (MagickFail == status)
206
0
      break;
207
208
166
    StopTimer(&image->timer);
209
210
    /*
211
      Proceed to next image.
212
    */
213
166
    if (image_info->subrange != 0)
214
166
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
215
166
        break;
216
0
    width=ReadBlobMSBLong(image);
217
0
    height=ReadBlobMSBLong(image);
218
0
    if (!(EOFBlob(image)) && (width <= AVS_WIDTH_LIMIT) &&
219
0
        (height <= AVS_HEIGHT_LIMIT))
220
0
      {
221
        /*
222
          Allocate next image structure.
223
        */
224
0
        AllocateNextImage(image_info,image);
225
0
        if (image->next == (Image *) NULL)
226
0
          {
227
0
            DestroyImageList(image);
228
0
            return((Image *) NULL);
229
0
          }
230
0
        image=SyncNextImageInList(image);
231
0
        status=MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),
232
0
                                      exception,LoadImagesText,image->filename);
233
0
        if (status == MagickFail)
234
0
          break;
235
0
      }
236
0
  } while (!(EOFBlob(image)));
237
166
  while (image->previous != (Image *) NULL)
238
0
    image=image->previous;
239
166
  CloseBlob(image);
240
241
166
  if (MagickFail == status)
242
0
    {
243
0
      DestroyImageList(image);
244
0
      image=(Image *) NULL;
245
0
    }
246
247
166
  return(image);
248
512
}
249

250
/*
251
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252
%                                                                             %
253
%                                                                             %
254
%                                                                             %
255
%   R e g i s t e r A V S I m a g e                                           %
256
%                                                                             %
257
%                                                                             %
258
%                                                                             %
259
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260
%
261
%  Method RegisterAVSImage adds attributes for the AVS image format to
262
%  the list of supported formats.  The attributes include the image format
263
%  tag, a method to read and/or write the format, whether the format
264
%  supports the saving of more than one frame to the same file or blob,
265
%  whether the format supports native in-memory I/O, and a brief
266
%  description of the format.
267
%
268
%  The format of the RegisterAVSImage method is:
269
%
270
%      RegisterAVSImage(void)
271
%
272
*/
273
ModuleExport void RegisterAVSImage(void)
274
1
{
275
1
  MagickInfo
276
1
    *entry;
277
278
1
  entry=SetMagickInfo("AVS");
279
1
  entry->decoder=(DecoderHandler) ReadAVSImage;
280
1
  entry->encoder=(EncoderHandler) WriteAVSImage;
281
1
  entry->description="AVS X image";
282
1
  entry->module="AVS";
283
1
  entry->coder_class=UnstableCoderClass;
284
1
  (void) RegisterMagickInfo(entry);
285
1
}
286

287
/*
288
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289
%                                                                             %
290
%                                                                             %
291
%                                                                             %
292
%   U n r e g i s t e r A V S I m a g e                                       %
293
%                                                                             %
294
%                                                                             %
295
%                                                                             %
296
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
297
%
298
%  Method UnregisterAVSImage removes format registrations made by the
299
%  AVS module from the list of supported formats.
300
%
301
%  The format of the UnregisterAVSImage method is:
302
%
303
%      UnregisterAVSImage(void)
304
%
305
*/
306
ModuleExport void UnregisterAVSImage(void)
307
0
{
308
0
  (void) UnregisterMagickInfo("AVS");
309
0
}
310

311
/*
312
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313
%                                                                             %
314
%                                                                             %
315
%                                                                             %
316
%   W r i t e A V S I m a g e                                                 %
317
%                                                                             %
318
%                                                                             %
319
%                                                                             %
320
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321
%
322
%  Method WriteAVSImage writes an image to a file in AVS X image format.
323
%
324
%  The format of the WriteAVSImage method is:
325
%
326
%      unsigned int WriteAVSImage(const ImageInfo *image_info,Image *image)
327
%
328
%  A description of each parameter follows.
329
%
330
%    o status: Method WriteAVSImage return True if the image is written.
331
%      False is returned is there is a memory shortage or if the image file
332
%      fails to write.
333
%
334
%    o image_info: Specifies a pointer to a ImageInfo structure.
335
%
336
%    o image:  A pointer to an Image structure.
337
%
338
%
339
*/
340
static unsigned int WriteAVSImage(const ImageInfo *image_info,Image *image)
341
166
{
342
166
  register const PixelPacket
343
166
    *p;
344
345
166
  register long
346
166
    x,
347
166
    y;
348
349
166
  register unsigned char
350
166
    *q;
351
352
166
  unsigned char
353
166
    *pixels;
354
355
166
  unsigned int
356
166
    status;
357
358
166
  unsigned long
359
166
    scene;
360
361
166
  size_t
362
166
    image_list_length;
363
364
  /*
365
    Open output image file.
366
  */
367
166
  assert(image_info != (const ImageInfo *) NULL);
368
166
  assert(image_info->signature == MagickSignature);
369
166
  assert(image != (Image *) NULL);
370
166
  assert(image->signature == MagickSignature);
371
166
  image_list_length=GetImageListLength(image);
372
166
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
373
166
  if (status == False)
374
166
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
375
166
  scene=0;
376
166
  do
377
166
  {
378
    /*
379
      Write AVS header.
380
    */
381
166
    if (TransformColorspace(image,RGBColorspace) == MagickFail)
382
166
      ThrowWriterException(CoderError,UnableToTransformColorspace,image);
383
384
166
    (void) WriteBlobMSBLong(image,image->columns);
385
166
    (void) WriteBlobMSBLong(image,image->rows);
386
    /*
387
      Allocate memory for pixels.
388
    */
389
166
    pixels=MagickAllocateResourceLimitedMemory(unsigned char *,image->columns*sizeof(PixelPacket));
390
166
    if (pixels == (unsigned char *) NULL)
391
166
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
392
    /*
393
      Convert MIFF to AVS raster pixels.
394
    */
395
56.4k
    for (y=0; y < (long) image->rows; y++)
396
56.2k
    {
397
56.2k
      p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
398
56.2k
      if (p == (PixelPacket *) NULL)
399
0
        break;
400
56.2k
      q=pixels;
401
1.73M
      for (x=0; x < (long) image->columns; x++)
402
1.68M
      {
403
1.68M
        *q++=ScaleQuantumToChar(
404
1.68M
          MaxRGB-(image->matte ? p->opacity : OpaqueOpacity));
405
1.68M
        *q++=ScaleQuantumToChar(p->red);
406
1.68M
        *q++=ScaleQuantumToChar(p->green);
407
1.68M
        *q++=ScaleQuantumToChar(p->blue);
408
1.68M
        p++;
409
1.68M
      }
410
56.2k
      (void) WriteBlob(image,q-pixels,(char *) pixels);
411
56.2k
      if (image->previous == (Image *) NULL)
412
56.2k
        if (QuantumTick(y,image->rows))
413
10.6k
          if (!MagickMonitorFormatted(y,image->rows,&image->exception,
414
10.6k
                                      SaveImageText,image->filename,
415
10.6k
                                      image->columns,image->rows))
416
0
            break;
417
56.2k
    }
418
166
    MagickFreeResourceLimitedMemory(unsigned char *,pixels);
419
166
    if (image->next == (Image *) NULL)
420
166
      break;
421
0
    image=SyncNextImageInList(image);
422
0
    status=MagickMonitorFormatted(scene++,image_list_length,
423
0
                                  &image->exception,SaveImagesText,
424
0
                                  image->filename);
425
0
    if (status == False)
426
0
      break;
427
0
  } while (image_info->adjoin);
428
166
  if (image_info->adjoin)
429
166
    while (image->previous != (Image *) NULL)
430
0
      image=image->previous;
431
166
  status &= CloseBlob(image);
432
166
  return(status);
433
166
}