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