Coverage Report

Created: 2025-06-16 07:00

/src/imagemagick/coders/fax.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            FFFFF   AAA   X   X                              %
7
%                            F      A   A   X X                               %
8
%                            FFF    AAAAA    X                                %
9
%                            F      A   A   X X                               %
10
%                            F      A   A  X   X                              %
11
%                                                                             %
12
%                                                                             %
13
%                   Read/Write Group 3 Fax 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/script/license.php                               %
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/attribute.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/colormap.h"
47
#include "MagickCore/colorspace.h"
48
#include "MagickCore/colorspace-private.h"
49
#include "MagickCore/constitute.h"
50
#include "MagickCore/exception.h"
51
#include "MagickCore/exception-private.h"
52
#include "MagickCore/compress.h"
53
#include "MagickCore/image.h"
54
#include "MagickCore/image-private.h"
55
#include "MagickCore/list.h"
56
#include "MagickCore/magick.h"
57
#include "MagickCore/memory_.h"
58
#include "MagickCore/monitor.h"
59
#include "MagickCore/monitor-private.h"
60
#include "MagickCore/quantum-private.h"
61
#include "MagickCore/resource_.h"
62
#include "MagickCore/static.h"
63
#include "MagickCore/string_.h"
64
#include "MagickCore/module.h"
65

66
/*
67
  Forward declarations.
68
*/
69
static MagickBooleanType
70
  WriteFAXImage(const ImageInfo *,Image *,ExceptionInfo *);
71

72
/*
73
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74
%                                                                             %
75
%                                                                             %
76
%                                                                             %
77
%   I s F A X                                                                 %
78
%                                                                             %
79
%                                                                             %
80
%                                                                             %
81
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82
%
83
%  IsFAX() returns MagickTrue if the image format type, identified by the
84
%  magick string, is FAX.
85
%
86
%  The format of the IsFAX method is:
87
%
88
%      MagickBooleanType IsFAX(const unsigned char *magick,const size_t length)
89
%
90
%  A description of each parameter follows:
91
%
92
%    o magick: compare image format pattern against these bytes.
93
%
94
%    o length: Specifies the length of the magick string.
95
%
96
%
97
*/
98
static MagickBooleanType IsFAX(const unsigned char *magick,const size_t length)
99
0
{
100
0
  if (length < 4)
101
0
    return(MagickFalse);
102
0
  if (LocaleNCompare((char *) magick,"DFAX",4) == 0)
103
0
    return(MagickTrue);
104
0
  return(MagickFalse);
105
0
}
106

107
/*
108
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109
%                                                                             %
110
%                                                                             %
111
%                                                                             %
112
%   R e a d F A X I m a g e                                                   %
113
%                                                                             %
114
%                                                                             %
115
%                                                                             %
116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117
%
118
%  ReadFAXImage() reads a Group 3 FAX image file and returns it.  It
119
%  allocates the memory necessary for the new Image structure and returns a
120
%  pointer to the new image.
121
%
122
%  The format of the ReadFAXImage method is:
123
%
124
%      Image *ReadFAXImage(const ImageInfo *image_info,ExceptionInfo *exception)
125
%
126
%  A description of each parameter follows:
127
%
128
%    o image_info: the image info.
129
%
130
%    o exception: return any errors or warnings in this structure.
131
%
132
*/
133
static Image* FaxReadG3(Image *image,ExceptionInfo *exception)
134
347
{
135
347
  MagickBooleanType
136
347
    status;
137
138
347
  status=HuffmanDecodeImage(image,exception);
139
347
  if (status == MagickFalse)
140
0
    ThrowFileException(exception,CorruptImageError,"UnableToReadImageData",
141
347
      image->filename);
142
347
  if (EOFBlob(image) != MagickFalse)
143
340
    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
144
347
      image->filename);
145
347
  if (CloseBlob(image) == MagickFalse)
146
0
    status=MagickFalse;
147
347
  if (status == MagickFalse)
148
0
    return(DestroyImageList(image));
149
347
  return(GetFirstImageInList(image));
150
347
}
151
152
static Image* FaxReadG4(Image *image,const ImageInfo *image_info,
153
  ExceptionInfo *exception)
