Coverage Report

Created: 2026-09-13 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/aai.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                             AAA    AAA   IIIII                              %
7
%                            A   A  A   A    I                                %
8
%                            AAAAA  AAAAA    I                                %
9
%                            A   A  A   A    I                                %
10
%                            A   A  A   A  IIIII                              %
11
%                                                                             %
12
%                                                                             %
13
%                        Read/Write AAI X 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/blob.h"
44
#include "MagickCore/blob-private.h"
45
#include "MagickCore/cache.h"
46
#include "MagickCore/colorspace.h"
47
#include "MagickCore/colorspace-private.h"
48
#include "MagickCore/exception.h"
49
#include "MagickCore/exception-private.h"
50
#include "MagickCore/image.h"
51
#include "MagickCore/image-private.h"
52
#include "MagickCore/list.h"
53
#include "MagickCore/magick.h"
54
#include "MagickCore/memory_.h"
55
#include "MagickCore/monitor.h"
56
#include "MagickCore/monitor-private.h"
57
#include "MagickCore/pixel.h"
58
#include "MagickCore/pixel-accessor.h"
59
#include "MagickCore/quantum-private.h"
60
#include "MagickCore/static.h"
61
#include "MagickCore/string_.h"
62
#include "MagickCore/module.h"
63

64
/*
65
  Forward declarations.
66
*/
67
static MagickBooleanType
68
  WriteAAIImage(const ImageInfo *,Image *,ExceptionInfo *);
69

70
/*
71
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72
%                                                                             %
73
%                                                                             %
74
%                                                                             %
75
%   R e a d A A I I m a g e                                                   %
76
%                                                                             %
77
%                                                                             %
78
%                                                                             %
79
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80
%
81
%  ReadAAIImage() reads an AAI Dune image file and returns it.  It
82
%  allocates the memory necessary for the new Image structure and returns a
83
%  pointer to the new image.
84
%
85
%  The format of the ReadAAIImage method is:
86
%
87
%      Image *ReadAAIImage(const ImageInfo *image_info,ExceptionInfo *exception)
88
%
89
%  A description of each parameter follows:
90
%
91
%    o image_info: the image info.
92
%
93
%    o exception: return any errors or warnings in this structure.
94
%
95
*/
96
static Image *ReadAAIImage(const ImageInfo *image_info,ExceptionInfo *exception)
97
607
{
98
607
  Image
99
607
    *image;
100
101
607
  MagickBooleanType
102
607
    status;
103
104
607
  Quantum
105
607
    *q;
106
107
607
  size_t
108
607
    height,
109
607
    length,
110
607
    width;
111
112
607
  ssize_t
113
607
    count,
114
607
    x,
115
607
    y;
116
117
607
  unsigned char
118
607
    *p,
119
607
    *pixels;
120
121
  /*
122
    Open image file.
123
  */
124
607
  assert(image_info != (const ImageInfo *) NULL);
125
607
  assert(image_info->signature == MagickCoreSignature);
126
607
  assert(exception != (ExceptionInfo *) NULL);
127
607
  assert(exception->signature == MagickCoreSignature);
128
607
  if (IsEventLogging() != MagickFalse)
129
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
130
0
      image_info->filename);
131
607
  image=AcquireImage(image_info,exception);
132
607
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
133
607
  if (status == MagickFalse)
134
0
    {
135
0
      image=DestroyImageList(image);
136
0
      return((Image *) NULL);
137
0
    }
138
  /*
139
    Read AAI Dune image.
140
  */
141
607
  width=ReadBlobLSBLong(image);
142
607
  height=ReadBlobLSBLong(image);
143
607
  if (EOFBlob(image) != MagickFalse)
144
601
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
145
601
  if ((width == 0UL) || (height == 0UL))
146
599
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
147
599
  do
148
1.00k
  {
149
    /*
150
      Convert AAI raster image to pixel packets.
151
    */
152
1.00k
    image->columns=width;
153
1.00k
    image->rows=height;
154
1.00k
    image->depth=8;
155
1.00k
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
156
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
157
0
        break;
158
1.00k
    status=SetImageExtent(image,image->columns,image->rows,exception);
159
1.00k
    if (status == MagickFalse)
160
187
      return(DestroyImageList(image));
161
818
    pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
162
818
      4*sizeof(*pixels));
163
818
    if (pixels == (unsigned char *) NULL) 
164
818
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
165
818
    length=(size_t) 4*image->columns;
166
38.1k
    for (y=0; y < (ssize_t) image->rows; y++)
