Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            PPPP    GGGG  X   X                              %
      7 %                            P   P  G       X X                               %
      8 %                            PPPP   G  GG    X                                %
      9 %                            P      G   G   X X                               %
     10 %                            P       GGG   X   X                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                           PGX JPEG 2000 Format                              %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 2016                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2019 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 %    https://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/color-private.h"
     49 #include "MagickCore/colormap.h"
     50 #include "MagickCore/colorspace.h"
     51 #include "MagickCore/colorspace-private.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/monitor.h"
     60 #include "MagickCore/monitor-private.h"
     61 #include "MagickCore/quantum-private.h"
     62 #include "MagickCore/static.h"
     63 #include "MagickCore/string_.h"
     64 #include "MagickCore/module.h"
     65 
     66 /*
     68   Forward declarations.
     69 */
     70 static MagickBooleanType
     71   WritePGXImage(const ImageInfo *,Image *,ExceptionInfo *);
     72 
     73 /*
     75 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     76 %                                                                             %
     77 %                                                                             %
     78 %                                                                             %
     79 %   I s P G X                                                                 %
     80 %                                                                             %
     81 %                                                                             %
     82 %                                                                             %
     83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     84 %
     85 %  IsPGXreturns True if the image format type, identified by the magick
     86 %  string, is PGX.
     87 %
     88 %  The format of the IsPGX method is:
     89 %
     90 %      unsigned int IsPGX(const unsigned char *magick,const size_t length)
     91 %
     92 %  A description of each parameter follows:
     93 %
     94 %    o magick: compare image format pattern against these bytes.
     95 %
     96 %    o length: Specifies the length of the magick string.
     97 %
     98 */
     99 static unsigned int IsPGX(const unsigned char *magick,const size_t length)
    100 {
    101   if (length < 5)
    102     return(MagickFalse);
    103   if ((memcmp(magick,"PG ML",5) == 0) || (memcmp(magick,"PG LM",5) == 0))
    104     return(MagickTrue);
    105   return(MagickFalse);
    106 }
    107 
    108 /*
    110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    111 %                                                                             %
    112 %                                                                             %
    113 %                                                                             %
    114 %   R e a d P G X I m a g e                                                   %
    115 %                                                                             %
    116 %                                                                             %
    117 %                                                                             %
    118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    119 %
    120 %  ReadPGXImage() reads an image of raw bits in LSB order and returns it.
    121 %  It allocates the memory necessary for the new Image structure and returns
    122 %  a pointer to the new image.
    123 %
    124 %  The format of the ReadPGXImage method is:
    125 %
    126 %      Image *ReadPGXImage(const ImageInfo *image_info,
    127 %        ExceptionInfo *exception)
    128 %
    129 %  A description of each parameter follows:
    130 %
    131 %    o image_info: the image info.
    132 %
    133 %    o exception: return any errors or warnings in this structure.
    134 %
    135 */
    136 static Image *ReadPGXImage(const ImageInfo *image_info,ExceptionInfo *exception)
    137 {
    138   char
    139     buffer[MagickPathExtent],
    140     endian[MagickPathExtent],
    141     sans[MagickPathExtent],
    142     sign[MagickPathExtent];
    143 
    144   const unsigned char
    145     *pixels;
    146 
    147   Image
    148     *image;
    149 
    150   int
    151     height,
    152     precision,
    153     width;
    154 
    155   QuantumInfo
    156     *quantum_info;
    157 
    158   MagickBooleanType
    159     status;
    160 
    161   size_t
    162     length;
    163 
    164   ssize_t
    165     count,
    166     y;
    167 
    168   /*
    169     Open image file.
    170   */
    171   assert(image_info != (const ImageInfo *) NULL);
    172   assert(image_info->signature == MagickCoreSignature);
    173   if (image_info->debug != MagickFalse)
    174     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    175       image_info->filename);
    176   assert(exception != (ExceptionInfo *) NULL);
    177   assert(exception->signature == MagickCoreSignature);
    178   image=AcquireImage(image_info,exception);
    179   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    180   if (status == MagickFalse)
    181     {
    182       image=DestroyImageList(image);
    183       return((Image *) NULL);
    184     }
    185   if (ReadBlobString(image,buffer) == (char *) NULL)
    186     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    187   count=(ssize_t) sscanf(buffer,"PG%[ \t]%2s%[ \t+-]%d%[ \t]%d%[ \t]%d",sans,
    188     endian,sign,&precision,sans,&width,sans,&height);
    189   if (count != 8)
    190     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    191   image->depth=(size_t) precision;
    192   if (LocaleCompare(endian,"ML") == 0)
    193     image->endian=MSBEndian;
    194   image->columns=(size_t) width;
    195   image->rows=(size_t) height;
    196   if ((image->columns == 0) || (image->rows == 0))
    197     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    198   if (image_info->ping != MagickFalse)
    199     {
    200       (void) CloseBlob(image);
    201       return(GetFirstImageInList(image));
    202     }
    203   status=SetImageExtent(image,image->columns,image->rows,exception);
    204   if (status == MagickFalse)
    205     return(DestroyImageList(image));
    206   /*
    207     Convert PGX image.
    208   */
    209   (void) SetImageColorspace(image,GRAYColorspace,exception);
    210   quantum_info=AcquireQuantumInfo(image_info,image);
    211   if (quantum_info == (QuantumInfo *) NULL)
    212     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    213   length=GetQuantumExtent(image,quantum_info,GrayQuantum);
    214   for (y=0; y < (ssize_t) image->rows; y++)
    215   {
    216     register Quantum
    217       *magick_restrict q;
    218 
    219     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    220     if (q == (Quantum *) NULL)
    221       break;
    222     pixels=(const unsigned char *) ReadBlobStream(image,length,
    223       GetQuantumPixels(quantum_info),&count);
    224     if (count != (ssize_t) length)
    225       break;
    226     (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
    227       GrayQuantum,pixels,exception);
    228     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    229       break;
    230     if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
    231       break;
    232   }
    233   SetQuantumImageType(image,GrayQuantum);
    234   quantum_info=DestroyQuantumInfo(quantum_info);
    235   if (EOFBlob(image) != MagickFalse)
    236     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    237       image->filename);
    238   (void) CloseBlob(image);
    239   return(GetFirstImageInList(image));
    240 }
    241 
    242 /*
    244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    245 %                                                                             %
    246 %                                                                             %
    247 %                                                                             %
    248 %   R e g i s t e r P G X I m a g e                                           %
    249 %                                                                             %
    250 %                                                                             %
    251 %                                                                             %
    252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    253 %
    254 %  RegisterPGXImage() adds attributes for the PGX image format to
    255 %  the list of supported formats.  The attributes include the image format
    256 %  tag, a method to read and/or write the format, whether the format
    257 %  supports the saving of more than one frame to the same file or blob,
    258 %  whether the format supports native in-memory I/O, and a brief
    259 %  description of the format.
    260 %
    261 %  The format of the RegisterPGXImage method is:
    262 %
    263 %      size_t RegisterPGXImage(void)
    264 %
    265 */
    266 ModuleExport size_t RegisterPGXImage(void)
    267 {
    268   MagickInfo
    269     *entry;
    270 
    271   entry=AcquireMagickInfo("PGX","PGX","JPEG 2000 uncompressed format");
    272   entry->decoder=(DecodeImageHandler *) ReadPGXImage;
    273   entry->encoder=(EncodeImageHandler *) WritePGXImage;
    274   entry->magick=(IsImageFormatHandler *) IsPGX;
    275   entry->flags^=CoderAdjoinFlag;
    276   entry->flags^=CoderUseExtensionFlag;
    277   (void) RegisterMagickInfo(entry);
    278   return(MagickImageCoderSignature);
    279 }
    280 
    281 /*
    283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    284 %                                                                             %
    285 %                                                                             %
    286 %                                                                             %
    287 %   U n r e g i s t e r P G X I m a g e                                       %
    288 %                                                                             %
    289 %                                                                             %
    290 %                                                                             %
    291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    292 %
    293 %  UnregisterPGXImage() removes format registrations made by the
    294 %  PGX module from the list of supported formats.
    295 %
    296 %  The format of the UnregisterPGXImage method is:
    297 %
    298 %      UnregisterPGXImage(void)
    299 %
    300 */
    301 ModuleExport void UnregisterPGXImage(void)
    302 {
    303   (void) UnregisterMagickInfo("PGX");
    304 }
    305 
    306 /*
    308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    309 %                                                                             %
    310 %                                                                             %
    311 %                                                                             %
    312 %   W r i t e P G X I m a g e                                                 %
    313 %                                                                             %
    314 %                                                                             %
    315 %                                                                             %
    316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    317 %
    318 %  WritePGXImage() writes an image of raw bits in LSB order to a file.
    319 %
    320 %  The format of the WritePGXImage method is:
    321 %
    322 %      MagickBooleanType WritePGXImage(const ImageInfo *image_info,
    323 %        Image *image,ExceptionInfo *exception)
    324 %
    325 %  A description of each parameter follows.
    326 %
    327 %    o image_info: the image info.
    328 %
    329 %    o image:  The image.
    330 %
    331 %    o exception: return any errors or warnings in this structure.
    332 %
    333 */
    334 static MagickBooleanType WritePGXImage(const ImageInfo *image_info,Image *image,
    335   ExceptionInfo *exception)
    336 {
    337   char
    338     buffer[MagickPathExtent];
    339 
    340   MagickBooleanType
    341     status;
    342 
    343   QuantumInfo
    344     *quantum_info;
    345 
    346   register const Quantum
    347     *p;
    348 
    349   size_t
    350     length;
    351 
    352   ssize_t
    353     count,
    354     y;
    355 
    356   unsigned char
    357     *pixels;
    358 
    359   /*
    360     Open output image file.
    361   */
    362   assert(image_info != (const ImageInfo *) NULL);
    363   assert(image_info->signature == MagickCoreSignature);
    364   assert(image != (Image *) NULL);
    365   assert(image->signature == MagickCoreSignature);
    366   if (image->debug != MagickFalse)
    367     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    368   assert(exception != (ExceptionInfo *) NULL);
    369   assert(exception->signature == MagickCoreSignature);
    370   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    371   if (status == MagickFalse)
    372     return(status);
    373   (void) FormatLocaleString(buffer,MagickPathExtent,"PG ML + %g %g %g\n",
    374     (double) image->depth,(double) image->columns,(double) image->rows);
    375   (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer);
    376   (void) TransformImageColorspace(image,sRGBColorspace,exception);
    377   quantum_info=AcquireQuantumInfo(image_info,image);
    378   if (quantum_info == (QuantumInfo *) NULL)
    379     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    380   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
    381   for (y=0; y < (ssize_t) image->rows; y++)
    382   {
    383     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    384     if (p == (const Quantum *) NULL)
    385       break;
    386     length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
    387       GrayQuantum,pixels,exception);
    388     count=WriteBlob(image,length,pixels);
    389     if (count != (ssize_t) length)
    390       break;
    391     count=WriteBlob(image,(size_t) (-(ssize_t) length) & 0x01,pixels);
    392     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
    393       image->rows);
    394     if (status == MagickFalse)
    395       break;
    396   }
    397   quantum_info=DestroyQuantumInfo(quantum_info);
    398   if (y < (ssize_t) image->rows)
    399     ThrowWriterException(CorruptImageError,"UnableToWriteImageData");
    400   (void) CloseBlob(image);
    401   return(status);
    402 }
    403