154
433
{
155
433
  char
156
433
    filename[MagickPathExtent];
157
158
433
  ImageInfo
159
433
    *read_info;
160
161
433
  filename[0]='\0';
162
433
  if (ImageToFile(image,filename,exception) == MagickFalse)
163
433
    ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
164
433
  (void) CloseBlob(image);
165
433
  image=DestroyImage(image);
166
433
  read_info=CloneImageInfo(image_info);
167
433
  SetImageInfoBlob(read_info,(void *) NULL,0);
168
433
  (void) FormatLocaleString(read_info->filename,MagickPathExtent,"group4:%s",
169
433
    filename);
170
433
  read_info->orientation=TopLeftOrientation;
171
433
  image=ReadImage(read_info,exception);
172
433
  if (image != (Image *) NULL)
173
428
    {
174
428
      (void) CopyMagickString(image->filename,image_info->filename,
175
428
        MagickPathExtent);
176
428
      (void) CopyMagickString(image->magick_filename,image_info->filename,
177
428
        MagickPathExtent);
178
428
      (void) CopyMagickString(image->magick,"G4",MagickPathExtent);
179
428
    }
180
433
  read_info=DestroyImageInfo(read_info);
181
433
  (void) RelinquishUniqueFileResource(filename);
182
433
  return(GetFirstImageInList(image));
183
433
}
184
185
static Image *ReadFAXImage(const ImageInfo *image_info,ExceptionInfo *exception)
186
1.13k
{
187
1.13k
  Image
188
1.13k
    *image;
189
190
1.13k
  MagickBooleanType
191
1.13k
    status;
192
193
  /*
194
    Open image file.
195
  */
196
1.13k
  assert(image_info != (const ImageInfo *) NULL);
197
1.13k
  assert(image_info->signature == MagickCoreSignature);
198
1.13k
  assert(exception != (ExceptionInfo *) NULL);
199
1.13k
  assert(exception->signature == MagickCoreSignature);
200
1.13k
  if (IsEventLogging() != MagickFalse)
201
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
202
0
      image_info->filename);
203
1.13k
  image=AcquireImage(image_info,exception);
204
1.13k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
205
1.13k
  if (status == MagickFalse)
206
186
    {
207
186
      image=DestroyImageList(image);
208
186
      return((Image *) NULL);
209
186
    }
210
  /*
211
    Initialize image structure.
212
  */
213
948
  image->storage_class=PseudoClass;
214
948
  if (image->columns == 0)
215
151
    image->columns=2592;
216
948
  if (image->rows == 0)
217
152
    image->rows=3508;
218
948
  image->depth=8;
219
948
  if (AcquireImageColormap(image,2,exception) == MagickFalse)
220
948
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
221
  /*
222
    Monochrome colormap.
223
  */
224
948
  image->colormap[0].red=QuantumRange;
225
948
  image->colormap[0].green=QuantumRange;
226
948
  image->colormap[0].blue=QuantumRange;
227
948
  image->colormap[1].red=(Quantum) 0;
228
948
  image->colormap[1].green=(Quantum) 0;
229
948
  image->colormap[1].blue=(Quantum) 0;
230
948
  if (image_info->ping != MagickFalse)
231
1
    {
232
1
      (void) CloseBlob(image);
233
1
      return(GetFirstImageInList(image));
234
1
    }
235
947
  status=SetImageExtent(image,image->columns,image->rows,exception);
236
947
  if (status == MagickFalse)
237
167
    return(DestroyImageList(image));
238
780
  if (LocaleCompare(image_info->magick,"G4") == 0)
239
433
    return(FaxReadG4(image,image_info,exception));
240
347
  else
241
347
    return(FaxReadG3(image,exception));
242
780
}
243

244
/*
245
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246
%                                                                             %
247
%                                                                             %
248
%                                                                             %
249
%   R e g i s t e r F A X I m a g e                                           %
250
%                                                                             %
251
%                                                                             %
252
%                                                                             %
253
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254
%
255
%  RegisterFAXImage() adds attributes for the FAX image format to
256
%  the list of supported formats.  The attributes include the image format
257
%  tag, a method to read and/or write the format, whether the format
258
%  supports the saving of more than one frame to the same file or blob,
259
%  whether the format supports native in-memory I/O, and a brief
260
%  description of the format.
261
%
262
%  The format of the RegisterFAXImage method is:
263
%
264
%      size_t RegisterFAXImage(void)
265
%
266
*/
267
ModuleExport size_t RegisterFAXImage(void)
268
12
{
269
12
  MagickInfo
270
12
    *entry;
271
272
12
  static const char
273
12
    *Note=
274
12
    {
275
12
      "FAX machines use non-square pixels which are 1.5 times wider than\n"
276
12
      "they are tall but computer displays use square pixels, therefore\n"
277
12
      "FAX images may appear to be narrow unless they are explicitly\n"
278
12
      "resized using a geometry of \"150x100%\".\n"
279
12
    };
280
281
12
  entry=AcquireMagickInfo("FAX","FAX","Group 3 FAX");
282
12
  entry->decoder=(DecodeImageHandler *) ReadFAXImage;
283
12
  entry->encoder=(EncodeImageHandler *) WriteFAXImage;
284
12
  entry->magick=(IsImageFormatHandler *) IsFAX;
285
12
  entry->note=ConstantString(Note);
286
12
  (void) RegisterMagickInfo(entry);
287
12
  entry=AcquireMagickInfo("FAX","G3","Group 3 FAX");
288
12
  entry->decoder=(DecodeImageHandler *) ReadFAXImage;
289
12
  entry->encoder=(EncodeImageHandler *) WriteFAXImage;
290
12
  entry->magick=(IsImageFormatHandler *) IsFAX;
291
12
  entry->flags^=CoderAdjoinFlag;
292
12
  (void) RegisterMagickInfo(entry);
293
12
  entry=AcquireMagickInfo("FAX","G4","Group 4 FAX");
294
12
  entry->decoder=(DecodeImageHandler *) ReadFAXImage;
295
12
  entry->encoder=(EncodeImageHandler *) WriteFAXImage;
296
12
  entry->magick=(IsImageFormatHandler *) IsFAX;
297
12
  entry->flags^=CoderAdjoinFlag;
298
12
  (void) RegisterMagickInfo(entry);
299
12
  return(MagickImageCoderSignature);
300
12
}
301

