Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            RRRR    AAA   W   W                              %
      7 %                            R   R  A   A  W   W                              %
      8 %                            RRRR   AAAAA  W W W                              %
      9 %                            R R    A   A  WW WW                              %
     10 %                            R  R   A   A  W   W                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                       Read/Write RAW 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/blob.h"
     45 #include "MagickCore/blob-private.h"
     46 #include "MagickCore/cache.h"
     47 #include "MagickCore/colorspace.h"
     48 #include "MagickCore/constitute.h"
     49 #include "MagickCore/exception.h"
     50 #include "MagickCore/exception-private.h"
     51 #include "MagickCore/image.h"
     52 #include "MagickCore/image-private.h"
     53 #include "MagickCore/list.h"
     54 #include "MagickCore/magick.h"
     55 #include "MagickCore/memory_.h"
     56 #include "MagickCore/monitor.h"
     57 #include "MagickCore/monitor-private.h"
     58 #include "MagickCore/pixel-accessor.h"
     59 #include "MagickCore/quantum-private.h"
     60 #include "MagickCore/quantum-private.h"
     61 #include "MagickCore/static.h"
     62 #include "MagickCore/statistic.h"
     63 #include "MagickCore/string_.h"
     64 #include "MagickCore/module.h"
     65 
     66 /*
     68   Forward declarations.
     69 */
     70 static MagickBooleanType
     71   WriteRAWImage(const ImageInfo *,Image *,ExceptionInfo *);
     72 
     73 /*
     75 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     76 %                                                                             %
     77 %                                                                             %
     78 %                                                                             %
     79 %   R e a d R A W I m a g e                                                   %
     80 %                                                                             %
     81 %                                                                             %
     82 %                                                                             %
     83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     84 %
     85 %  ReadRAWImage() reads an image of raw samples and returns it.  It allocates
     86 %  the memory necessary for the new Image structure and returns a pointer to
     87 %  the new image.
     88 %
     89 %  The format of the ReadRAWImage method is:
     90 %
     91 %      Image *ReadRAWImage(const ImageInfo *image_info,ExceptionInfo *exception)
     92 %
     93 %  A description of each parameter follows:
     94 %
     95 %    o image_info: the image info.
     96 %
     97 %    o exception: return any errors or warnings in this structure.
     98 %
     99 */
    100 static Image *ReadRAWImage(const ImageInfo *image_info,ExceptionInfo *exception)
    101 {
    102   const unsigned char
    103     *pixels;
    104 
    105   Image
    106     *canvas_image,
    107     *image;
    108 
    109   MagickBooleanType
    110     status;
    111 
    112   MagickOffsetType
    113     scene;
    114 
    115   QuantumInfo
    116     *quantum_info;
    117 
    118   QuantumType
    119     quantum_type;
    120 
    121   size_t
    122     length;
    123 
    124   ssize_t
    125     count,
    126     y;
    127 
    128   /*
    129     Open image file.
    130   */
    131   assert(image_info != (const ImageInfo *) NULL);
    132   assert(image_info->signature == MagickCoreSignature);
    133   if (image_info->debug != MagickFalse)
    134     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    135       image_info->filename);
    136   assert(exception != (ExceptionInfo *) NULL);
    137   assert(exception->signature == MagickCoreSignature);
    138   image=AcquireImage(image_info,exception);
    139   if ((image->columns == 0) || (image->rows == 0))
    140     ThrowReaderException(OptionError,"MustSpecifyImageSize");
    141   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    142   if (status == MagickFalse)
    143     {
    144       image=DestroyImageList(image);
    145       return((Image *) NULL);
    146     }
    147   if (DiscardBlobBytes(image,image->offset) == MagickFalse)
    148     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    149       image->filename);
    150   /*
    151     Create virtual canvas to support cropping (i.e. image.gray[100x100+10+20]).
    152   */
    153   canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
    154     exception);
    155   (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod,
    156     exception);
    157   quantum_type=GrayQuantum;
    158   quantum_info=AcquireQuantumInfo(image_info,canvas_image);
    159   if (quantum_info == (QuantumInfo *) NULL)
    160     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    161   pixels=(const unsigned char *) NULL;
    162   if (image_info->number_scenes != 0)
    163     while (image->scene < image_info->scene)
    164     {
    165       /*
    166         Skip to next image.
    167       */
    168       image->scene++;
    169       length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
    170       for (y=0; y < (ssize_t) image->rows; y++)
    171       {
    172         pixels=(const unsigned char *) ReadBlobStream(image,length,
    173           GetQuantumPixels(quantum_info),&count);
    174         if (count != (ssize_t) length)
    175           break;
    176       }
    177     }
    178   scene=0;
    179   count=0;
    180   length=0;
    181   do
    182   {
    183     /*
    184       Read pixels to virtual canvas image then push to image.
    185     */
    186     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
    187       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    188         break;
    189     status=SetImageExtent(image,image->columns,image->rows,exception);
    190     if (status == MagickFalse)
    191       return(DestroyImageList(image));
    192     if (scene == 0)
    193       {
    194         length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
    195         pixels=(const unsigned char *) ReadBlobStream(image,length,
    196           GetQuantumPixels(quantum_info),&count);
    197       }
    198     for (y=0; y < (ssize_t) image->extract_info.height; y++)
    199     {
    200       register const Quantum
    201         *magick_restrict p;
    202 
    203       register Quantum
    204         *magick_restrict q;
    205 
    206       register ssize_t
    207         x;
    208 
    209       if (count != (ssize_t) length)
    210         {
    211           ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    212             image->filename);
    213           break;
    214         }
    215       q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,exception);
    216       if (q == (Quantum *) NULL)
    217         break;
    218       length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,quantum_info,
    219         quantum_type,pixels,exception);
    220       if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
    221         break;
    222       if (((y-image->extract_info.y) >= 0) &&
    223           ((y-image->extract_info.y) < (ssize_t) image->rows))
    224         {
    225           p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
    226             image->columns,1,exception);
    227           q=QueueAuthenticPixels(image,0,y-image->extract_info.y,image->columns,
    228             1,exception);
    229           if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
    230             break;
    231           for (x=0; x < (ssize_t) image->columns; x++)
    232           {
    233             SetPixelRed(image,GetPixelRed(canvas_image,p),q);
    234             SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
    235             SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
    236             p+=GetPixelChannels(canvas_image);
    237             q+=GetPixelChannels(image);
    238           }
    239           if (SyncAuthenticPixels(image,exception) == MagickFalse)
    240             break;
    241         }
    242       if (image->previous == (Image *) NULL)
    243         {
    244           status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    245             image->rows);
    246           if (status == MagickFalse)
    247             break;
    248         }
    249       pixels=(const unsigned char *) ReadBlobStream(image,length,
    250         GetQuantumPixels(quantum_info),&count);
    251     }
    252     SetQuantumImageType(image,quantum_type);
    253     /*
    254       Proceed to next image.
    255     */
    256     if (image_info->number_scenes != 0)
    257       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
    258         break;
    259     if (count == (ssize_t) length)
    260       {
    261         /*
    262           Allocate next image structure.
    263         */
    264         AcquireNextImage(image_info,image,exception);
    265         if (GetNextImageInList(image) == (Image *) NULL)
    266           {
    267             image=DestroyImageList(image);
    268             return((Image *) NULL);
    269           }
    270         image=SyncNextImageInList(image);
    271         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
    272           GetBlobSize(image));
    273         if (status == MagickFalse)
    274           break;
    275       }
    276     scene++;
    277   } while (count == (ssize_t) length);
    278   quantum_info=DestroyQuantumInfo(quantum_info);
    279   canvas_image=DestroyImage(canvas_image);
    280   (void) CloseBlob(image);
    281   return(GetFirstImageInList(image));
    282 }
    283 
    284 /*
    286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    287 %                                                                             %
    288 %                                                                             %
    289 %                                                                             %
    290 %   R e g i s t e r R A W I m a g e                                           %
    291 %                                                                             %
    292 %                                                                             %
    293 %                                                                             %
    294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    295 %
    296 %  RegisterRAWImage() adds attributes for the RAW image format to the list of
    297 %  supported formats.  The attributes include the image format tag, a method to
    298 %  read and/or write the format, whether the format supports the saving of
    299 %  more than one frame to the same file or blob, whether the format supports
    300 %  native in-memory I/O, and a brief description of the format.
    301 %
    302 %  The format of the RegisterRAWImage method is:
    303 %
    304 %      size_t RegisterRAWImage(void)
    305 %
    306 */
    307 ModuleExport size_t RegisterRAWImage(void)
    308 {
    309   MagickInfo
    310     *entry;
    311 
    312   entry=AcquireMagickInfo("RAW","R","Raw red samples");
    313   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    314   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    315   entry->flags|=CoderRawSupportFlag;
    316   entry->flags|=CoderEndianSupportFlag;
    317   entry->format_type=ImplicitFormatType;
    318   (void) RegisterMagickInfo(entry);
    319   entry=AcquireMagickInfo("RAW","C","Raw cyan samples");
    320   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    321   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    322   entry->flags|=CoderRawSupportFlag;
    323   entry->flags|=CoderEndianSupportFlag;
    324   entry->format_type=ImplicitFormatType;
    325   (void) RegisterMagickInfo(entry);
    326   entry=AcquireMagickInfo("RAW","G","Raw green samples");
    327   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    328   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    329   entry->flags|=CoderRawSupportFlag;
    330   entry->flags|=CoderEndianSupportFlag;
    331   entry->format_type=ImplicitFormatType;
    332   (void) RegisterMagickInfo(entry);
    333   entry=AcquireMagickInfo("RAW","M","Raw magenta samples");
    334   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    335   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    336   entry->flags|=CoderRawSupportFlag;
    337   entry->flags|=CoderEndianSupportFlag;
    338   entry->format_type=ImplicitFormatType;
    339   (void) RegisterMagickInfo(entry);
    340   entry=AcquireMagickInfo("RAW","B","Raw blue samples");
    341   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    342   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    343   entry->flags|=CoderRawSupportFlag;
    344   entry->flags|=CoderEndianSupportFlag;
    345   entry->format_type=ImplicitFormatType;
    346   (void) RegisterMagickInfo(entry);
    347   entry=AcquireMagickInfo("RAW","Y","Raw yellow samples");
    348   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    349   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    350   entry->flags|=CoderRawSupportFlag;
    351   entry->flags|=CoderEndianSupportFlag;
    352   entry->format_type=ImplicitFormatType;
    353   (void) RegisterMagickInfo(entry);
    354   entry=AcquireMagickInfo("RAW","A","Raw alpha samples");
    355   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    356   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    357   entry->flags|=CoderRawSupportFlag;
    358   entry->flags|=CoderEndianSupportFlag;
    359   entry->format_type=ImplicitFormatType;
    360   (void) RegisterMagickInfo(entry);
    361   entry=AcquireMagickInfo("RAW","O","Raw opacity samples");
    362   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    363   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    364   entry->flags|=CoderRawSupportFlag;
    365   entry->flags|=CoderEndianSupportFlag;
    366   entry->format_type=ImplicitFormatType;
    367   (void) RegisterMagickInfo(entry);
    368   entry=AcquireMagickInfo("RAW","K","Raw black samples");
    369   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
    370   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
    371   entry->flags|=CoderRawSupportFlag;
    372   entry->flags|=CoderEndianSupportFlag;
    373   entry->format_type=ImplicitFormatType;
    374   (void) RegisterMagickInfo(entry);
    375   return(MagickImageCoderSignature);
    376 }
    377 
    378 /*
    380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    381 %                                                                             %
    382 %                                                                             %
    383 %                                                                             %
    384 %   U n r e g i s t e r R A W I m a g e                                       %
    385 %                                                                             %
    386 %                                                                             %
    387 %                                                                             %
    388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    389 %
    390 %  UnregisterRAWImage() removes format registrations made by the RAW module
    391 %  from the list of supported formats.
    392 %
    393 %  The format of the UnregisterRAWImage method is:
    394 %
    395 %      UnregisterRAWImage(void)
    396 %
    397 */
    398 ModuleExport void UnregisterRAWImage(void)
    399 {
    400   (void) UnregisterMagickInfo("R");
    401   (void) UnregisterMagickInfo("C");
    402   (void) UnregisterMagickInfo("G");
    403   (void) UnregisterMagickInfo("M");
    404   (void) UnregisterMagickInfo("B");
    405   (void) UnregisterMagickInfo("Y");
    406   (void) UnregisterMagickInfo("A");
    407   (void) UnregisterMagickInfo("O");
    408   (void) UnregisterMagickInfo("K");
    409 }
    410 
    411 /*
    413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    414 %                                                                             %
    415 %                                                                             %
    416 %                                                                             %
    417 %   W r i t e R A W I m a g e                                                 %
    418 %                                                                             %
    419 %                                                                             %
    420 %                                                                             %
    421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    422 %
    423 %  WriteRAWImage() writes an image to a file as raw intensity values.
    424 %
    425 %  The format of the WriteRAWImage method is:
    426 %
    427 %      MagickBooleanType WriteRAWImage(const ImageInfo *image_info,
    428 %        Image *image,ExceptionInfo *exception)
    429 %
    430 %  A description of each parameter follows.
    431 %
    432 %    o image_info: the image info.
    433 %
    434 %    o image:  The image.
    435 %
    436 %    o exception: return any errors or warnings in this structure.
    437 %
    438 */
    439 static MagickBooleanType WriteRAWImage(const ImageInfo *image_info,Image *image,
    440   ExceptionInfo *exception)
    441 {
    442   MagickOffsetType
    443     scene;
    444 
    445   QuantumInfo
    446     *quantum_info;
    447 
    448   QuantumType
    449     quantum_type;
    450 
    451   MagickBooleanType
    452     status;
    453 
    454   register const Quantum
    455     *p;
    456 
    457   size_t
    458     length;
    459 
    460   ssize_t
    461     count,
    462     y;
    463 
    464   unsigned char
    465     *pixels;
    466 
    467   /*
    468     Open output image file.
    469   */
    470   assert(image_info != (const ImageInfo *) NULL);
    471   assert(image_info->signature == MagickCoreSignature);
    472   assert(image != (Image *) NULL);
    473   assert(image->signature == MagickCoreSignature);
    474   if (image->debug != MagickFalse)
    475     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    476   assert(exception != (ExceptionInfo *) NULL);
    477   assert(exception->signature == MagickCoreSignature);
    478   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    479   if (status == MagickFalse)
    480     return(status);
    481   switch (*image->magick)
    482   {
    483     case 'A':
    484     case 'a':
    485     {
    486       quantum_type=AlphaQuantum;
    487       break;
    488     }
    489     case 'B':
    490     case 'b':
    491     {
    492       quantum_type=BlueQuantum;
    493       break;
    494     }
    495     case 'C':
    496     case 'c':
    497     {
    498       quantum_type=CyanQuantum;
    499       if (image->colorspace == CMYKColorspace)
    500         break;
    501       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
    502     }
    503     case 'g':
    504     case 'G':
    505     {
    506       quantum_type=GreenQuantum;
    507       break;
    508     }
    509     case 'I':
    510     case 'i':
    511     {
    512       quantum_type=IndexQuantum;
    513       break;
    514     }
    515     case 'K':
    516     case 'k':
    517     {
    518       quantum_type=BlackQuantum;
    519       if (image->colorspace == CMYKColorspace)
    520         break;
    521       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
    522     }
    523     case 'M':
    524     case 'm':
    525     {
    526       quantum_type=MagentaQuantum;
    527       if (image->colorspace == CMYKColorspace)
    528         break;
    529       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
    530     }
    531     case 'o':
    532     case 'O':
    533     {
    534       quantum_type=OpacityQuantum;
    535       break;
    536     }
    537     case 'R':
    538     case 'r':
    539     {
    540       quantum_type=RedQuantum;
    541       break;
    542     }
    543     case 'Y':
    544     case 'y':
    545     {
    546       quantum_type=YellowQuantum;
    547       if (image->colorspace == CMYKColorspace)
    548         break;
    549       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
    550     }
    551     default:
    552     {
    553       quantum_type=GrayQuantum;
    554       break;
    555     }
    556   }
    557   scene=0;
    558   do
    559   {
    560     /*
    561       Convert image to RAW raster pixels.
    562     */
    563     quantum_info=AcquireQuantumInfo(image_info,image);
    564     if (quantum_info == (QuantumInfo *) NULL)
    565       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    566     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
    567     for (y=0; y < (ssize_t) image->rows; y++)
    568     {
    569       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    570       if (p == (const Quantum *) NULL)
    571         break;
    572       length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
    573         quantum_type,pixels,exception);
    574       count=WriteBlob(image,length,pixels);
    575       if (count != (ssize_t) length)
    576         break;
    577       if (image->previous == (Image *) NULL)
    578         {
    579           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    580             image->rows);
    581           if (status == MagickFalse)
    582             break;
    583         }
    584     }
    585     quantum_info=DestroyQuantumInfo(quantum_info);
    586     if (GetNextImageInList(image) == (Image *) NULL)
    587       break;
    588     image=SyncNextImageInList(image);
    589     status=SetImageProgress(image,SaveImagesTag,scene++,
    590       GetImageListLength(image));
    591     if (status == MagickFalse)
    592       break;
    593   } while (image_info->adjoin != MagickFalse);
    594   (void) CloseBlob(image);
    595   return(MagickTrue);
    596 }
    597