Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                         GGGG  RRRR    AAA   Y   Y                           %
      7 %                        G      R   R  A   A   Y Y                            %
      8 %                        G  GG  RRRR   AAAAA    Y                             %
      9 %                        G   G  R R    A   A    Y                             %
     10 %                         GGG   R  R   A   A    Y                             %
     11 %                                                                             %
     12 %                                                                             %
     13 %                    Read/Write RAW Gray 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/cache.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/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/pixel.h"
     61 #include "MagickCore/pixel-accessor.h"
     62 #include "MagickCore/quantum-private.h"
     63 #include "MagickCore/static.h"
     64 #include "MagickCore/statistic.h"
     65 #include "MagickCore/string_.h"
     66 #include "MagickCore/module.h"
     67 
     68 /*
     70   Forward declarations.
     71 */
     72 static MagickBooleanType
     73   WriteGRAYImage(const ImageInfo *,Image *,ExceptionInfo *);
     74 
     75 /*
     77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     78 %                                                                             %
     79 %                                                                             %
     80 %                                                                             %
     81 %   R e a d G R A Y I m a g e                                                 %
     82 %                                                                             %
     83 %                                                                             %
     84 %                                                                             %
     85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     86 %
     87 %  ReadGRAYImage() reads an image of raw grayscale samples and returns
     88 %  it.  It allocates the memory necessary for the new Image structure and
     89 %  returns a pointer to the new image.
     90 %
     91 %  The format of the ReadGRAYImage method is:
     92 %
     93 %      Image *ReadGRAYImage(const ImageInfo *image_info,
     94 %        ExceptionInfo *exception)
     95 %
     96 %  A description of each parameter follows:
     97 %
     98 %    o image_info: the image info.
     99 %
    100 %    o exception: return any errors or warnings in this structure.
    101 %
    102 */
    103 static Image *ReadGRAYImage(const ImageInfo *image_info,
    104   ExceptionInfo *exception)
    105 {
    106   const unsigned char
    107     *pixels;
    108 
    109   Image
    110     *canvas_image,
    111     *image;
    112 
    113   MagickBooleanType
    114     status;
    115 
    116   MagickOffsetType
    117     scene;
    118 
    119   QuantumInfo
    120     *quantum_info;
    121 
    122   QuantumType
    123     quantum_type;
    124 
    125   size_t
    126     length;
    127 
    128   ssize_t
    129     count,
    130     y;
    131 
    132   /*
    133     Open image file.
    134   */
    135   assert(image_info != (const ImageInfo *) NULL);
    136   assert(image_info->signature == MagickCoreSignature);
    137   if (image_info->debug != MagickFalse)
    138     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    139       image_info->filename);
    140   assert(exception != (ExceptionInfo *) NULL);
    141   assert(exception->signature == MagickCoreSignature);
    142   image=AcquireImage(image_info,exception);
    143   if ((image->columns == 0) || (image->rows == 0))
    144     ThrowReaderException(OptionError,"MustSpecifyImageSize");
    145   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    146   if (status == MagickFalse)
    147     {
    148       image=DestroyImageList(image);
    149       return((Image *) NULL);
    150     }
    151   if (DiscardBlobBytes(image,(size_t) image->offset) == MagickFalse)
    152     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    153       image->filename);
    154   /*
    155     Create virtual canvas to support cropping (i.e. image.gray[100x100+10+20]).
    156   */
    157   SetImageColorspace(image,GRAYColorspace,exception);
    158   canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
    159     exception);
    160   (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod,
    161     exception);
    162   quantum_type=GrayQuantum;
    163   quantum_info=AcquireQuantumInfo(image_info,canvas_image);
    164   if (quantum_info == (QuantumInfo *) NULL)
    165     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    166   pixels=(const unsigned char *) NULL;
    167   if (image_info->number_scenes != 0)
    168     while (image->scene < image_info->scene)
    169     {
    170       /*
    171         Skip to next image.
    172       */
    173       image->scene++;
    174       length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
    175       for (y=0; y < (ssize_t) image->rows; y++)
    176       {
    177         pixels=(const unsigned char *) ReadBlobStream(image,length,
    178           GetQuantumPixels(quantum_info),&count);
    179         if (count != (ssize_t) length)
    180           break;
    181       }
    182     }
    183   scene=0;
    184   count=0;
    185   length=0;
    186   do
    187   {
    188     /*
    189       Read pixels to virtual canvas image then push to image.
    190     */
    191     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
    192       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    193         break;
    194     status=SetImageExtent(image,image->columns,image->rows,exception);
    195     if (status == MagickFalse)
    196       return(DestroyImageList(image));
    197     SetImageColorspace(image,GRAYColorspace,exception);
    198     if (scene == 0)
    199       {
    200         length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
    201         pixels=(const unsigned char *) ReadBlobStream(image,length,
    202           GetQuantumPixels(quantum_info),&count);
    203       }
    204     for (y=0; y < (ssize_t) image->extract_info.height; y++)
    205     {
    206       register const Quantum
    207         *magick_restrict p;
    208 
    209       register ssize_t
    210         x;
    211 
    212       register Quantum
    213         *magick_restrict q;
    214 
    215       if (count != (ssize_t) length)
    216         {
    217           ThrowFileException(exception,CorruptImageError,
    218             "UnexpectedEndOfFile",image->filename);
    219           break;
    220         }
    221       q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,exception);
    222       if (q == (Quantum *) NULL)
    223         break;
    224       length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,quantum_info,
    225         quantum_type,pixels,exception);
    226       if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
    227         break;
    228       if (((y-image->extract_info.y) >= 0) &&
    229           ((y-image->extract_info.y) < (ssize_t) image->rows))
    230         {
    231           p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
    232             image->columns,1,exception);
    233           q=QueueAuthenticPixels(image,0,y-image->extract_info.y,image->columns,
    234             1,exception);
    235           if ((p == (const Quantum *) NULL) ||
    236               (q == (Quantum *) NULL))
    237             break;
    238           for (x=0; x < (ssize_t) image->columns; x++)
    239           {
    240             SetPixelGray(image,GetPixelGray(canvas_image,p),q);
    241             p+=GetPixelChannels(canvas_image);
    242             q+=GetPixelChannels(image);
    243           }
    244           if (SyncAuthenticPixels(image,exception) == MagickFalse)
    245             break;
    246         }
    247       if (image->previous == (Image *) NULL)
    248         {
    249           status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    250             image->rows);
    251           if (status == MagickFalse)
    252             break;
    253         }
    254       pixels=(const unsigned char *) ReadBlobStream(image,length,
    255         GetQuantumPixels(quantum_info),&count);
    256     }
    257     SetQuantumImageType(image,quantum_type);
    258     /*
    259       Proceed to next image.
    260     */
    261     if (image_info->number_scenes != 0)
    262       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    263         break;
    264     if (count == (ssize_t) length)
    265       {
    266         /*
    267           Allocate next image structure.
    268         */
    269         AcquireNextImage(image_info,image,exception);
    270         if (GetNextImageInList(image) == (Image *) NULL)
    271           {
    272             image=DestroyImageList(image);
    273             return((Image *) NULL);
    274           }
    275         image=SyncNextImageInList(image);
    276         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
    277           GetBlobSize(image));
    278         if (status == MagickFalse)
    279           break;
    280       }
    281     scene++;
    282   } while (count == (ssize_t) length);
    283   quantum_info=DestroyQuantumInfo(quantum_info);
    284   canvas_image=DestroyImage(canvas_image);
    285   (void) CloseBlob(image);
    286   return(GetFirstImageInList(image));
    287 }
    288 
    289 /*
    291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    292 %                                                                             %
    293 %                                                                             %
    294 %                                                                             %
    295 %   R e g i s t e r G R A Y I m a g e                                         %
    296 %                                                                             %
    297 %                                                                             %
    298 %                                                                             %
    299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    300 %
    301 %  RegisterGRAYImage() adds attributes for the GRAY image format to
    302 %  the list of supported formats.  The attributes include the image format
    303 %  tag, a method to read and/or write the format, whether the format
    304 %  supports the saving of more than one frame to the same file or blob,
    305 %  whether the format supports native in-memory I/O, and a brief
    306 %  description of the format.
    307 %
    308 %  The format of the RegisterGRAYImage method is:
    309 %
    310 %      size_t RegisterGRAYImage(void)
    311 %
    312 */
    313 ModuleExport size_t RegisterGRAYImage(void)
    314 {
    315   MagickInfo
    316     *entry;
    317 
    318   entry=AcquireMagickInfo("GRAY","GRAY","Raw gray samples");
    319   entry->decoder=(DecodeImageHandler *) ReadGRAYImage;
    320   entry->encoder=(EncodeImageHandler *) WriteGRAYImage;
    321   entry->flags|=CoderRawSupportFlag;
    322   entry->flags|=CoderEndianSupportFlag;
    323   (void) RegisterMagickInfo(entry);
    324   return(MagickImageCoderSignature);
    325 }
    326 
    327 /*
    329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    330 %                                                                             %
    331 %                                                                             %
    332 %                                                                             %
    333 %   U n r e g i s t e r G R A Y I m a g e                                     %
    334 %                                                                             %
    335 %                                                                             %
    336 %                                                                             %
    337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    338 %
    339 %  UnregisterGRAYImage() removes format registrations made by the
    340 %  GRAY module from the list of supported formats.
    341 %
    342 %  The format of the UnregisterGRAYImage method is:
    343 %
    344 %      UnregisterGRAYImage(void)
    345 %
    346 */
    347 ModuleExport void UnregisterGRAYImage(void)
    348 {
    349   (void) UnregisterMagickInfo("GRAY");
    350 }
    351 
    352 /*
    354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    355 %                                                                             %
    356 %                                                                             %
    357 %                                                                             %
    358 %   W r i t e G R A Y I m a g e                                               %
    359 %                                                                             %
    360 %                                                                             %
    361 %                                                                             %
    362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    363 %
    364 %  WriteGRAYImage() writes an image to a file as gray scale intensity
    365 %  values.
    366 %
    367 %  The format of the WriteGRAYImage method is:
    368 %
    369 %      MagickBooleanType WriteGRAYImage(const ImageInfo *image_info,
    370 %        Image *image,ExceptionInfo *exception)
    371 %
    372 %  A description of each parameter follows.
    373 %
    374 %    o image_info: the image info.
    375 %
    376 %    o image:  The image.
    377 %
    378 %    o exception: return any errors or warnings in this structure.
    379 %
    380 */
    381 static MagickBooleanType WriteGRAYImage(const ImageInfo *image_info,
    382   Image *image,ExceptionInfo *exception)
    383 {
    384   MagickBooleanType
    385     status;
    386 
    387   MagickOffsetType
    388     scene;
    389 
    390   QuantumInfo
    391     *quantum_info;
    392 
    393   QuantumType
    394     quantum_type;
    395 
    396   size_t
    397     length;
    398 
    399   ssize_t
    400     count,
    401     y;
    402 
    403   unsigned char
    404     *pixels;
    405 
    406   /*
    407     Open output image file.
    408   */
    409   assert(image_info != (const ImageInfo *) NULL);
    410   assert(image_info->signature == MagickCoreSignature);
    411   assert(image != (Image *) NULL);
    412   assert(image->signature == MagickCoreSignature);
    413   if (image->debug != MagickFalse)
    414     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    415   assert(exception != (ExceptionInfo *) NULL);
    416   assert(exception->signature == MagickCoreSignature);
    417   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    418   if (status == MagickFalse)
    419     return(status);
    420   scene=0;
    421   do
    422   {
    423     /*
    424       Write grayscale pixels.
    425     */
    426     (void) TransformImageColorspace(image,sRGBColorspace,exception);
    427     quantum_type=GrayQuantum;
    428     quantum_info=AcquireQuantumInfo(image_info,image);
    429     if (quantum_info == (QuantumInfo *) NULL)
    430       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    431     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
    432     for (y=0; y < (ssize_t) image->rows; y++)
    433     {
    434       register const Quantum
    435         *magick_restrict p;
    436 
    437       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    438       if (p == (const Quantum *) NULL)
    439         break;
    440       length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
    441         quantum_type,pixels,exception);
    442       count=WriteBlob(image,length,pixels);
    443       if (count != (ssize_t) length)
    444         break;
    445       if (image->previous == (Image *) NULL)
    446         {
    447           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    448             image->rows);
    449           if (status == MagickFalse)
    450             break;
    451         }
    452     }
    453     quantum_info=DestroyQuantumInfo(quantum_info);
    454     if (GetNextImageInList(image) == (Image *) NULL)
    455       break;
    456     image=SyncNextImageInList(image);
    457     status=SetImageProgress(image,SaveImagesTag,scene++,
    458       GetImageListLength(image));
    459     if (status == MagickFalse)
    460       break;
    461   } while (image_info->adjoin != MagickFalse);
    462   (void) CloseBlob(image);
    463   return(MagickTrue);
    464 }
    465