Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                              JJJ  PPPP    222                               %
      7 %                               J   P   P  2   2                              %
      8 %                               J   PPPP     22                               %
      9 %                            J  J   P       2                                 %
     10 %                             JJ    P      22222                              %
     11 %                                                                             %
     12 %                                                                             %
     13 %                     Read/Write JPEG-2000 Image Format                       %
     14 %                                                                             %
     15 %                                   Cristy                                    %
     16 %                                Nathan Brown                                 %
     17 %                                 June 2001                                   %
     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/artifact.h"
     45 #include "MagickCore/attribute.h"
     46 #include "MagickCore/blob.h"
     47 #include "MagickCore/blob-private.h"
     48 #include "MagickCore/cache.h"
     49 #include "MagickCore/colorspace.h"
     50 #include "MagickCore/colorspace-private.h"
     51 #include "MagickCore/color.h"
     52 #include "MagickCore/color-private.h"
     53 #include "MagickCore/exception.h"
     54 #include "MagickCore/exception-private.h"
     55 #include "MagickCore/image.h"
     56 #include "MagickCore/image-private.h"
     57 #include "MagickCore/list.h"
     58 #include "MagickCore/magick.h"
     59 #include "MagickCore/memory_.h"
     60 #include "MagickCore/monitor.h"
     61 #include "MagickCore/monitor-private.h"
     62 #include "MagickCore/option.h"
     63 #include "MagickCore/pixel-accessor.h"
     64 #include "MagickCore/profile.h"
     65 #include "MagickCore/property.h"
     66 #include "MagickCore/quantum-private.h"
     67 #include "MagickCore/resource_.h"
     68 #include "MagickCore/semaphore.h"
     69 #include "MagickCore/static.h"
     70 #include "MagickCore/statistic.h"
     71 #include "MagickCore/string_.h"
     72 #include "MagickCore/string-private.h"
     73 #include "MagickCore/module.h"
     74 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
     75 #include <openjpeg.h>
     76 #endif
     77 
     78 /*
     80   Forward declarations.
     81 */
     82 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
     83 static MagickBooleanType
     84   WriteJP2Image(const ImageInfo *,Image *,ExceptionInfo *);
     85 #endif
     86 
     87 /*
     89 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     90 %                                                                             %
     91 %                                                                             %
     92 %                                                                             %
     93 %   I s J 2 K                                                                 %
     94 %                                                                             %
     95 %                                                                             %
     96 %                                                                             %
     97 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     98 %
     99 %  IsJ2K() returns MagickTrue if the image format type, identified by the
    100 %  magick string, is J2K.
    101 %
    102 %  The format of the IsJ2K method is:
    103 %
    104 %      MagickBooleanType IsJ2K(const unsigned char *magick,const size_t length)
    105 %
    106 %  A description of each parameter follows:
    107 %
    108 %    o magick: compare image format pattern against these bytes.
    109 %
    110 %    o length: Specifies the length of the magick string.
    111 %
    112 */
    113 static MagickBooleanType IsJ2K(const unsigned char *magick,const size_t length)
    114 {
    115   if (length < 4)
    116     return(MagickFalse);
    117   if (memcmp(magick,"\xff\x4f\xff\x51",4) == 0)
    118     return(MagickTrue);
    119   return(MagickFalse);
    120 }
    121 
    122 /*
    124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    125 %                                                                             %
    126 %                                                                             %
    127 %                                                                             %
    128 %   I s J P 2                                                                 %
    129 %                                                                             %
    130 %                                                                             %
    131 %                                                                             %
    132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    133 %
    134 %  IsJP2() returns MagickTrue if the image format type, identified by the
    135 %  magick string, is JP2.
    136 %
    137 %  The format of the IsJP2 method is:
    138 %
    139 %      MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
    140 %
    141 %  A description of each parameter follows:
    142 %
    143 %    o magick: compare image format pattern against these bytes.
    144 %
    145 %    o length: Specifies the length of the magick string.
    146 %
    147 */
    148 static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
    149 {
    150   if (length < 4)
    151     return(MagickFalse);
    152   if (memcmp(magick,"\x0d\x0a\x87\x0a",4) == 0)
    153     return(MagickTrue);
    154   if (length < 12)
    155     return(MagickFalse);
    156   if (memcmp(magick,"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a",12) == 0)
    157     return(MagickTrue);
    158   return(MagickFalse);
    159 }
    160 
    161 /*
    163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    164 %                                                                             %
    165 %                                                                             %
    166 %                                                                             %
    167 %   R e a d J P 2 I m a g e                                                   %
    168 %                                                                             %
    169 %                                                                             %
    170 %                                                                             %
    171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    172 %
    173 %  ReadJP2Image() reads a JPEG 2000 Image file (JP2) or JPEG 2000
    174 %  codestream (JPC) image file and returns it.  It allocates the memory
    175 %  necessary for the new Image structure and returns a pointer to the new
    176 %  image or set of images.
    177 %
    178 %  JP2 support is originally written by Nathan Brown, nathanbrown (at) letu.edu.
    179 %
    180 %  The format of the ReadJP2Image method is:
    181 %
    182 %      Image *ReadJP2Image(const ImageInfo *image_info,
    183 %        ExceptionInfo *exception)
    184 %
    185 %  A description of each parameter follows:
    186 %
    187 %    o image_info: the image info.
    188 %
    189 %    o exception: return any errors or warnings in this structure.
    190 %
    191 */
    192 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    193 static void JP2ErrorHandler(const char *message,void *client_data)
    194 {
    195   ExceptionInfo
    196     *exception;
    197 
    198   exception=(ExceptionInfo *) client_data;
    199   (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
    200     message,"`%s'","OpenJP2");
    201 }
    202 
    203 static OPJ_SIZE_T JP2ReadHandler(void *buffer,OPJ_SIZE_T length,void *context)
    204 {
    205   Image
    206     *image;
    207 
    208   ssize_t
    209     count;
    210 
    211   image=(Image *) context;
    212   count=ReadBlob(image,(ssize_t) length,(unsigned char *) buffer);
    213   if (count == 0)
    214     return((OPJ_SIZE_T) -1);
    215   return((OPJ_SIZE_T) count);
    216 }
    217 
    218 static OPJ_BOOL JP2SeekHandler(OPJ_OFF_T offset,void *context)
    219 {
    220   Image
    221     *image;
    222 
    223   image=(Image *) context;
    224   return(SeekBlob(image,offset,SEEK_SET) < 0 ? OPJ_FALSE : OPJ_TRUE);
    225 }
    226 
    227 static OPJ_OFF_T JP2SkipHandler(OPJ_OFF_T offset,void *context)
    228 {
    229   Image
    230     *image;
    231 
    232   image=(Image *) context;
    233   return(SeekBlob(image,offset,SEEK_CUR) < 0 ? -1 : offset);
    234 }
    235 
    236 static void JP2WarningHandler(const char *message,void *client_data)
    237 {
    238   ExceptionInfo
    239     *exception;
    240 
    241   exception=(ExceptionInfo *) client_data;
    242   (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
    243     message,"`%s'","OpenJP2");
    244 }
    245 
    246 static OPJ_SIZE_T JP2WriteHandler(void *buffer,OPJ_SIZE_T length,void *context)
    247 {
    248   Image
    249     *image;
    250 
    251   ssize_t
    252     count;
    253 
    254   image=(Image *) context;
    255   count=WriteBlob(image,(ssize_t) length,(unsigned char *) buffer);
    256   return((OPJ_SIZE_T) count);
    257 }
    258 
    259 static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
    260 {
    261   const char
    262     *option;
    263 
    264   Image
    265     *image;
    266 
    267   int
    268     jp2_status;
    269 
    270   MagickBooleanType
    271     status;
    272 
    273   opj_codec_t
    274     *jp2_codec;
    275 
    276   opj_dparameters_t
    277     parameters;
    278 
    279   opj_image_t
    280     *jp2_image;
    281 
    282   opj_stream_t
    283     *jp2_stream;
    284 
    285   register ssize_t
    286     i;
    287 
    288   ssize_t
    289     y;
    290 
    291   unsigned char
    292     sans[4];
    293 
    294   /*
    295     Open image file.
    296   */
    297   assert(image_info != (const ImageInfo *) NULL);
    298   assert(image_info->signature == MagickCoreSignature);
    299   if (image_info->debug != MagickFalse)
    300     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    301       image_info->filename);
    302   assert(exception != (ExceptionInfo *) NULL);
    303   assert(exception->signature == MagickCoreSignature);
    304   image=AcquireImage(image_info,exception);
    305   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    306   if (status == MagickFalse)
    307     {
    308       image=DestroyImageList(image);
    309       return((Image *) NULL);
    310     }
    311   /*
    312     Initialize JP2 codec.
    313   */
    314   if (ReadBlob(image,4,sans) != 4)
    315     {
    316       image=DestroyImageList(image);
    317       return((Image *) NULL);
    318     }
    319   (void) SeekBlob(image,SEEK_SET,0);
    320   if (LocaleCompare(image_info->magick,"JPT") == 0)
    321     jp2_codec=opj_create_decompress(OPJ_CODEC_JPT);
    322   else
    323     if (IsJ2K(sans,4) != MagickFalse)
    324       jp2_codec=opj_create_decompress(OPJ_CODEC_J2K);
    325     else
    326       jp2_codec=opj_create_decompress(OPJ_CODEC_JP2);
    327   opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
    328   opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
    329   opj_set_default_decoder_parameters(&parameters);
    330   option=GetImageOption(image_info,"jp2:reduce-factor");
    331   if (option != (const char *) NULL)
    332     parameters.cp_reduce=StringToInteger(option);
    333   option=GetImageOption(image_info,"jp2:quality-layers");
    334   if (option != (const char *) NULL)
    335     parameters.cp_layer=StringToInteger(option);
    336   if (opj_setup_decoder(jp2_codec,&parameters) == 0)
    337     {
    338       opj_destroy_codec(jp2_codec);
    339       ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
    340     }
    341   jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,1);
    342   opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
    343   opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
    344   opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
    345   opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
    346   opj_stream_set_user_data(jp2_stream,image,NULL);
    347   opj_stream_set_user_data_length(jp2_stream,GetBlobSize(image));
    348   if (opj_read_header(jp2_stream,jp2_codec,&jp2_image) == 0)
    349     {
    350       opj_stream_destroy(jp2_stream);
    351       opj_destroy_codec(jp2_codec);
    352       ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
    353     }
    354   jp2_status=1;
    355   if ((image->columns != 0) && (image->rows != 0))
    356     {
    357       /*
    358         Extract an area from the image.
    359       */
    360       jp2_status=opj_set_decode_area(jp2_codec,jp2_image,
    361         (OPJ_INT32) image->extract_info.x,(OPJ_INT32) image->extract_info.y,
    362         (OPJ_INT32) (image->extract_info.x+(ssize_t) image->columns),
    363         (OPJ_INT32) (image->extract_info.y+(ssize_t) image->rows));
    364       if (jp2_status == 0)
    365         {
    366           opj_stream_destroy(jp2_stream);
    367           opj_destroy_codec(jp2_codec);
    368           opj_image_destroy(jp2_image);
    369           ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
    370         }
    371     }
    372   if ((AcquireMagickResource(WidthResource,(size_t) jp2_image->comps[0].w) == MagickFalse) ||
    373       (AcquireMagickResource(HeightResource,(size_t) jp2_image->comps[0].h) == MagickFalse))
    374     {
    375       opj_stream_destroy(jp2_stream);
    376       opj_destroy_codec(jp2_codec);
    377       opj_image_destroy(jp2_image);
    378       ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
    379     }
    380   if ((image_info->number_scenes != 0) && (image_info->scene != 0))
    381     jp2_status=opj_get_decoded_tile(jp2_codec,jp2_stream,jp2_image,
    382       (unsigned int) image_info->scene-1);
    383   else
    384     if (image->ping == MagickFalse)
    385       {
    386         jp2_status=opj_set_decode_area(jp2_codec,jp2_image,0,0,
    387           jp2_image->comps[0].w-1,jp2_image->comps[0].h-1);
    388         if (jp2_status != 0)
    389           jp2_status=opj_decode(jp2_codec,jp2_stream,jp2_image);
    390         if (jp2_status != 0)
    391           jp2_status=opj_end_decompress(jp2_codec,jp2_stream);
    392       }
    393   if (jp2_status == 0)
    394     {
    395       opj_stream_destroy(jp2_stream);
    396       opj_destroy_codec(jp2_codec);
    397       opj_image_destroy(jp2_image);
    398       ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
    399     }
    400   opj_stream_destroy(jp2_stream);
    401   for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
    402   {
    403     if ((jp2_image->comps[0].dx == 0) || (jp2_image->comps[0].dy == 0) ||
    404         (jp2_image->comps[0].prec != jp2_image->comps[i].prec) ||
    405         (jp2_image->comps[0].sgnd != jp2_image->comps[i].sgnd) ||
    406         ((image->ping == MagickFalse) && (jp2_image->comps[i].data == NULL)))
    407       {
    408         opj_destroy_codec(jp2_codec);
    409         opj_image_destroy(jp2_image);
    410         ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported")
    411       }
    412   }
    413   /*
    414     Convert JP2 image.
    415   */
    416   image->columns=(size_t) jp2_image->comps[0].w;
    417   image->rows=(size_t) jp2_image->comps[0].h;
    418   image->depth=jp2_image->comps[0].prec;
    419   image->compression=JPEG2000Compression;
    420   if (jp2_image->numcomps == 1)
    421     SetImageColorspace(image,GRAYColorspace,exception);
    422   else
    423     if (jp2_image->color_space == 2)
    424       {
    425         SetImageColorspace(image,GRAYColorspace,exception);
    426         if (jp2_image->numcomps > 1)
    427           image->alpha_trait=BlendPixelTrait;
    428       }
    429     else
    430       if (jp2_image->color_space == 3)
    431         SetImageColorspace(image,Rec601YCbCrColorspace,exception);
    432   if (jp2_image->numcomps > 3)
    433     image->alpha_trait=BlendPixelTrait;
    434   if (jp2_image->icc_profile_buf != (unsigned char *) NULL)
    435     {
    436       StringInfo
    437         *profile;
    438 
    439       profile=BlobToStringInfo(jp2_image->icc_profile_buf,
    440         jp2_image->icc_profile_len);
    441       if (profile != (StringInfo *) NULL)
    442         {
    443           SetImageProfile(image,"icc",profile,exception);
    444           profile=DestroyStringInfo(profile);
    445         }
    446     }
    447   if (image->ping != MagickFalse)
    448     {
    449       opj_destroy_codec(jp2_codec);
    450       opj_image_destroy(jp2_image);
    451       return(GetFirstImageInList(image));
    452     }
    453   status=SetImageExtent(image,image->columns,image->rows,exception);
    454   if (status == MagickFalse)
    455     {
    456       opj_destroy_codec(jp2_codec);
    457       opj_image_destroy(jp2_image);
    458       return(DestroyImageList(image));
    459     }
    460   for (y=0; y < (ssize_t) image->rows; y++)
    461   {
    462     register Quantum
    463       *magick_restrict q;
    464 
    465     register ssize_t
    466       x;
    467 
    468     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
    469     if (q == (Quantum *) NULL)
    470       break;
    471     for (x=0; x < (ssize_t) image->columns; x++)
    472     {
    473       for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
    474       {
    475         double
    476           pixel,
    477           scale;
    478 
    479         scale=QuantumRange/(double) ((1UL << jp2_image->comps[i].prec)-1);
    480         pixel=scale*(jp2_image->comps[i].data[y/jp2_image->comps[i].dy*
    481           image->columns/jp2_image->comps[i].dx+x/jp2_image->comps[i].dx]+
    482           (jp2_image->comps[i].sgnd ? 1UL << (jp2_image->comps[i].prec-1) : 0));
    483         switch (i)
    484         {
    485            case 0:
    486            {
    487              if (jp2_image->numcomps == 1)
    488                {
    489                  SetPixelGray(image,ClampToQuantum(pixel),q);
    490                  SetPixelAlpha(image,OpaqueAlpha,q);
    491                  break;
    492                }
    493              SetPixelRed(image,ClampToQuantum(pixel),q);
    494              SetPixelGreen(image,ClampToQuantum(pixel),q);
    495              SetPixelBlue(image,ClampToQuantum(pixel),q);
    496              SetPixelAlpha(image,OpaqueAlpha,q);
    497              break;
    498            }
    499            case 1:
    500            {
    501              if (jp2_image->numcomps == 2)
    502                {
    503                  SetPixelAlpha(image,ClampToQuantum(pixel),q);
    504                  break;
    505                }
    506              SetPixelGreen(image,ClampToQuantum(pixel),q);
    507              break;
    508            }
    509            case 2:
    510            {
    511              SetPixelBlue(image,ClampToQuantum(pixel),q);
    512              break;
    513            }
    514            case 3:
    515            {
    516              SetPixelAlpha(image,ClampToQuantum(pixel),q);
    517              break;
    518            }
    519         }
    520       }
    521       q+=GetPixelChannels(image);
    522     }
    523     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    524       break;
    525     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    526       image->rows);
    527     if (status == MagickFalse)
    528       break;
    529   }
    530   /*
    531     Free resources.
    532   */
    533   opj_destroy_codec(jp2_codec);
    534   opj_image_destroy(jp2_image);
    535   (void) CloseBlob(image);
    536   if ((image_info->number_scenes != 0) && (image_info->scene != 0))
    537     AppendImageToList(&image,CloneImage(image,0,0,MagickTrue,exception));
    538   return(GetFirstImageInList(image));
    539 }
    540 #endif
    541 
    542 /*
    544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    545 %                                                                             %
    546 %                                                                             %
    547 %                                                                             %
    548 %   R e g i s t e r J P 2 I m a g e                                           %
    549 %                                                                             %
    550 %                                                                             %
    551 %                                                                             %
    552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    553 %
    554 %  RegisterJP2Image() adds attributes for the JP2 image format to the list of
    555 %  supported formats.  The attributes include the image format tag, a method
    556 %  method to read and/or write the format, whether the format supports the
    557 %  saving of more than one frame to the same file or blob, whether the format
    558 %  supports native in-memory I/O, and a brief description of the format.
    559 %
    560 %  The format of the RegisterJP2Image method is:
    561 %
    562 %      size_t RegisterJP2Image(void)
    563 %
    564 */
    565 ModuleExport size_t RegisterJP2Image(void)
    566 {
    567   char
    568     version[MagickPathExtent];
    569 
    570   MagickInfo
    571     *entry;
    572 
    573   *version='\0';
    574 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    575   (void) FormatLocaleString(version,MagickPathExtent,"%s",opj_version());
    576 #endif
    577   entry=AcquireMagickInfo("JP2","JP2","JPEG-2000 File Format Syntax");
    578   if (*version != '\0')
    579     entry->version=ConstantString(version);
    580   entry->mime_type=ConstantString("image/jp2");
    581   entry->magick=(IsImageFormatHandler *) IsJP2;
    582   entry->flags^=CoderAdjoinFlag;
    583   entry->flags|=CoderDecoderSeekableStreamFlag;
    584   entry->flags|=CoderEncoderSeekableStreamFlag;
    585 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    586   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
    587   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
    588 #endif
    589   (void) RegisterMagickInfo(entry);
    590   entry=AcquireMagickInfo("JP2","J2C","JPEG-2000 Code Stream Syntax");
    591   if (*version != '\0')
    592     entry->version=ConstantString(version);
    593   entry->mime_type=ConstantString("image/jp2");
    594   entry->magick=(IsImageFormatHandler *) IsJ2K;
    595   entry->flags^=CoderAdjoinFlag;
    596   entry->flags|=CoderDecoderSeekableStreamFlag;
    597   entry->flags|=CoderEncoderSeekableStreamFlag;
    598 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    599   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
    600   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
    601 #endif
    602   (void) RegisterMagickInfo(entry);
    603   entry=AcquireMagickInfo("JP2","J2K","JPEG-2000 Code Stream Syntax");
    604   if (*version != '\0')
    605     entry->version=ConstantString(version);
    606   entry->mime_type=ConstantString("image/jp2");
    607   entry->magick=(IsImageFormatHandler *) IsJ2K;
    608   entry->flags^=CoderAdjoinFlag;
    609   entry->flags|=CoderDecoderSeekableStreamFlag;
    610   entry->flags|=CoderEncoderSeekableStreamFlag;
    611 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    612   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
    613   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
    614 #endif
    615   (void) RegisterMagickInfo(entry);
    616   entry=AcquireMagickInfo("JP2","JPM","JPEG-2000 File Format Syntax");
    617   if (*version != '\0')
    618     entry->version=ConstantString(version);
    619   entry->mime_type=ConstantString("image/jp2");
    620   entry->magick=(IsImageFormatHandler *) IsJP2;
    621   entry->flags^=CoderAdjoinFlag;
    622   entry->flags|=CoderDecoderSeekableStreamFlag;
    623   entry->flags|=CoderEncoderSeekableStreamFlag;
    624 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    625   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
    626   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
    627 #endif
    628   (void) RegisterMagickInfo(entry);
    629   entry=AcquireMagickInfo("JP2","JPT","JPEG-2000 File Format Syntax");
    630   if (*version != '\0')
    631     entry->version=ConstantString(version);
    632   entry->mime_type=ConstantString("image/jp2");
    633   entry->magick=(IsImageFormatHandler *) IsJP2;
    634   entry->flags^=CoderAdjoinFlag;
    635   entry->flags|=CoderDecoderSeekableStreamFlag;
    636   entry->flags|=CoderEncoderSeekableStreamFlag;
    637 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    638   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
    639   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
    640 #endif
    641   (void) RegisterMagickInfo(entry);
    642   entry=AcquireMagickInfo("JP2","JPC","JPEG-2000 Code Stream Syntax");
    643   if (*version != '\0')
    644     entry->version=ConstantString(version);
    645   entry->mime_type=ConstantString("image/jp2");
    646   entry->magick=(IsImageFormatHandler *) IsJP2;
    647   entry->flags^=CoderAdjoinFlag;
    648   entry->flags|=CoderDecoderSeekableStreamFlag;
    649   entry->flags|=CoderEncoderSeekableStreamFlag;
    650 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    651   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
    652   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
    653 #endif
    654   (void) RegisterMagickInfo(entry);
    655   return(MagickImageCoderSignature);
    656 }
    657 
    658 /*
    660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    661 %                                                                             %
    662 %                                                                             %
    663 %                                                                             %
    664 %   U n r e g i s t e r J P 2 I m a g e                                       %
    665 %                                                                             %
    666 %                                                                             %
    667 %                                                                             %
    668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    669 %
    670 %  UnregisterJP2Image() removes format registrations made by the JP2 module
    671 %  from the list of supported formats.
    672 %
    673 %  The format of the UnregisterJP2Image method is:
    674 %
    675 %      UnregisterJP2Image(void)
    676 %
    677 */
    678 ModuleExport void UnregisterJP2Image(void)
    679 {
    680   (void) UnregisterMagickInfo("JPC");
    681   (void) UnregisterMagickInfo("JPT");
    682   (void) UnregisterMagickInfo("JPM");
    683   (void) UnregisterMagickInfo("JP2");
    684   (void) UnregisterMagickInfo("J2K");
    685 }
    686 
    687 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
    689 /*
    690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    691 %                                                                             %
    692 %                                                                             %
    693 %                                                                             %
    694 %   W r i t e J P 2 I m a g e                                                 %
    695 %                                                                             %
    696 %                                                                             %
    697 %                                                                             %
    698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    699 %
    700 %  WriteJP2Image() writes an image in the JPEG 2000 image format.
    701 %
    702 %  JP2 support originally written by Nathan Brown, nathanbrown (at) letu.edu
    703 %
    704 %  The format of the WriteJP2Image method is:
    705 %
    706 %      MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
    707 %        ExceptionInfo *exception)
    708 %
    709 %  A description of each parameter follows.
    710 %
    711 %    o image_info: the image info.
    712 %
    713 %    o image:  The image.
    714 %
    715 */
    716 
    717 static void CinemaProfileCompliance(const opj_image_t *jp2_image,
    718   opj_cparameters_t *parameters)
    719 {
    720   /*
    721     Digital Cinema 4K profile compliant codestream.
    722   */
    723   parameters->tile_size_on=OPJ_FALSE;
    724   parameters->cp_tdx=1;
    725   parameters->cp_tdy=1;
    726   parameters->tp_flag='C';
    727   parameters->tp_on=1;
    728   parameters->cp_tx0=0;
    729   parameters->cp_ty0=0;
    730   parameters->image_offset_x0=0;
    731   parameters->image_offset_y0=0;
    732   parameters->cblockw_init=32;
    733   parameters->cblockh_init=32;
    734   parameters->csty|=0x01;
    735   parameters->prog_order=OPJ_CPRL;
    736   parameters->roi_compno=(-1);
    737   parameters->subsampling_dx=1;
    738   parameters->subsampling_dy=1;
    739   parameters->irreversible=1;
    740   if ((jp2_image->comps[0].w == 2048) || (jp2_image->comps[0].h == 1080))
    741     {
    742       /*
    743         Digital Cinema 2K.
    744       */
    745       parameters->cp_cinema=OPJ_CINEMA2K_24;
    746       parameters->cp_rsiz=OPJ_CINEMA2K;
    747       parameters->max_comp_size=1041666;
    748       if (parameters->numresolution > 6)
    749         parameters->numresolution=6;
    750 
    751     }
    752   if ((jp2_image->comps[0].w == 4096) || (jp2_image->comps[0].h == 2160))
    753     {
    754       /*
    755         Digital Cinema 4K.
    756       */
    757       parameters->cp_cinema=OPJ_CINEMA4K_24;
    758       parameters->cp_rsiz=OPJ_CINEMA4K;
    759       parameters->max_comp_size=1041666;
    760       if (parameters->numresolution < 1)
    761         parameters->numresolution=1;
    762       if (parameters->numresolution > 7)
    763         parameters->numresolution=7;
    764       parameters->numpocs=2;
    765       parameters->POC[0].tile=1;
    766       parameters->POC[0].resno0=0;
    767       parameters->POC[0].compno0=0;
    768       parameters->POC[0].layno1=1;
    769       parameters->POC[0].resno1=parameters->numresolution-1;
    770       parameters->POC[0].compno1=3;
    771       parameters->POC[0].prg1=OPJ_CPRL;
    772       parameters->POC[1].tile=1;
    773       parameters->POC[1].resno0=parameters->numresolution-1;
    774       parameters->POC[1].compno0=0;
    775       parameters->POC[1].layno1=1;
    776       parameters->POC[1].resno1=parameters->numresolution;
    777       parameters->POC[1].compno1=3;
    778       parameters->POC[1].prg1=OPJ_CPRL;
    779     }
    780   parameters->tcp_numlayers=1;
    781   parameters->tcp_rates[0]=((float) (jp2_image->numcomps*jp2_image->comps[0].w*
    782     jp2_image->comps[0].h*jp2_image->comps[0].prec))/(parameters->max_comp_size*
    783     8*jp2_image->comps[0].dx*jp2_image->comps[0].dy);
    784   parameters->cp_disto_alloc=1;
    785 }
    786 
    787 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
    788   ExceptionInfo *exception)
    789 {
    790   const char
    791     *option,
    792     *property;
    793 
    794   int
    795     jp2_status;
    796 
    797   MagickBooleanType
    798     status;
    799 
    800   opj_codec_t
    801     *jp2_codec;
    802 
    803   OPJ_COLOR_SPACE
    804     jp2_colorspace;
    805 
    806   opj_cparameters_t
    807     parameters;
    808 
    809   opj_image_cmptparm_t
    810     jp2_info[5];
    811 
    812   opj_image_t
    813     *jp2_image;
    814 
    815   opj_stream_t
    816     *jp2_stream;
    817 
    818   register ssize_t
    819     i;
    820 
    821   ssize_t
    822     y;
    823 
    824   unsigned int
    825     channels;
    826 
    827   /*
    828     Open image file.
    829   */
    830   assert(image_info != (const ImageInfo *) NULL);
    831   assert(image_info->signature == MagickCoreSignature);
    832   assert(image != (Image *) NULL);
    833   assert(image->signature == MagickCoreSignature);
    834   if (image->debug != MagickFalse)
    835     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    836   assert(exception != (ExceptionInfo *) NULL);
    837   assert(exception->signature == MagickCoreSignature);
    838   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    839   if (status == MagickFalse)
    840     return(status);
    841   /*
    842     Initialize JPEG 2000 API.
    843   */
    844   opj_set_default_encoder_parameters(&parameters);
    845   for (i=1; i < 6; i++)
    846     if (((size_t) (1UL << (i+2)) > image->columns) &&
    847         ((size_t) (1UL << (i+2)) > image->rows))
    848       break;
    849   parameters.numresolution=i;
    850   option=GetImageOption(image_info,"jp2:number-resolutions");
    851   if (option != (const char *) NULL)
    852     parameters.numresolution=StringToInteger(option);
    853   parameters.tcp_numlayers=1;
    854   parameters.tcp_rates[0]=0;  /* lossless */
    855   parameters.cp_disto_alloc=1;
    856   if ((image_info->quality != 0) && (image_info->quality != 100))
    857     {
    858       parameters.tcp_distoratio[0]=(double) image_info->quality;
    859       parameters.cp_fixed_quality=OPJ_TRUE;
    860     }
    861   if (image_info->extract != (char *) NULL)
    862     {
    863       RectangleInfo
    864         geometry;
    865 
    866       int
    867         flags;
    868 
    869       /*
    870         Set tile size.
    871       */
    872       flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
    873       parameters.cp_tdx=(int) geometry.width;
    874       parameters.cp_tdy=(int) geometry.width;
    875       if ((flags & HeightValue) != 0)
    876         parameters.cp_tdy=(int) geometry.height;
    877       if ((flags & XValue) != 0)
    878         parameters.cp_tx0=geometry.x;
    879       if ((flags & YValue) != 0)
    880         parameters.cp_ty0=geometry.y;
    881       parameters.tile_size_on=OPJ_TRUE;
    882     }
    883   option=GetImageOption(image_info,"jp2:quality");
    884   if (option != (const char *) NULL)
    885     {
    886       register const char
    887         *p;
    888 
    889       /*
    890         Set quality PSNR.
    891       */
    892       p=option;
    893       for (i=0; sscanf(p,"%f",&parameters.tcp_distoratio[i]) == 1; i++)
    894       {
    895         if (i > 100)
    896           break;
    897         while ((*p != '\0') && (*p != ','))
    898           p++;
    899         if (*p == '\0')
    900           break;
    901         p++;
    902       }
    903       parameters.tcp_numlayers=i+1;
    904       parameters.cp_fixed_quality=OPJ_TRUE;
    905     }
    906   option=GetImageOption(image_info,"jp2:progression-order");
    907   if (option != (const char *) NULL)
    908     {
    909       if (LocaleCompare(option,"LRCP") == 0)
    910         parameters.prog_order=OPJ_LRCP;
    911       if (LocaleCompare(option,"RLCP") == 0)
    912         parameters.prog_order=OPJ_RLCP;
    913       if (LocaleCompare(option,"RPCL") == 0)
    914         parameters.prog_order=OPJ_RPCL;
    915       if (LocaleCompare(option,"PCRL") == 0)
    916         parameters.prog_order=OPJ_PCRL;
    917       if (LocaleCompare(option,"CPRL") == 0)
    918         parameters.prog_order=OPJ_CPRL;
    919     }
    920   option=GetImageOption(image_info,"jp2:rate");
    921   if (option != (const char *) NULL)
    922     {
    923       register const char
    924         *p;
    925 
    926       /*
    927         Set compression rate.
    928       */
    929       p=option;
    930       for (i=0; sscanf(p,"%f",&parameters.tcp_rates[i]) == 1; i++)
    931       {
    932         if (i >= 100)
    933           break;
    934         while ((*p != '\0') && (*p != ','))
    935           p++;
    936         if (*p == '\0')
    937           break;
    938         p++;
    939       }
    940       parameters.tcp_numlayers=i+1;
    941       parameters.cp_disto_alloc=OPJ_TRUE;
    942     }
    943   if (image_info->sampling_factor != (const char *) NULL)
    944     (void) sscanf(image_info->sampling_factor,"%d,%d",
    945       &parameters.subsampling_dx,&parameters.subsampling_dy);
    946   property=GetImageProperty(image,"comment",exception);
    947   if (property != (const char *) NULL)
    948     parameters.cp_comment=(char *) property;
    949   channels=3;
    950   jp2_colorspace=OPJ_CLRSPC_SRGB;
    951   if (image->colorspace == YUVColorspace)
    952     {
    953       jp2_colorspace=OPJ_CLRSPC_SYCC;
    954       parameters.subsampling_dx=2;
    955     }
    956   else
    957     {
    958       if (IsGrayColorspace(image->colorspace) != MagickFalse)
    959         {
    960           channels=1;
    961           jp2_colorspace=OPJ_CLRSPC_GRAY;
    962         }
    963       else
    964         (void) TransformImageColorspace(image,sRGBColorspace,exception);
    965       if (image->alpha_trait != UndefinedPixelTrait)
    966         channels++;
    967     }
    968   parameters.tcp_mct=channels == 3 ? 1 : 0;
    969   memset(jp2_info,0,sizeof(jp2_info));
    970   for (i=0; i < (ssize_t) channels; i++)
    971   {
    972     jp2_info[i].prec=(OPJ_UINT32) image->depth;
    973     jp2_info[i].bpp=(OPJ_UINT32) image->depth;
    974     if ((image->depth == 1) &&
    975         ((LocaleCompare(image_info->magick,"JPT") == 0) ||
    976          (LocaleCompare(image_info->magick,"JP2") == 0)))
    977       {
    978         jp2_info[i].prec++;  /* OpenJPEG returns exception for depth @ 1 */
    979         jp2_info[i].bpp++;
    980       }
    981     jp2_info[i].sgnd=0;
    982     jp2_info[i].dx=parameters.subsampling_dx;
    983     jp2_info[i].dy=parameters.subsampling_dy;
    984     jp2_info[i].w=(OPJ_UINT32) image->columns;
    985     jp2_info[i].h=(OPJ_UINT32) image->rows;
    986   }
    987   jp2_image=opj_image_create((OPJ_UINT32) channels,jp2_info,jp2_colorspace);
    988   if (jp2_image == (opj_image_t *) NULL)
    989     ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
    990   jp2_image->x0=parameters.image_offset_x0;
    991   jp2_image->y0=parameters.image_offset_y0;
    992   jp2_image->x1=(unsigned int) (2*parameters.image_offset_x0+(image->columns-1)*
    993     parameters.subsampling_dx+1);
    994   jp2_image->y1=(unsigned int) (2*parameters.image_offset_y0+(image->rows-1)*
    995     parameters.subsampling_dx+1);
    996   if ((image->depth == 12) &&
    997       ((image->columns == 2048) || (image->rows == 1080) ||
    998        (image->columns == 4096) || (image->rows == 2160)))
    999     CinemaProfileCompliance(jp2_image,&parameters);
   1000   if (channels == 4)
   1001     jp2_image->comps[3].alpha=1;
   1002   else
   1003    if ((channels == 2) && (jp2_colorspace == OPJ_CLRSPC_GRAY))
   1004      jp2_image->comps[1].alpha=1;
   1005   /*
   1006     Convert to JP2 pixels.
   1007   */
   1008   for (y=0; y < (ssize_t) image->rows; y++)
   1009   {
   1010     register const Quantum
   1011       *p;
   1012 
   1013     ssize_t
   1014       x;
   1015 
   1016     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   1017     if (p == (const Quantum *) NULL)
   1018       break;
   1019     for (x=0; x < (ssize_t) image->columns; x++)
   1020     {
   1021       for (i=0; i < (ssize_t) channels; i++)
   1022       {
   1023         double
   1024           scale;
   1025 
   1026         register int
   1027           *q;
   1028 
   1029         scale=(double) ((1UL << jp2_image->comps[i].prec)-1)/QuantumRange;
   1030         q=jp2_image->comps[i].data+(y/jp2_image->comps[i].dy*
   1031           image->columns/jp2_image->comps[i].dx+x/jp2_image->comps[i].dx);
   1032         switch (i)
   1033         {
   1034           case 0:
   1035           {
   1036             if (jp2_colorspace == OPJ_CLRSPC_GRAY)
   1037               {
   1038                 *q=(int) (scale*GetPixelGray(image,p));
   1039                 break;
   1040               }
   1041             *q=(int) (scale*GetPixelRed(image,p));
   1042             break;
   1043           }
   1044           case 1:
   1045           {
   1046             if (jp2_colorspace == OPJ_CLRSPC_GRAY)
   1047               {
   1048                 *q=(int) (scale*GetPixelAlpha(image,p));
   1049                 break;
   1050               }
   1051             *q=(int) (scale*GetPixelGreen(image,p));
   1052             break;
   1053           }
   1054           case 2:
   1055           {
   1056             *q=(int) (scale*GetPixelBlue(image,p));
   1057             break;
   1058           }
   1059           case 3:
   1060           {
   1061             *q=(int) (scale*GetPixelAlpha(image,p));
   1062             break;
   1063           }
   1064         }
   1065       }
   1066       p+=GetPixelChannels(image);
   1067     }
   1068     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
   1069       image->rows);
   1070     if (status == MagickFalse)
   1071       break;
   1072   }
   1073   if (LocaleCompare(image_info->magick,"JPT") == 0)
   1074     jp2_codec=opj_create_compress(OPJ_CODEC_JPT);
   1075   else
   1076     if (LocaleCompare(image_info->magick,"J2K") == 0)
   1077       jp2_codec=opj_create_compress(OPJ_CODEC_J2K);
   1078     else
   1079       jp2_codec=opj_create_compress(OPJ_CODEC_JP2);
   1080   opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
   1081   opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
   1082   opj_setup_encoder(jp2_codec,&parameters,jp2_image);
   1083   jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,OPJ_FALSE);
   1084   if (jp2_stream == (opj_stream_t *) NULL)
   1085     {
   1086       opj_destroy_codec(jp2_codec);
   1087       opj_image_destroy(jp2_image);
   1088       ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
   1089     }
   1090   opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
   1091   opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
   1092   opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
   1093   opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
   1094   opj_stream_set_user_data(jp2_stream,image,NULL);
   1095   jp2_status=opj_start_compress(jp2_codec,jp2_image,jp2_stream);
   1096   if ((jp2_status == 0) || (opj_encode(jp2_codec,jp2_stream) == 0) ||
   1097       (opj_end_compress(jp2_codec,jp2_stream) == 0))
   1098     {
   1099       opj_stream_destroy(jp2_stream);
   1100       opj_destroy_codec(jp2_codec);
   1101       opj_image_destroy(jp2_image);
   1102       ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
   1103     }
   1104   /*
   1105     Free resources.
   1106   */
   1107   opj_stream_destroy(jp2_stream);
   1108   opj_destroy_codec(jp2_codec);
   1109   opj_image_destroy(jp2_image);
   1110   (void) CloseBlob(image);
   1111   return(MagickTrue);
   1112 }
   1113 #endif
   1114