302
/*
303
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304
%                                                                             %
305
%                                                                             %
306
%                                                                             %
307
%   U n r e g i s t e r F A X I m a g e                                       %
308
%                                                                             %
309
%                                                                             %
310
%                                                                             %
311
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312
%
313
%  UnregisterFAXImage() removes format registrations made by the
314
%  FAX module from the list of supported formats.
315
%
316
%  The format of the UnregisterFAXImage method is:
317
%
318
%      UnregisterFAXImage(void)
319
%
320
*/
321
ModuleExport void UnregisterFAXImage(void)
322
0
{
323
0
  (void) UnregisterMagickInfo("FAX");
324
0
  (void) UnregisterMagickInfo("G3");
325
0
  (void) UnregisterMagickInfo("G4");
326
0
}
327

328
/*
329
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330
%                                                                             %
331
%                                                                             %
332
%                                                                             %
333
%   W r i t e F A X I m a g e                                                 %
334
%                                                                             %
335
%                                                                             %
336
%                                                                             %
337
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338
%
339
%  WriteFAXImage() writes an image to a file in 1 dimensional Huffman encoded
340
%  format.
341
%
342
%  The format of the WriteFAXImage method is:
343
%
344
%      MagickBooleanType WriteFAXImage(const ImageInfo *image_info,
345
%        Image *image,ExceptionInfo *exception)
346
%
347
%  A description of each parameter follows.
348
%
349
%    o image_info: the image info.
350
%
351
%    o image:  The image.
352
%
353
%    o exception: return any errors or warnings in this structure.
354
%
355
*/
356
static MagickBooleanType WriteFAXImage(const ImageInfo *image_info,Image *image,
357
  ExceptionInfo *exception)
358
0
{
359
0
  ImageInfo
360
0
    *write_info;
361
362
0
  MagickBooleanType
363
0
    status;
364
365
0
  MagickOffsetType
366
0
    scene;
367
368
0
  size_t
369
0
    number_scenes;
370
371
  /*
372
    Open output image file.
373
  */
374
0
  assert(image_info != (const ImageInfo *) NULL);
375
0
  assert(image_info->signature == MagickCoreSignature);
376
0
  assert(image != (Image *) NULL);
377
0
  assert(image->signature == MagickCoreSignature);
378
0
  assert(exception != (ExceptionInfo *) NULL);
379
0
  assert(exception->signature == MagickCoreSignature);
380
0
  if (IsEventLogging() != MagickFalse)
381
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
382
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
383
0
  if (status == MagickFalse)
384
0
    return(status);
385
0
  write_info=CloneImageInfo(image_info);
386
0
  (void) CopyMagickString(write_info->magick,"FAX",MagickPathExtent);
387
0
  scene=0;
388
0
  number_scenes=GetImageListLength(image);
389
0
  do
390
0
  {
391
    /*
392
      Convert MIFF to monochrome.
393
    */
394
0
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
395
0
      (void) TransformImageColorspace(image,sRGBColorspace,exception);
396
0
    status=HuffmanEncodeImage(write_info,image,image,exception);
397
0
    if (GetNextImageInList(image) == (Image *) NULL)
398
0
      break;
399
0
    image=SyncNextImageInList(image);
400
0
    status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
401
0
    if (status == MagickFalse)
402
0
      break;
403
0
  } while (write_info->adjoin != MagickFalse);
404
0
  write_info=DestroyImageInfo(write_info);
405
0
  if (CloseBlob(image) == MagickFalse)
406
0
    status=MagickFalse;
407
0
  return(status);
408
0
}