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