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