/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 | } |