Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                     V   V  IIIII   CCCC   AAA   RRRR                        %
      7 %                     V   V    I    C      A   A  R   R                       %
      8 %                     V   V    I    C      AAAAA  RRRR                        %
      9 %                      V V     I    C      A   A  R R                         %
     10 %                       V    IIIII   CCCC  A   A  R  R                        %
     11 %                                                                             %
     12 %                                                                             %
     13 %                    Read/Write VICAR Rasterfile 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/cache.h"
     48 #include "MagickCore/colormap.h"
     49 #include "MagickCore/colorspace.h"
     50 #include "MagickCore/colorspace-private.h"
     51 #include "MagickCore/constitute.h"
     52 #include "MagickCore/exception.h"
     53 #include "MagickCore/exception-private.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/module.h"
     60 #include "MagickCore/monitor.h"
     61 #include "MagickCore/monitor-private.h"
     62 #include "MagickCore/quantum-private.h"
     63 #include "MagickCore/quantum-private.h"
     64 #include "MagickCore/static.h"
     65 #include "MagickCore/string_.h"
     66 #include "MagickCore/string-private.h"
     67 
     68 /*
     70   Forward declarations.
     71 */
     72 static MagickBooleanType
     73   WriteVICARImage(const ImageInfo *,Image *,ExceptionInfo *);
     74 
     75 /*
     77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     78 %                                                                             %
     79 %                                                                             %
     80 %                                                                             %
     81 %   I s V I C A R                                                             %
     82 %                                                                             %
     83 %                                                                             %
     84 %                                                                             %
     85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     86 %
     87 %  IsVICAR() returns MagickTrue if the image format type, identified by the
     88 %  magick string, is VICAR.
     89 %
     90 %  The format of the IsVICAR method is:
     91 %
     92 %      MagickBooleanType IsVICAR(const unsigned char *magick,
     93 %        const size_t length)
     94 %
     95 %  A description of each parameter follows:
     96 %
     97 %    o magick: compare image format pattern against these bytes.
     98 %
     99 %    o length: Specifies the length of the magick string.
    100 %
    101 */
    102 static MagickBooleanType IsVICAR(const unsigned char *magick,
    103   const size_t length)
    104 {
    105   if (length < 14)
    106     return(MagickFalse);
    107   if (LocaleNCompare((const char *) magick,"LBLSIZE",7) == 0)
    108     return(MagickTrue);
    109   if (LocaleNCompare((const char *) magick,"NJPL1I",6) == 0)
    110     return(MagickTrue);
    111   if (LocaleNCompare((const char *) magick,"PDS_VERSION_ID",14) == 0)
    112     return(MagickTrue);
    113   return(MagickFalse);
    114 }
    115 
    116 /*
    118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    119 %                                                                             %
    120 %                                                                             %
    121 %                                                                             %
    122 %   R e a d V I C A R I m a g e                                               %
    123 %                                                                             %
    124 %                                                                             %
    125 %                                                                             %
    126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    127 %
    128 %  ReadVICARImage() reads a VICAR image file and returns it.  It
    129 %  allocates the memory necessary for the new Image structure and returns a
    130 %  pointer to the new image.
    131 %
    132 %  The format of the ReadVICARImage method is:
    133 %
    134 %      Image *ReadVICARImage(const ImageInfo *image_info,
    135 %        ExceptionInfo *exception)
    136 %
    137 %  A description of each parameter follows:
    138 %
    139 %    o image: Method ReadVICARImage returns a pointer to the image after
    140 %      reading.  A null image is returned if there is a memory shortage or if
    141 %      the image cannot be read.
    142 %
    143 %    o image_info: the image info.
    144 %
    145 %    o exception: return any errors or warnings in this structure.
    146 %
    147 %
    148 */
    149 static Image *ReadVICARImage(const ImageInfo *image_info,
    150   ExceptionInfo *exception)
    151 {
    152   char
    153     keyword[MagickPathExtent],
    154     value[MagickPathExtent];
    155 
    156   const unsigned char
    157     *pixels;
    158 
    159   Image
    160     *image;
    161 
    162   int
    163     c;
    164 
    165   MagickBooleanType
    166     status,
    167     value_expected;
    168 
    169   QuantumInfo
    170     *quantum_info;
    171 
    172   QuantumType
    173     quantum_type;
    174 
    175   register Quantum
    176     *q;
    177 
    178   size_t
    179     length;
    180 
    181   ssize_t
    182     count,
    183     y;
    184 
    185   /*
    186     Open image file.
    187   */
    188   assert(image_info != (const ImageInfo *) NULL);
    189   assert(image_info->signature == MagickCoreSignature);
    190   if (image_info->debug != MagickFalse)
    191     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    192       image_info->filename);
    193   assert(exception != (ExceptionInfo *) NULL);
    194   assert(exception->signature == MagickCoreSignature);
    195   image=AcquireImage(image_info,exception);
    196   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    197   if (status == MagickFalse)
    198     {
    199       image=DestroyImageList(image);
    200       return((Image *) NULL);
    201     }
    202   /*
    203     Decode image header.
    204   */
    205   c=ReadBlobByte(image);
    206   count=1;
    207   if (c == EOF)
    208     {
    209       image=DestroyImage(image);
    210       return((Image *) NULL);
    211     }
    212   length=0;
    213   image->columns=0;
    214   image->rows=0;
    215   while (isgraph(c) && ((image->columns == 0) || (image->rows == 0)))
    216   {
    217     if (isalnum(c) == MagickFalse)
    218       {
    219         c=ReadBlobByte(image);
    220         count++;
    221       }
    222     else
    223       {
    224         register char
    225           *p;
    226 
    227         /*
    228           Determine a keyword and its value.
    229         */
    230         p=keyword;
    231         do
    232         {
    233           if ((size_t) (p-keyword) < (MagickPathExtent-1))
    234             *p++=c;
    235           c=ReadBlobByte(image);
    236           count++;
    237         } while (isalnum(c) || (c == '_'));
    238         *p='\0';
    239         value_expected=MagickFalse;
    240         while ((isspace((int) ((unsigned char) c)) != 0) || (c == '='))
    241         {
    242           if (c == '=')
    243             value_expected=MagickTrue;
    244           c=ReadBlobByte(image);
    245           count++;
    246         }
    247         if (value_expected == MagickFalse)
    248           continue;
    249         p=value;
    250         while (isalnum(c))
    251         {
    252           if ((size_t) (p-value) < (MagickPathExtent-1))
    253             *p++=c;
    254           c=ReadBlobByte(image);
    255           count++;
    256         }
    257         *p='\0';
    258         /*
    259           Assign a value to the specified keyword.
    260         */
    261         if (LocaleCompare(keyword,"Label_RECORDS") == 0)
    262           length=(ssize_t) StringToLong(value);
    263         if (LocaleCompare(keyword,"LBLSIZE") == 0)
    264           length=(ssize_t) StringToLong(value);
    265         if (LocaleCompare(keyword,"RECORD_BYTES") == 0)
    266           image->columns=StringToUnsignedLong(value);
    267         if (LocaleCompare(keyword,"NS") == 0)
    268           image->columns=StringToUnsignedLong(value);
    269         if (LocaleCompare(keyword,"LINES") == 0)
    270           image->rows=StringToUnsignedLong(value);
    271         if (LocaleCompare(keyword,"NL") == 0)
    272           image->rows=StringToUnsignedLong(value);
    273       }
    274     while (isspace((int) ((unsigned char) c)) != 0)
    275     {
    276       c=ReadBlobByte(image);
    277       count++;
    278     }
    279   }
    280   while (count < (ssize_t) length)
    281   {
    282     c=ReadBlobByte(image);
    283     if (c == EOF)
    284       break;
    285     count++;
    286   }
    287   if ((image->columns == 0) || (image->rows == 0))
    288     ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
    289   image->depth=8;
    290   if (image_info->ping != MagickFalse)
    291     {
    292       (void) CloseBlob(image);
    293       return(GetFirstImageInList(image));
    294     }
    295   status=SetImageExtent(image,image->columns,image->rows,exception);
    296   if (status == MagickFalse)
    297     return(DestroyImageList(image));
    298   /*
    299     Read VICAR pixels.
    300   */
    301   (void) SetImageColorspace(image,GRAYColorspace,exception);
    302   quantum_type=GrayQuantum;
    303   quantum_info=AcquireQuantumInfo(image_info,image);
    304   if (quantum_info == (QuantumInfo *) NULL)
    305     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    306   length=GetQuantumExtent(image,quantum_info,quantum_type);
    307   for (y=0; y < (ssize_t) image->rows; y++)
    308   {
    309     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    310     if (q == (Quantum *) NULL)
    311       break;
    312     pixels=(const unsigned char *) ReadBlobStream(image,length,
    313       GetQuantumPixels(quantum_info),&count);
    314     if (count != (ssize_t) length)
    315       break;
    316     (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
    317       quantum_type,pixels,exception);
    318     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    319       break;
    320     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    321       image->rows);
    322     if (status == MagickFalse)
    323       break;
    324   }
    325   SetQuantumImageType(image,quantum_type);
    326   quantum_info=DestroyQuantumInfo(quantum_info);
    327   if (EOFBlob(image) != MagickFalse)
    328     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    329       image->filename);
    330   (void) CloseBlob(image);
    331   return(GetFirstImageInList(image));
    332 }
    333 
    334 /*
    336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    337 %                                                                             %
    338 %                                                                             %
    339 %                                                                             %
    340 %   R e g i s t e r V I C A R I m a g e                                       %
    341 %                                                                             %
    342 %                                                                             %
    343 %                                                                             %
    344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    345 %
    346 %  RegisterVICARImage() adds attributes for the VICAR image format to
    347 %  the list of supported formats.  The attributes include the image format
    348 %  tag, a method to read and/or write the format, whether the format
    349 %  supports the saving of more than one frame to the same file or blob,
    350 %  whether the format supports native in-memory I/O, and a brief
    351 %  description of the format.
    352 %
    353 %  The format of the RegisterVICARImage method is:
    354 %
    355 %      size_t RegisterVICARImage(void)
    356 %
    357 */
    358 ModuleExport size_t RegisterVICARImage(void)
    359 {
    360   MagickInfo
    361     *entry;
    362 
    363   entry=AcquireMagickInfo("VICAR","VICAR","VICAR rasterfile format");
    364   entry->decoder=(DecodeImageHandler *) ReadVICARImage;
    365   entry->encoder=(EncodeImageHandler *) WriteVICARImage;
    366   entry->magick=(IsImageFormatHandler *) IsVICAR;
    367   entry->flags^=CoderAdjoinFlag;
    368   (void) RegisterMagickInfo(entry);
    369   return(MagickImageCoderSignature);
    370 }
    371 
    372 /*
    374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    375 %                                                                             %
    376 %                                                                             %
    377 %                                                                             %
    378 %   U n r e g i s t e r V I C A R I m a g e                                   %
    379 %                                                                             %
    380 %                                                                             %
    381 %                                                                             %
    382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    383 %
    384 %  UnregisterVICARImage() removes format registrations made by the
    385 %  VICAR module from the list of supported formats.
    386 %
    387 %  The format of the UnregisterVICARImage method is:
    388 %
    389 %      UnregisterVICARImage(void)
    390 %
    391 */
    392 ModuleExport void UnregisterVICARImage(void)
    393 {
    394   (void) UnregisterMagickInfo("VICAR");
    395 }
    396 
    397 /*
    399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    400 %                                                                             %
    401 %                                                                             %
    402 %                                                                             %
    403 %   W r i t e V I C A R I m a g e                                             %
    404 %                                                                             %
    405 %                                                                             %
    406 %                                                                             %
    407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    408 %
    409 %  WriteVICARImage() writes an image in the VICAR rasterfile format.
    410 %  Vicar files contain a text header, followed by one or more planes of binary
    411 %  grayscale image data.  Vicar files are designed to allow many planes to be
    412 %  stacked together to form image cubes.  This method only writes a single
    413 %  grayscale plane.
    414 %
    415 %  WriteVICARImage was written contributed by gorelick (at) esther.la.asu.edu.
    416 %
    417 %  The format of the WriteVICARImage method is:
    418 %
    419 %      MagickBooleanType WriteVICARImage(const ImageInfo *image_info,
    420 %        Image *image,ExceptionInfo *exception)
    421 %
    422 %  A description of each parameter follows.
    423 %
    424 %    o image_info: the image info.
    425 %
    426 %    o image:  The image.
    427 %
    428 %    o exception: return any errors or warnings in this structure.
    429 %
    430 */
    431 static MagickBooleanType WriteVICARImage(const ImageInfo *image_info,
    432   Image *image,ExceptionInfo *exception)
    433 {
    434   char
    435     header[MagickPathExtent];
    436 
    437   int
    438     y;
    439 
    440   MagickBooleanType
    441     status;
    442 
    443   QuantumInfo
    444     *quantum_info;
    445 
    446   register const Quantum
    447     *p;
    448 
    449   size_t
    450     length;
    451 
    452   ssize_t
    453     count;
    454 
    455   unsigned char
    456     *pixels;
    457 
    458   /*
    459     Open output image file.
    460   */
    461   assert(image_info != (const ImageInfo *) NULL);
    462   assert(image_info->signature == MagickCoreSignature);
    463   assert(image != (Image *) NULL);
    464   assert(image->signature == MagickCoreSignature);
    465   if (image->debug != MagickFalse)
    466     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    467   assert(exception != (ExceptionInfo *) NULL);
    468   assert(exception->signature == MagickCoreSignature);
    469   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    470   if (status == MagickFalse)
    471     return(status);
    472   (void) TransformImageColorspace(image,sRGBColorspace,exception);
    473   /*
    474     Write header.
    475   */
    476   (void) ResetMagickMemory(header,' ',MagickPathExtent);
    477   (void) FormatLocaleString(header,MagickPathExtent,
    478     "LBLSIZE=%.20g FORMAT='BYTE' TYPE='IMAGE' BUFSIZE=20000 DIM=2 EOL=0 "
    479     "RECSIZE=%.20g ORG='BSQ' NL=%.20g NS=%.20g NB=1 N1=0 N2=0 N3=0 N4=0 NBB=0 "
    480     "NLB=0 TASK='ImageMagick'",(double) MagickPathExtent,(double) image->columns,
    481     (double) image->rows,(double) image->columns);
    482   (void) WriteBlob(image,MagickPathExtent,(unsigned char *) header);
    483   /*
    484     Write VICAR pixels.
    485   */
    486   image->depth=8;
    487   quantum_info=AcquireQuantumInfo(image_info,image);
    488   if (quantum_info == (QuantumInfo *) NULL)
    489     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    490   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
    491   for (y=0; y < (ssize_t) image->rows; y++)
    492   {
    493     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    494     if (p == (const Quantum *) NULL)
    495       break;
    496     length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
    497       GrayQuantum,pixels,exception);
    498     count=WriteBlob(image,length,pixels);
    499     if (count != (ssize_t) length)
    500       break;
    501     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    502       image->rows);
    503     if (status == MagickFalse)
    504       break;
    505   }
    506   quantum_info=DestroyQuantumInfo(quantum_info);
    507   (void) CloseBlob(image);
    508   return(MagickTrue);
    509 }
    510