Coverage Report

Created: 2026-07-25 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/mtv.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
%                            M   M  TTTTT  V   V                              %
15
%                            MM MM    T    V   V                              %
16
%                            M M M    T    V   V                              %
17
%                            M   M    T     V V                               %
18
%                            M   M    T      V                                %
19
%                                                                             %
20
%                                                                             %
21
%                   Read/Write MTV Raytracer 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/pixel_cache.h"
41
#include "magick/log.h"
42
#include "magick/magick.h"
43
#include "magick/monitor.h"
44
#include "magick/utility.h"
45
#include "magick/static.h"
46

47
/*
48
  Forward declarations.
49
*/
50
static unsigned int
51
  WriteMTVImage(const ImageInfo *,Image *);
52

53
/*
54
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55
%                                                                             %
56
%                                                                             %
57
%                                                                             %
58
%   R e a d M T V I m a g e                                                   %
59
%                                                                             %
60
%                                                                             %
61
%                                                                             %
62
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63
%
64
%  Method ReadMTVImage reads a MTV image file and returns it.  It allocates
65
%  the memory necessary for the new Image structure and returns a pointer to
66
%  the new image.
67
%
68
%  The format of the ReadMTVImage method is:
69
%
70
%      Image *ReadMTVImage(const ImageInfo *image_info,ExceptionInfo *exception)
71
%
72
%  A description of each parameter follows:
73
%
74
%    o image:  Method ReadMTVImage returns a pointer to the image after
75
%      reading.  A null image is returned if there is a memory shortage or
76
%      if the image cannot be read.
77
%
78
%    o image_info: Specifies a pointer to a ImageInfo structure.
79
%
80
%    o exception: return any errors or warnings in this structure.
81
%
82
%
83
*/
84
static Image *ReadMTVImage(const ImageInfo *image_info,ExceptionInfo *exception)
85
911
{
86
911
  char
87
911
    buffer[MaxTextExtent];
88
89
911
  Image
90
911
    *image;
91
92
911
  long
93
911
    count,
94
911
    y;
95
96
911
  register long
97
911
    x;
98
99
911
  register PixelPacket
100
911
    *q;
101
102
911
  register unsigned char
103
911
    *p;
104
105
911
  unsigned char
106
911
    *pixels;
107
108
911
  unsigned int
109
911
    status;
110
111
911
  unsigned long
112
911
    columns,
113
911
    rows;
114
115
  /*
116
    Open image file.
117
  */
118
911
  assert(image_info != (const ImageInfo *) NULL);
119
911
  assert(image_info->signature == MagickSignature);
120
911
  assert(exception != (ExceptionInfo *) NULL);
121
911
  assert(exception->signature == MagickSignature);
122
911
  image=AllocateImage(image_info);
123
911
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
124
911
  if (status == False)
125
911
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
126
  /*
127
    Read MTV image.
128
  */
129
911
  buffer[0]='\0';
130
911
  (void) ReadBlobString(image,buffer);
131
911
  columns=0;
132
911
  rows=0;
133
911
  count=sscanf(buffer,"%lu %lu\n",&columns,&rows);
134
911
  if (count != 2)
135
868
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
136
868
  do
137
868
  {
138
868
    size_t
139
868
      row_size;
140
141
    /*
142
      Initialize image structure.
143
    */
144
868
    image->columns=columns;
145
868
    image->rows=rows;
146
868
    image->depth=8;
147
868
    if (image->logging)
148
868
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
149
868
                          "Image[%lu] Geometry %lux%lu", image->scene,
150
868
                          image->columns, image->rows);
151
868
    if (image_info->ping && (image_info->subrange != 0))
152
0
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
153
0
        break;
154
155
868
    if (CheckImagePixelLimits(image, exception) != MagickPass)
156
573
      ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
157
158
    /*
159
      Convert MTV raster image to pixel packets.
160
    */
161
573
    pixels=MagickAllocateResourceLimitedArray(unsigned char *,image->columns,3);
162
573
    if (pixels == (unsigned char *) NULL)
163
573
      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
164
573
    row_size= (size_t) image->columns*3;
165
124k
    for (y=0; y < (long) image->rows; y++)
166
124k
    {
167
124k
      if (ReadBlob(image,row_size,pixels) != row_size)
168
396
        break;
169
123k
      p=pixels;
170
123k
      q=SetImagePixelsEx(image,0,y,image->columns,1,exception);
171
123k
      if (q == (PixelPacket *) NULL)
172
0
        break;
173
17.1M
      for (x=0; x < (long) image->columns; x++)
174
17.0M
      {
175
17.0M
        q->red=ScaleCharToQuantum(*p++);
176
17.0M
        q->green=ScaleCharToQuantum(*p++);
177
17.0M
        q->blue=ScaleCharToQuantum(*p++);
178
17.0M
        q++;
179
17.0M
      }
180
123k
      if (!SyncImagePixelsEx(image,exception))
181
0
        break;
182
123k
      if (image->previous == (Image *) NULL)
183
123k
        if (QuantumTick(y,image->rows))
184
20.8k
          if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
185
20.8k
                                      image->filename,
186
20.8k
                                      image->columns,image->rows))