167
37.5k
    {
168
37.5k
      count=ReadBlob(image,length,pixels);
169
37.5k
      if (count != (ssize_t) length)
170
176
        {
171
176
          pixels=(unsigned char *) RelinquishMagickMemory(pixels);
172
176
          ThrowReaderException(CorruptImageError,"UnableToReadImageData");
173
0
        }
174
37.3k
      p=pixels;
175
37.3k
      q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
176
37.3k
      if (q == (Quantum *) NULL)
177
0
        break;
178
110k
      for (x=0; x < (ssize_t) image->columns; x++)
179
73.3k
      {
180
73.3k
        SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
181
73.3k
        SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
182
73.3k
        SetPixelRed(image,ScaleCharToQuantum(*p++),q);
183
73.3k
        if (*p == 254)
184
1.85k
          *p=255;
185
73.3k
        SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
186
73.3k
        if (GetPixelAlpha(image,q) != OpaqueAlpha)
187
0
          image->alpha_trait=BlendPixelTrait;
188
73.3k
        q+=(ptrdiff_t) GetPixelChannels(image);
189
73.3k
      }
190
37.3k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
191
0
        break;
192
37.3k
      if (image->previous == (Image *) NULL)
193
36.5k
        {
194
36.5k
          status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
195
36.5k
            image->rows);
196
36.5k
          if (status == MagickFalse)
197
0
            break;
198
36.5k
        }
199
37.3k
    }
200
642
    pixels=(unsigned char *) RelinquishMagickMemory(pixels);
201
642
    if (EOFBlob(image) != MagickFalse)
202
0
      {
203
0
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
204
0
          image->filename);
205
0
        break;
206
0
      }
207
    /*
208
      Proceed to next image.
209
    */
210
642
    if (image_info->number_scenes != 0)
211
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
212
0
        break;
213
642
    width=ReadBlobLSBLong(image);
214
642
    height=ReadBlobLSBLong(image);
215
642
    if ((width != 0UL) && (height != 0UL))
216
406
      {
217
        /*
218
          Allocate next image structure.
219
        */
220
406
        AcquireNextImage(image_info,image,exception);
221
406
        if (GetNextImageInList(image) == (Image *) NULL)
222
0
          {
223
0
            status=MagickFalse;
224
0
            break;
225
0
          }
226
406
        image=SyncNextImageInList(image);
227
406
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
228
406
          GetBlobSize(image));
229
406
        if (status == MagickFalse)
230
0
          break;
231
406
      }
232
642
  } while ((width != 0UL) && (height != 0UL));
233
236
  if (CloseBlob(image) == MagickFalse)
234
0
    status=MagickFalse;
235
236
  if (status == MagickFalse)
236
0
    return(DestroyImageList(image));
237
236
  return(GetFirstImageInList(image));
238
236
}
239

240
/*
241
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242
%                                                                             %
243
%                                                                             %
244
%                                                                             %
245
%   R e g i s t e r A A I I m a g e                                           %
246
%                                                                             %
247
%                                                                             %
248
%                                                                             %
249
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250
%
251
%  RegisterAAIImage() adds attributes for the AAI Dune image format to the list
252
%  of supported formats.  The attributes include the image format tag, a
253
%  method to read and/or write the format, whether the format supports the
254
%  saving of more than one frame to the same file or blob, whether the format
255
%  supports native in-memory I/O, and a brief description of the format.
256
%
257
%  The format of the RegisterAAIImage method is:
258
%
259
%      size_t RegisterAAIImage(void)
260
%
261
*/
262
ModuleExport size_t RegisterAAIImage(void)
263
8
{
264
8
  MagickInfo
265
8
    *entry;
266
267
8
  entry=AcquireMagickInfo("AAI","AAI","AAI Dune image");
268
8
  entry->decoder=(DecodeImageHandler *) ReadAAIImage;
269
8
  entry->encoder=(EncodeImageHandler *) WriteAAIImage;
270
8
  (void) RegisterMagickInfo(entry);
271
8
  return(MagickImageCoderSignature);
272
8
}
273

274
/*
275
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276
%                                                                             %
277
%                                                                             %
278
%                                                                             %
279
%   U n r e g i s t e r A A I I m a g e                                       %
280
%                                                                             %
281
%                                                                             %
282
%                                                                             %
283
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284
%
285
%  UnregisterAAIImage() removes format registrations made by the
286
%  AAI module from the list of supported formats.
287
%
288
%  The format of the UnregisterAAIImage method is:
289
%
290
%      UnregisterAAIImage(void)
291
%
292
*/
293
ModuleExport void UnregisterAAIImage(void)
294
0
{
295
0
  (void) UnregisterMagickInfo("AAI");
296
0
}
297

