Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                         CCCC   AAA   L      SSSSS                           %
      7 %                        C      A   A  L      SS                              %
      8 %                        C      AAAAA  L       SSS                            %
      9 %                        C      A   A  L         SS                           %
     10 %                         CCCC  A   A  LLLLL  SSSSS                           %
     11 %                                                                             %
     12 %                                                                             %
     13 %                 Read/Write CALS Raster Group 1 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 % The CALS raster format is a standard developed by the Computer Aided
     37 % Acquisition and Logistics Support (CALS) office of the United States
     38 % Department of Defense to standardize graphics data interchange for
     39 % electronic publishing, especially in the areas of technical graphics,
     40 % CAD/CAM, and image processing applications.
     41 %
     42 */
     43 
     44 /*
     46   Include declarations.
     47 */
     48 #include "MagickCore/studio.h"
     49 #include "MagickCore/blob.h"
     50 #include "MagickCore/blob-private.h"
     51 #include "MagickCore/cache.h"
     52 #include "MagickCore/colorspace.h"
     53 #include "MagickCore/constitute.h"
     54 #include "MagickCore/exception.h"
     55 #include "MagickCore/exception-private.h"
     56 #include "MagickCore/geometry.h"
     57 #include "MagickCore/image.h"
     58 #include "MagickCore/image-private.h"
     59 #include "MagickCore/list.h"
     60 #include "MagickCore/magick.h"
     61 #include "MagickCore/memory_.h"
     62 #include "MagickCore/monitor.h"
     63 #include "MagickCore/monitor-private.h"
     64 #include "MagickCore/option.h"
     65 #include "MagickCore/quantum-private.h"
     66 #include "MagickCore/resource_.h"
     67 #include "MagickCore/static.h"
     68 #include "MagickCore/string_.h"
     69 #include "MagickCore/module.h"
     70 
     71 #if defined(MAGICKCORE_TIFF_DELEGATE)
     73 /*
     74  Forward declarations.
     75 */
     76 static MagickBooleanType
     77   WriteCALSImage(const ImageInfo *,Image *,ExceptionInfo *);
     78 #endif
     79 
     80 /*
     82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     83 %                                                                             %
     84 %                                                                             %
     85 %                                                                             %
     86 %   I s C A L S                                                               %
     87 %                                                                             %
     88 %                                                                             %
     89 %                                                                             %
     90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     91 %
     92 %  IsCALS() returns MagickTrue if the image format type, identified by the
     93 %  magick string, is CALS Raster Group 1.
     94 %
     95 %  The format of the IsCALS method is:
     96 %
     97 %      MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
     98 %
     99 %  A description of each parameter follows:
    100 %
    101 %    o magick: compare image format pattern against these bytes.
    102 %
    103 %    o length: Specifies the length of the magick string.
    104 %
    105 */
    106 static MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
    107 {
    108   if (length < 128)
    109     return(MagickFalse);
    110   if (LocaleNCompare((const char *) magick,"version: MIL-STD-1840",21) == 0)
    111     return(MagickTrue);
    112   if (LocaleNCompare((const char *) magick,"srcdocid:",9) == 0)
    113     return(MagickTrue);
    114   if (LocaleNCompare((const char *) magick,"rorient:",8) == 0)
    115     return(MagickTrue);
    116   return(MagickFalse);
    117 }
    118 
    119 /*
    121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    122 %                                                                             %
    123 %                                                                             %
    124 %                                                                             %
    125 %   R e a d C A L S I m a g e                                                 %
    126 %                                                                             %
    127 %                                                                             %
    128 %                                                                             %
    129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    130 %
    131 %  ReadCALSImage() reads an CALS Raster Group 1 image format image file and
    132 %  returns it.  It allocates the memory necessary for the new Image structure
    133 %  and returns a pointer to the new image.
    134 %
    135 %  The format of the ReadCALSImage method is:
    136 %
    137 %      Image *ReadCALSImage(const ImageInfo *image_info,
    138 %        ExceptionInfo *exception)
    139 %
    140 %  A description of each parameter follows:
    141 %
    142 %    o image_info: the image info.
    143 %
    144 %    o exception: return any errors or warnings in this structure.
    145 %
    146 */
    147 static Image *ReadCALSImage(const ImageInfo *image_info,
    148   ExceptionInfo *exception)
    149 {
    150   char
    151     filename[MagickPathExtent],
    152     header[MagickPathExtent],
    153     message[MagickPathExtent];
    154 
    155   FILE
    156     *file;
    157 
    158   Image
    159     *image;
    160 
    161   ImageInfo
    162     *read_info;
    163 
    164   int
    165     c,
    166     unique_file;
    167 
    168   MagickBooleanType
    169     status;
    170 
    171   register ssize_t
    172     i;
    173 
    174   unsigned long
    175     density,
    176     direction,
    177     height,
    178     orientation,
    179     pel_path,
    180     type,
    181     width;
    182 
    183   /*
    184     Open image file.
    185   */
    186   assert(image_info != (const ImageInfo *) NULL);
    187   assert(image_info->signature == MagickCoreSignature);
    188   if (image_info->debug != MagickFalse)
    189     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    190       image_info->filename);
    191   assert(exception != (ExceptionInfo *) NULL);
    192   assert(exception->signature == MagickCoreSignature);
    193   image=AcquireImage(image_info,exception);
    194   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    195   if (status == MagickFalse)
    196     {
    197       image=DestroyImageList(image);
    198       return((Image *) NULL);
    199     }
    200   /*
    201     Read CALS header.
    202   */
    203   (void) ResetMagickMemory(header,0,sizeof(header));
    204   density=0;
    205   direction=0;
    206   orientation=1;
    207   pel_path=0;
    208   type=1;
    209   width=0;
    210   height=0;
    211   for (i=0; i < 16; i++)
    212   {
    213     if (ReadBlob(image,128,(unsigned char *) header) != 128)
    214       break;
    215     switch (*header)
    216     {
    217       case 'R':
    218       case 'r':
    219       {
    220         if (LocaleNCompare(header,"rdensty:",8) == 0)
    221           {
    222             (void) sscanf(header+8,"%lu",&density);
    223             break;
    224           }
    225         if (LocaleNCompare(header,"rpelcnt:",8) == 0)
    226           {
    227             (void) sscanf(header+8,"%lu,%lu",&width,&height);
    228             break;
    229           }
    230         if (LocaleNCompare(header,"rorient:",8) == 0)
    231           {
    232             (void) sscanf(header+8,"%lu,%lu",&pel_path,&direction);
    233             if (pel_path == 90)
    234               orientation=5;
    235             else
    236               if (pel_path == 180)
    237                 orientation=3;
    238               else
    239                 if (pel_path == 270)
    240                   orientation=7;
    241             if (direction == 90)
    242               orientation++;
    243             break;
    244           }
    245         if (LocaleNCompare(header,"rtype:",6) == 0)
    246           {
    247             (void) sscanf(header+6,"%lu",&type);
    248             break;
    249           }
    250         break;
    251       }
    252     }
    253   }
    254   /*
    255     Read CALS pixels.
    256   */
    257   file=(FILE *) NULL;
    258   unique_file=AcquireUniqueFileResource(filename);
    259   if (unique_file != -1)
    260     file=fdopen(unique_file,"wb");
    261   if ((unique_file == -1) || (file == (FILE *) NULL))
    262     ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
    263   while ((c=ReadBlobByte(image)) != EOF)
    264     (void) fputc(c,file);
    265   (void) fclose(file);
    266   (void) CloseBlob(image);
    267   image=DestroyImage(image);
    268   read_info=CloneImageInfo(image_info);
    269   SetImageInfoBlob(read_info,(void *) NULL,0);
    270   (void) FormatLocaleString(read_info->filename,MagickPathExtent,"group4:%s",
    271     filename);
    272   (void) FormatLocaleString(message,MagickPathExtent,"%lux%lu",width,height);
    273   (void) CloneString(&read_info->size,message);
    274   (void) FormatLocaleString(message,MagickPathExtent,"%lu",density);
    275   (void) CloneString(&read_info->density,message);
    276   read_info->orientation=(OrientationType) orientation;
    277   image=ReadImage(read_info,exception);
    278   if (image != (Image *) NULL)
    279     {
    280       (void) CopyMagickString(image->filename,image_info->filename,
    281         MagickPathExtent);
    282       (void) CopyMagickString(image->magick_filename,image_info->filename,
    283         MagickPathExtent);
    284       (void) CopyMagickString(image->magick,"CALS",MagickPathExtent);
    285     }
    286   read_info=DestroyImageInfo(read_info);
    287   (void) RelinquishUniqueFileResource(filename);
    288   return(image);
    289 }
    290 
    291 /*
    293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    294 %                                                                             %
    295 %                                                                             %
    296 %                                                                             %
    297 %   R e g i s t e r C A L S I m a g e                                         %
    298 %                                                                             %
    299 %                                                                             %
    300 %                                                                             %
    301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    302 %
    303 %  RegisterCALSImage() adds attributes for the CALS Raster Group 1 image file
    304 %  image format to the list of supported formats.  The attributes include the
    305 %  image format tag, a method to read and/or write the format, whether the
    306 %  format supports the saving of more than one frame to the same file or blob,
    307 %  whether the format supports native in-memory I/O, and a brief description
    308 %  of the format.
    309 %
    310 %  The format of the RegisterCALSImage method is:
    311 %
    312 %      size_t RegisterCALSImage(void)
    313 %
    314 */
    315 ModuleExport size_t RegisterCALSImage(void)
    316 {
    317 #define CALSDescription  "Continuous Acquisition and Life-cycle Support Type 1"
    318 #define CALSNote  "Specified in MIL-R-28002 and MIL-PRF-28002"
    319 
    320   MagickInfo
    321     *entry;
    322 
    323   entry=AcquireMagickInfo("CALS","CAL",CALSDescription);
    324   entry->decoder=(DecodeImageHandler *) ReadCALSImage;
    325 #if defined(MAGICKCORE_TIFF_DELEGATE)
    326   entry->encoder=(EncodeImageHandler *) WriteCALSImage;
    327 #endif
    328   entry->flags^=CoderAdjoinFlag;
    329   entry->magick=(IsImageFormatHandler *) IsCALS;
    330   entry->note=ConstantString(CALSNote);
    331   (void) RegisterMagickInfo(entry);
    332   entry=AcquireMagickInfo("CALS","CALS",CALSDescription);
    333   entry->decoder=(DecodeImageHandler *) ReadCALSImage;
    334 #if defined(MAGICKCORE_TIFF_DELEGATE)
    335   entry->encoder=(EncodeImageHandler *) WriteCALSImage;
    336 #endif
    337   entry->flags^=CoderAdjoinFlag;
    338   entry->magick=(IsImageFormatHandler *) IsCALS;
    339   entry->note=ConstantString(CALSNote);
    340   (void) RegisterMagickInfo(entry);
    341   return(MagickImageCoderSignature);
    342 }
    343 
    344 /*
    346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    347 %                                                                             %
    348 %                                                                             %
    349 %                                                                             %
    350 %   U n r e g i s t e r C A L S I m a g e                                     %
    351 %                                                                             %
    352 %                                                                             %
    353 %                                                                             %
    354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    355 %
    356 %  UnregisterCALSImage() removes format registrations made by the
    357 %  CALS module from the list of supported formats.
    358 %
    359 %  The format of the UnregisterCALSImage method is:
    360 %
    361 %      UnregisterCALSImage(void)
    362 %
    363 */
    364 ModuleExport void UnregisterCALSImage(void)
    365 {
    366   (void) UnregisterMagickInfo("CAL");
    367   (void) UnregisterMagickInfo("CALS");
    368 }
    369 
    370 #if defined(MAGICKCORE_TIFF_DELEGATE)
    372 /*
    373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    374 %                                                                             %
    375 %                                                                             %
    376 %                                                                             %
    377 %   W r i t e C A L S I m a g e                                               %
    378 %                                                                             %
    379 %                                                                             %
    380 %                                                                             %
    381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    382 %
    383 %  WriteCALSImage() writes an image to a file in CALS Raster Group 1 image
    384 %  format.
    385 %
    386 %  The format of the WriteCALSImage method is:
    387 %
    388 %      MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
    389 %        Image *image,ExceptionInfo *exception)
    390 %
    391 %  A description of each parameter follows.
    392 %
    393 %    o image_info: the image info.
    394 %
    395 %    o image:  The image.
    396 %
    397 %    o exception: return any errors or warnings in this structure.
    398 %
    399 */
    400 
    401 static ssize_t WriteCALSRecord(Image *image,const char *data)
    402 {
    403   char
    404     pad[128];
    405 
    406   register const char
    407     *p;
    408 
    409   register ssize_t
    410     i;
    411 
    412   ssize_t
    413     count;
    414 
    415   i=0;
    416   count=0;
    417   if (data != (const char *) NULL)
    418     {
    419       p=data;
    420       for (i=0; (i < 128) && (p[i] != '\0'); i++);
    421       count=WriteBlob(image,(size_t) i,(const unsigned char *) data);
    422     }
    423   if (i < 128)
    424     {
    425       i=128-i;
    426       (void) ResetMagickMemory(pad,' ',(size_t) i);
    427       count=WriteBlob(image,(size_t) i,(const unsigned char *) pad);
    428     }
    429   return(count);
    430 }
    431 
    432 static MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
    433   Image *image,ExceptionInfo *exception)
    434 {
    435   char
    436     header[129];
    437 
    438   Image
    439     *group4_image;
    440 
    441   ImageInfo
    442     *write_info;
    443 
    444   MagickBooleanType
    445     status;
    446 
    447   register ssize_t
    448     i;
    449 
    450   size_t
    451     density,
    452     length,
    453     orient_x,
    454     orient_y;
    455 
    456   ssize_t
    457     count;
    458 
    459   unsigned char
    460     *group4;
    461 
    462   /*
    463     Open output image file.
    464   */
    465   assert(image_info != (const ImageInfo *) NULL);
    466   assert(image_info->signature == MagickCoreSignature);
    467   assert(image != (Image *) NULL);
    468   assert(image->signature == MagickCoreSignature);
    469   if (image->debug != MagickFalse)
    470     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    471   assert(exception != (ExceptionInfo *) NULL);
    472   assert(exception->signature == MagickCoreSignature);
    473   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    474   if (status == MagickFalse)
    475     return(status);
    476   /*
    477     Create standard CALS header.
    478   */
    479   count=WriteCALSRecord(image,"srcdocid: NONE");
    480   (void) count;
    481   count=WriteCALSRecord(image,"dstdocid: NONE");
    482   count=WriteCALSRecord(image,"txtfilid: NONE");
    483   count=WriteCALSRecord(image,"figid: NONE");
    484   count=WriteCALSRecord(image,"srcgph: NONE");
    485   count=WriteCALSRecord(image,"doccls: NONE");
    486   count=WriteCALSRecord(image,"rtype: 1");
    487   orient_x=0;
    488   orient_y=0;
    489   switch (image->orientation)
    490   {
    491     case TopRightOrientation:
    492     {
    493       orient_x=180;
    494       orient_y=270;
    495       break;
    496     }
    497     case BottomRightOrientation:
    498     {
    499       orient_x=180;
    500       orient_y=90;
    501       break;
    502     }
    503     case BottomLeftOrientation:
    504     {
    505       orient_y=90;
    506       break;
    507     }
    508     case LeftTopOrientation:
    509     {
    510       orient_x=270;
    511       break;
    512     }
    513     case RightTopOrientation:
    514     {
    515       orient_x=270;
    516       orient_y=180;
    517       break;
    518     }
    519     case RightBottomOrientation:
    520     {
    521       orient_x=90;
    522       orient_y=180;
    523       break;
    524     }
    525     case LeftBottomOrientation:
    526     {
    527       orient_x=90;
    528       break;
    529     }
    530     default:
    531     {
    532       orient_y=270;
    533       break;
    534     }
    535   }
    536   (void) FormatLocaleString(header,sizeof(header),"rorient: %03ld,%03ld",
    537     (long) orient_x,(long) orient_y);
    538   count=WriteCALSRecord(image,header);
    539   (void) FormatLocaleString(header,sizeof(header),"rpelcnt: %06lu,%06lu",
    540     (unsigned long) image->columns,(unsigned long) image->rows);
    541   count=WriteCALSRecord(image,header);
    542   density=200;
    543   if (image_info->density != (char *) NULL)
    544     {
    545       GeometryInfo
    546         geometry_info;
    547 
    548       (void) ParseGeometry(image_info->density,&geometry_info);
    549       density=(size_t) floor(geometry_info.rho+0.5);
    550     }
    551   (void) FormatLocaleString(header,sizeof(header),"rdensty: %04lu",
    552     (unsigned long) density);
    553   count=WriteCALSRecord(image,header);
    554   count=WriteCALSRecord(image,"notes: NONE");
    555   (void) ResetMagickMemory(header,' ',128);
    556   for (i=0; i < 5; i++)
    557     (void) WriteBlob(image,128,(unsigned char *) header);
    558   /*
    559     Write CALS pixels.
    560   */
    561   write_info=CloneImageInfo(image_info);
    562   (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
    563   (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
    564   group4_image=CloneImage(image,0,0,MagickTrue,exception);
    565   if (group4_image == (Image *) NULL)
    566     {
    567       (void) CloseBlob(image);
    568       return(MagickFalse);
    569     }
    570   group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
    571     exception);
    572   group4_image=DestroyImage(group4_image);
    573   if (group4 == (unsigned char *) NULL)
    574     {
    575       (void) CloseBlob(image);
    576       return(MagickFalse);
    577     }
    578   write_info=DestroyImageInfo(write_info);
    579   if (WriteBlob(image,length,group4) != (ssize_t) length)
    580     status=MagickFalse;
    581   group4=(unsigned char *) RelinquishMagickMemory(group4);
    582   (void) CloseBlob(image);
    583   return(status);
    584 }
    585 #endif
    586