187
0
            break;
188
123k
    }
189
573
    MagickFreeResourceLimitedMemory(unsigned char *,pixels);
190
573
    if (EOFBlob(image))
191
396
      {
192
396
        ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
193
396
          image->filename);
194
396
        break;
195
396
      }
196
177
    StopTimer(&image->timer);
197
    /*
198
      Proceed to next image.
199
    */
200
177
    if (image_info->subrange != 0)
201
177
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
202
177
        break;
203
0
    *buffer='\0';
204
0
    count=0;
205
0
    if (ReadBlobString(image,buffer) == NULL)
206
0
      break;
207
0
    count=sscanf(buffer,"%lu %lu\n",&columns,&rows);
208
0
    if (count == 2)
209
0
      {
210
        /*
211
          Allocate next image structure.
212
        */
213
0
        AllocateNextImage(image_info,image);
214
0
        if (image->next == (Image *) NULL)
215
0
          {
216
0
            DestroyImageList(image);
217
0
            return((Image *) NULL);
218
0
          }
219
0
        image=SyncNextImageInList(image);
220
0
        if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),
221
0
                                    exception,LoadImagesText,
222
0
                                    image->filename))
223
0
          break;
224
0
      }
225
0
  } while (count == 2);
226
573
  while (image->previous != (Image *) NULL)
227
0
    image=image->previous;
228
573
  CloseBlob(image);
229
573
  return(image);
230
868
}
231

232
/*
233
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234
%                                                                             %
235
%                                                                             %
236
%                                                                             %
237
%   R e g i s t e r M T V I m a g e                                           %
238
%                                                                             %
239
%                                                                             %
240
%                                                                             %
241
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242
%
243
%  Method RegisterMTVImage adds attributes for the MTV image format to
244
%  the list of supported formats.  The attributes include the image format
245
%  tag, a method to read and/or write the format, whether the format
246
%  supports the saving of more than one frame to the same file or blob,
247
%  whether the format supports native in-memory I/O, and a brief
248
%  description of the format.
249
%
250
%  The format of the RegisterMTVImage method is:
251
%
252
%      RegisterMTVImage(void)
253
%
254
*/
255
ModuleExport void RegisterMTVImage(void)
256
1
{
257
1
  MagickInfo
258
1
    *entry;
259
260
1
  entry=SetMagickInfo("MTV");
261
1
  entry->decoder=(DecoderHandler) ReadMTVImage;
262
1
  entry->encoder=(EncoderHandler) WriteMTVImage;
263
1
  entry->description="MTV Raytracing image format";
264
1
  entry->module="MTV";
265
1
  entry->coder_class=UnstableCoderClass;
266
1
  (void) RegisterMagickInfo(entry);
267
1
}
268

269
/*
270
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271
%                                                                             %
272
%                                                                             %
273
%                                                                             %
274
%   U n r e g i s t e r M T V I m a g e                                       %
275
%                                                                             %
276
%                                                                             %
277
%                                                                             %
278
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279
%
280
%  Method UnregisterMTVImage removes format registrations made by the
281
%  MTV module from the list of supported formats.
282
%
283
%  The format of the UnregisterMTVImage method is:
284
%
285
%      UnregisterMTVImage(void)
286
%
287
*/
288
ModuleExport void UnregisterMTVImage(void)
289
0
{
290
0
  (void) UnregisterMagickInfo("MTV");
291
0
}
292