298
/*
299
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300
%                                                                             %
301
%                                                                             %
302
%                                                                             %
303
%   W r i t e A A I I m a g e                                                 %
304
%                                                                             %
305
%                                                                             %
306
%                                                                             %
307
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
308
%
309
%  WriteAAIImage() writes an image to a file in AAI Dune image format.
310
%
311
%  The format of the WriteAAIImage method is:
312
%
313
%      MagickBooleanType WriteAAIImage(const ImageInfo *image_info,
314
%        Image *image,ExceptionInfo *exception)
315
%
316
%  A description of each parameter follows.
317
%
318
%    o image_info: the image info.
319
%
320
%    o image:  The image.
321
%
322
%    o exception: return any errors or warnings in this structure.
323
%
324
*/
325
static MagickBooleanType WriteAAIImage(const ImageInfo *image_info,Image *image,
326
  ExceptionInfo *exception)
327
236
{
328
236
  const Quantum
329
236
    *magick_restrict p;
330
331
236
  MagickBooleanType
332
236
    status;
333
334
236
  MagickOffsetType
335
236
    scene;
336
337
236
  size_t
338
236
    number_scenes;
339
340
236
  ssize_t
341
236
    count,
342
236
    x,
343
236
    y;
344
345
236
  unsigned char
346
236
    *pixels,
347
236
    *magick_restrict q;
348
349
  /*
350
    Open output image file.
351
  */
352
236
  assert(image_info != (const ImageInfo *) NULL);
353
236
  assert(image_info->signature == MagickCoreSignature);
354
236
  assert(image != (Image *) NULL);
355
236
  assert(image->signature == MagickCoreSignature);
356
236
  assert(exception != (ExceptionInfo *) NULL);
357
236
  assert(exception->signature == MagickCoreSignature);
358
236
  if (IsEventLogging() != MagickFalse)
359
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
360
236
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
361
236
  if (status == MagickFalse)
362
0
    return(status);
363
236
  scene=0;
364
236
  number_scenes=GetImageListLength(image);
365
236
  do
366
236
  {
367
    /*
368
      Write AAI header.
369
    */
370
236
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
371
0
      (void) TransformImageColorspace(image,sRGBColorspace,exception);
372
236
    (void) WriteBlobLSBLong(image,(unsigned int) image->columns);
373
236
    (void) WriteBlobLSBLong(image,(unsigned int) image->rows);
374
    /*
375
      Allocate memory for pixels.
376
    */
377
236
    pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
378
236
      4*sizeof(*pixels));
379
236
    if (pixels == (unsigned char *) NULL)
380
236
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
381
    /*
382
      Convert MIFF to AAI raster pixels.
383
    */
384
22.8k
    for (y=0; y < (ssize_t) image->rows; y++)
385
22.5k
    {
386
22.5k
      p=GetVirtualPixels(image,0,y,image->columns,1,exception);
387
22.5k
      if (p == (const Quantum *) NULL)
388
0
        break;
389
22.5k
      q=pixels;
390
66.7k
      for (x=0; x < (ssize_t) image->columns; x++)
391
44.1k
      {
392
44.1k
        *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
393
44.1k
        *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
394
44.1k
        *q++=ScaleQuantumToChar(GetPixelRed(image,p));
395
44.1k
        *q=ScaleQuantumToChar((Quantum) (image->alpha_trait !=
396
44.1k
          UndefinedPixelTrait ? GetPixelAlpha(image,p) : OpaqueAlpha));
397
44.1k
        if (*q == 255)
398
44.1k
          *q=254;
399
44.1k
        p+=(ptrdiff_t) GetPixelChannels(image);
400
44.1k
        q++;
401
44.1k
      }
402
22.5k
      count=WriteBlob(image,(size_t) (q-pixels),pixels);
403
22.5k
      if (count != (ssize_t) (q-pixels))
404
0
        break;
405
22.5k
      if (image->previous == (Image *) NULL)
406
22.5k
        {
407
22.5k
          status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
408
22.5k
            image->rows);
409
22.5k
          if (status == MagickFalse)
410
0
            break;
411
22.5k
        }
412
22.5k
    }
413
236
    pixels=(unsigned char *) RelinquishMagickMemory(pixels);
414
236
    if (GetNextImageInList(image) == (Image *) NULL)
415
236
      break;
416
0
    image=SyncNextImageInList(image);
417
0
    status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
418
0
    if (status == MagickFalse)
419
0
      break;
420
0
  } while (image_info->adjoin != MagickFalse);
421
236
  if (CloseBlob(image) == MagickFalse)
422
0
    status=MagickFalse;
423
236
  return(status);
424
236
}