293
/*
294
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295
%                                                                             %
296
%                                                                             %
297
%                                                                             %
298
%   W r i t e M T V I m a g e                                                 %
299
%                                                                             %
300
%                                                                             %
301
%                                                                             %
302
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
303
%
304
%  Method WriteMTVImage writes an image to a file in red, green, and blue
305
%  MTV rasterfile format.
306
%
307
%  The format of the WriteMTVImage method is:
308
%
309
%      unsigned int WriteMTVImage(const ImageInfo *image_info,Image *image)
310
%
311
%  A description of each parameter follows.
312
%
313
%    o status: Method WriteMTVImage return True if the image is written.
314
%      False is returned is there is a memory shortage or if the image file
315
%      fails to write.
316
%
317
%    o image_info: Specifies a pointer to a ImageInfo structure.
318
%
319
%    o image:  A pointer to an Image structure.
320
%
321
%
322
*/
323
static unsigned int WriteMTVImage(const ImageInfo *image_info,Image *image)
324
177
{
325
177
  char
326
177
    buffer[MaxTextExtent];
327
328
177
  int
329
177
    y;
330
331
177
  register const PixelPacket
332
177
    *p;
333
334
177
  register long
335
177
    x;
336
337
177
  register unsigned char
338
177
    *q;
339
340
177
  unsigned char
341
177
    *pixels;
342
343
177
  unsigned int
344
177
    status;
345
346
177
  unsigned long
347
177
    scene;
348
349
177
  size_t
350
177
    image_list_length;
351
352
  /*
353
    Open output image file.
354
  */
355
177
  assert(image_info != (const ImageInfo *) NULL);
356
177
  assert(image_info->signature == MagickSignature);
357
177
  assert(image != (Image *) NULL);
358
177
  assert(image->signature == MagickSignature);
359
177
  image_list_length=GetImageListLength(image);
360
177
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
361
177
  if (status == False)
362
177
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
363
177
  scene=0;
364
177
  do
365
177
  {
366
    /*
367
      Set image to RGB colorspace
368
    */
369
177
    if (TransformColorspace(image,RGBColorspace) == MagickFail)
370
177
      ThrowWriterException(CoderError,UnableToTransformColorspace,image);
371
    /*
372
      Allocate memory for pixels.
373
    */
374
177
    pixels=MagickAllocateResourceLimitedMemory(unsigned char *,
375
177
      image->columns*sizeof(PixelPacket));
376
177
    if (pixels == (unsigned char *) NULL)
377
177
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
378
    /*
379
      Initialize raster file header.
380
    */
381
177
    MagickFormatString(buffer,sizeof(buffer),"%lu %lu\n",image->columns,image->rows);
382
177
    (void) WriteBlobString(image,buffer);
383
76.1k
    for (y=0; y < (long) image->rows; y++)
384
76.0k
    {
385
76.0k
      p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
386
76.0k
      if (p == (const PixelPacket *) NULL)
387
0
        break;
388
76.0k
      q=pixels;
389
2.81M
      for (x=0; x < (long) image->columns; x++)
390
2.73M
      {
391
2.73M
        *q++=ScaleQuantumToChar(p->red);
392
2.73M
        *q++=ScaleQuantumToChar(p->green);
393
2.73M
        *q++=ScaleQuantumToChar(p->blue);
394
2.73M
        p++;
395
2.73M
      }
396
76.0k
      (void) WriteBlob(image,q-pixels,(char *) pixels);
397
76.0k
      if (image->previous == (Image *) NULL)
398
76.0k
        if (QuantumTick(y,image->rows))
399
11.9k
          if (!MagickMonitorFormatted(y,image->rows,&image->exception,
400
11.9k
                                      SaveImageText,image->filename,
401
11.9k
                                      image->columns,image->rows))
402
0
            break;
403
76.0k
    }
404
177
    MagickFreeResourceLimitedMemory(unsigned char *,pixels);
405
177
    if (image->next == (Image *) NULL)
406
177
      break;
407
0
    image=SyncNextImageInList(image);
408
0
    status=MagickMonitorFormatted(scene++,image_list_length,
409
0
                                  &image->exception,SaveImagesText,
410
0
                                  image->filename);
411
0
    if (status == False)
412
0
      break;
413
0
  } while (image_info->adjoin);
414
177
  if (image_info->adjoin)
415
177
    while (image->previous != (Image *) NULL)
416
0
      image=image->previous;
417
177
  status &= CloseBlob(image);
418
177
  return(status);
419
177
}