• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /*
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   register 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=1;
350   if ((image->columns != 0) && (image->rows != 0))
351     {
352       /*
353         Extract an area from the image.
354       */
355       jp2_status=opj_set_decode_area(jp2_codec,jp2_image,
356         (OPJ_INT32) image->extract_info.x,(OPJ_INT32) image->extract_info.y,
357         (OPJ_INT32) (image->extract_info.x+(ssize_t) image->columns),
358         (OPJ_INT32) (image->extract_info.y+(ssize_t) image->rows));
359       if (jp2_status == 0)
360         {
361           opj_stream_destroy(jp2_stream);
362           opj_destroy_codec(jp2_codec);
363           opj_image_destroy(jp2_image);
364           ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
365         }
366     }
367   if ((AcquireMagickResource(WidthResource,(size_t) jp2_image->comps[0].w) == MagickFalse) ||
368       (AcquireMagickResource(HeightResource,(size_t) jp2_image->comps[0].h) == MagickFalse))
369     {
370       opj_stream_destroy(jp2_stream);
371       opj_destroy_codec(jp2_codec);
372       opj_image_destroy(jp2_image);
373       ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
374     }
375   if ((image_info->number_scenes != 0) && (image_info->scene != 0))
376     jp2_status=opj_get_decoded_tile(jp2_codec,jp2_stream,jp2_image,
377       (unsigned int) image_info->scene-1);
378   else
379     if (image->ping == MagickFalse)
380       {
381         jp2_status=opj_set_decode_area(jp2_codec,jp2_image,0,0,
382           jp2_image->comps[0].w-1,jp2_image->comps[0].h-1);
383         if (jp2_status != 0)
384           jp2_status=opj_decode(jp2_codec,jp2_stream,jp2_image);
385         if (jp2_status != 0)
386           jp2_status=opj_end_decompress(jp2_codec,jp2_stream);
387       }
388   if (jp2_status == 0)
389     {
390       opj_stream_destroy(jp2_stream);
391       opj_destroy_codec(jp2_codec);
392       opj_image_destroy(jp2_image);
393       ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
394     }
395   opj_stream_destroy(jp2_stream);
396   for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
397   {
398     if ((jp2_image->comps[0].dx == 0) || (jp2_image->comps[0].dy == 0) ||
399         (jp2_image->comps[0].prec != jp2_image->comps[i].prec) ||
400         (jp2_image->comps[0].sgnd != jp2_image->comps[i].sgnd) ||
401         ((image->ping == MagickFalse) && (jp2_image->comps[i].data == NULL)))
402       {
403         opj_destroy_codec(jp2_codec);
404         opj_image_destroy(jp2_image);
405         ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported")
406       }
407   }
408   /*
409     Convert JP2 image.
410   */
411   image->columns=(size_t) jp2_image->comps[0].w;
412   image->rows=(size_t) jp2_image->comps[0].h;
413   image->depth=jp2_image->comps[0].prec;
414   image->compression=JPEG2000Compression;
415   if (jp2_image->numcomps == 1)
416     SetImageColorspace(image,GRAYColorspace,exception);
417   else
418     if (jp2_image->color_space == 2)
419       {
420         SetImageColorspace(image,GRAYColorspace,exception);
421         if (jp2_image->numcomps > 1)
422           image->alpha_trait=BlendPixelTrait;
423       }
424     else
425       if (jp2_image->color_space == 3)
426         SetImageColorspace(image,Rec601YCbCrColorspace,exception);
427   if (jp2_image->numcomps > 3)
428     image->alpha_trait=BlendPixelTrait;
429   if (jp2_image->icc_profile_buf != (unsigned char *) NULL)
430     {
431       StringInfo
432         *profile;
433 
434       profile=BlobToStringInfo(jp2_image->icc_profile_buf,
435         jp2_image->icc_profile_len);
436       if (profile != (StringInfo *) NULL)
437         {
438           SetImageProfile(image,"icc",profile,exception);
439           profile=DestroyStringInfo(profile);
440         }
441     }
442   if (image->ping != MagickFalse)
443     {
444       opj_destroy_codec(jp2_codec);
445       opj_image_destroy(jp2_image);
446       return(GetFirstImageInList(image));
447     }
448   status=SetImageExtent(image,image->columns,image->rows,exception);
449   if (status == MagickFalse)
450     {
451       opj_destroy_codec(jp2_codec);
452       opj_image_destroy(jp2_image);
453       return(DestroyImageList(image));
454     }
455   for (y=0; y < (ssize_t) image->rows; y++)
456   {
457     register Quantum
458       *magick_restrict q;
459 
460     register ssize_t
461       x;
462 
463     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
464     if (q == (Quantum *) NULL)
465       break;
466     for (x=0; x < (ssize_t) image->columns; x++)
467     {
468       for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
469       {
470         double
471           pixel,
472           scale;
473 
474         scale=QuantumRange/(double) ((1UL << jp2_image->comps[i].prec)-1);
475         pixel=scale*(jp2_image->comps[i].data[y/jp2_image->comps[i].dy*
476           image->columns/jp2_image->comps[i].dx+x/jp2_image->comps[i].dx]+
477           (jp2_image->comps[i].sgnd ? 1UL << (jp2_image->comps[i].prec-1) : 0));
478         switch (i)
479         {
480            case 0:
481            {
482              if (jp2_image->numcomps == 1)
483                {
484                  SetPixelGray(image,ClampToQuantum(pixel),q);
485                  SetPixelAlpha(image,OpaqueAlpha,q);
486                  break;
487                }
488              SetPixelRed(image,ClampToQuantum(pixel),q);
489              SetPixelGreen(image,ClampToQuantum(pixel),q);
490              SetPixelBlue(image,ClampToQuantum(pixel),q);
491              SetPixelAlpha(image,OpaqueAlpha,q);
492              break;
493            }
494            case 1:
495            {
496              if (jp2_image->numcomps == 2)
497                {
498                  SetPixelAlpha(image,ClampToQuantum(pixel),q);
499                  break;
500                }
501              SetPixelGreen(image,ClampToQuantum(pixel),q);
502              break;
503            }
504            case 2:
505            {
506              SetPixelBlue(image,ClampToQuantum(pixel),q);
507              break;
508            }
509            case 3:
510            {
511              SetPixelAlpha(image,ClampToQuantum(pixel),q);
512              break;
513            }
514         }
515       }
516       q+=GetPixelChannels(image);
517     }
518     if (SyncAuthenticPixels(image,exception) == MagickFalse)
519       break;
520     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
521       image->rows);
522     if (status == MagickFalse)
523       break;
524   }
525   /*
526     Free resources.
527   */
528   opj_destroy_codec(jp2_codec);
529   opj_image_destroy(jp2_image);
530   (void) CloseBlob(image);
531   if ((image_info->number_scenes != 0) && (image_info->scene != 0))
532     AppendImageToList(&image,CloneImage(image,0,0,MagickTrue,exception));
533   return(GetFirstImageInList(image));
534 }
535 #endif
536 
537 /*
538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 %                                                                             %
540 %                                                                             %
541 %                                                                             %
542 %   R e g i s t e r J P 2 I m a g e                                           %
543 %                                                                             %
544 %                                                                             %
545 %                                                                             %
546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547 %
548 %  RegisterJP2Image() adds attributes for the JP2 image format to the list of
549 %  supported formats.  The attributes include the image format tag, a method
550 %  method to read and/or write the format, whether the format supports the
551 %  saving of more than one frame to the same file or blob, whether the format
552 %  supports native in-memory I/O, and a brief description of the format.
553 %
554 %  The format of the RegisterJP2Image method is:
555 %
556 %      size_t RegisterJP2Image(void)
557 %
558 */
RegisterJP2Image(void)559 ModuleExport size_t RegisterJP2Image(void)
560 {
561   char
562     version[MagickPathExtent];
563 
564   MagickInfo
565     *entry;
566 
567   *version='\0';
568 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
569   (void) FormatLocaleString(version,MagickPathExtent,"%s",opj_version());
570 #endif
571   entry=AcquireMagickInfo("JP2","JP2","JPEG-2000 File Format Syntax");
572   if (*version != '\0')
573     entry->version=ConstantString(version);
574   entry->mime_type=ConstantString("image/jp2");
575   entry->magick=(IsImageFormatHandler *) IsJP2;
576   entry->flags^=CoderAdjoinFlag;
577   entry->flags|=CoderDecoderSeekableStreamFlag;
578   entry->flags|=CoderEncoderSeekableStreamFlag;
579 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
580   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
581   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
582 #endif
583   (void) RegisterMagickInfo(entry);
584   entry=AcquireMagickInfo("JP2","J2C","JPEG-2000 Code Stream Syntax");
585   if (*version != '\0')
586     entry->version=ConstantString(version);
587   entry->mime_type=ConstantString("image/jp2");
588   entry->magick=(IsImageFormatHandler *) IsJ2K;
589   entry->flags^=CoderAdjoinFlag;
590   entry->flags|=CoderDecoderSeekableStreamFlag;
591   entry->flags|=CoderEncoderSeekableStreamFlag;
592 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
593   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
594   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
595 #endif
596   (void) RegisterMagickInfo(entry);
597   entry=AcquireMagickInfo("JP2","J2K","JPEG-2000 Code Stream Syntax");
598   if (*version != '\0')
599     entry->version=ConstantString(version);
600   entry->mime_type=ConstantString("image/jp2");
601   entry->magick=(IsImageFormatHandler *) IsJ2K;
602   entry->flags^=CoderAdjoinFlag;
603   entry->flags|=CoderDecoderSeekableStreamFlag;
604   entry->flags|=CoderEncoderSeekableStreamFlag;
605 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
606   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
607   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
608 #endif
609   (void) RegisterMagickInfo(entry);
610   entry=AcquireMagickInfo("JP2","JPM","JPEG-2000 File Format Syntax");
611   if (*version != '\0')
612     entry->version=ConstantString(version);
613   entry->mime_type=ConstantString("image/jp2");
614   entry->magick=(IsImageFormatHandler *) IsJP2;
615   entry->flags^=CoderAdjoinFlag;
616   entry->flags|=CoderDecoderSeekableStreamFlag;
617   entry->flags|=CoderEncoderSeekableStreamFlag;
618 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
619   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
620   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
621 #endif
622   (void) RegisterMagickInfo(entry);
623   entry=AcquireMagickInfo("JP2","JPT","JPEG-2000 File Format Syntax");
624   if (*version != '\0')
625     entry->version=ConstantString(version);
626   entry->mime_type=ConstantString("image/jp2");
627   entry->magick=(IsImageFormatHandler *) IsJP2;
628   entry->flags^=CoderAdjoinFlag;
629   entry->flags|=CoderDecoderSeekableStreamFlag;
630   entry->flags|=CoderEncoderSeekableStreamFlag;
631 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
632   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
633   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
634 #endif
635   (void) RegisterMagickInfo(entry);
636   entry=AcquireMagickInfo("JP2","JPC","JPEG-2000 Code Stream Syntax");
637   if (*version != '\0')
638     entry->version=ConstantString(version);
639   entry->mime_type=ConstantString("image/jp2");
640   entry->magick=(IsImageFormatHandler *) IsJP2;
641   entry->flags^=CoderAdjoinFlag;
642   entry->flags|=CoderDecoderSeekableStreamFlag;
643   entry->flags|=CoderEncoderSeekableStreamFlag;
644 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
645   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
646   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
647 #endif
648   (void) RegisterMagickInfo(entry);
649   return(MagickImageCoderSignature);
650 }
651 
652 /*
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 %                                                                             %
655 %                                                                             %
656 %                                                                             %
657 %   U n r e g i s t e r J P 2 I m a g e                                       %
658 %                                                                             %
659 %                                                                             %
660 %                                                                             %
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 %
663 %  UnregisterJP2Image() removes format registrations made by the JP2 module
664 %  from the list of supported formats.
665 %
666 %  The format of the UnregisterJP2Image method is:
667 %
668 %      UnregisterJP2Image(void)
669 %
670 */
UnregisterJP2Image(void)671 ModuleExport void UnregisterJP2Image(void)
672 {
673   (void) UnregisterMagickInfo("JPC");
674   (void) UnregisterMagickInfo("JPT");
675   (void) UnregisterMagickInfo("JPM");
676   (void) UnregisterMagickInfo("JP2");
677   (void) UnregisterMagickInfo("J2K");
678 }
679 
680 #if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
681 /*
682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 %                                                                             %
684 %                                                                             %
685 %                                                                             %
686 %   W r i t e J P 2 I m a g e                                                 %
687 %                                                                             %
688 %                                                                             %
689 %                                                                             %
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691 %
692 %  WriteJP2Image() writes an image in the JPEG 2000 image format.
693 %
694 %  JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
695 %
696 %  The format of the WriteJP2Image method is:
697 %
698 %      MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
699 %        ExceptionInfo *exception)
700 %
701 %  A description of each parameter follows.
702 %
703 %    o image_info: the image info.
704 %
705 %    o image:  The image.
706 %
707 */
708 
CinemaProfileCompliance(const opj_image_t * jp2_image,opj_cparameters_t * parameters)709 static void CinemaProfileCompliance(const opj_image_t *jp2_image,
710   opj_cparameters_t *parameters)
711 {
712   /*
713     Digital Cinema 4K profile compliant codestream.
714   */
715   parameters->tile_size_on=OPJ_FALSE;
716   parameters->cp_tdx=1;
717   parameters->cp_tdy=1;
718   parameters->tp_flag='C';
719   parameters->tp_on=1;
720   parameters->cp_tx0=0;
721   parameters->cp_ty0=0;
722   parameters->image_offset_x0=0;
723   parameters->image_offset_y0=0;
724   parameters->cblockw_init=32;
725   parameters->cblockh_init=32;
726   parameters->csty|=0x01;
727   parameters->prog_order=OPJ_CPRL;
728   parameters->roi_compno=(-1);
729   parameters->subsampling_dx=1;
730   parameters->subsampling_dy=1;
731   parameters->irreversible=1;
732   if ((jp2_image->comps[0].w == 2048) || (jp2_image->comps[0].h == 1080))
733     {
734       /*
735         Digital Cinema 2K.
736       */
737       parameters->cp_cinema=OPJ_CINEMA2K_24;
738       parameters->cp_rsiz=OPJ_CINEMA2K;
739       parameters->max_comp_size=1041666;
740       if (parameters->numresolution > 6)
741         parameters->numresolution=6;
742 
743     }
744   if ((jp2_image->comps[0].w == 4096) || (jp2_image->comps[0].h == 2160))
745     {
746       /*
747         Digital Cinema 4K.
748       */
749       parameters->cp_cinema=OPJ_CINEMA4K_24;
750       parameters->cp_rsiz=OPJ_CINEMA4K;
751       parameters->max_comp_size=1041666;
752       if (parameters->numresolution < 1)
753         parameters->numresolution=1;
754       if (parameters->numresolution > 7)
755         parameters->numresolution=7;
756       parameters->numpocs=2;
757       parameters->POC[0].tile=1;
758       parameters->POC[0].resno0=0;
759       parameters->POC[0].compno0=0;
760       parameters->POC[0].layno1=1;
761       parameters->POC[0].resno1=parameters->numresolution-1;
762       parameters->POC[0].compno1=3;
763       parameters->POC[0].prg1=OPJ_CPRL;
764       parameters->POC[1].tile=1;
765       parameters->POC[1].resno0=parameters->numresolution-1;
766       parameters->POC[1].compno0=0;
767       parameters->POC[1].layno1=1;
768       parameters->POC[1].resno1=parameters->numresolution;
769       parameters->POC[1].compno1=3;
770       parameters->POC[1].prg1=OPJ_CPRL;
771     }
772   parameters->tcp_numlayers=1;
773   parameters->tcp_rates[0]=((float) (jp2_image->numcomps*jp2_image->comps[0].w*
774     jp2_image->comps[0].h*jp2_image->comps[0].prec))/(parameters->max_comp_size*
775     8*jp2_image->comps[0].dx*jp2_image->comps[0].dy);
776   parameters->cp_disto_alloc=1;
777 }
778 
WriteJP2Image(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)779 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
780   ExceptionInfo *exception)
781 {
782   const char
783     *option,
784     *property;
785 
786   int
787     jp2_status;
788 
789   MagickBooleanType
790     status;
791 
792   opj_codec_t
793     *jp2_codec;
794 
795   OPJ_COLOR_SPACE
796     jp2_colorspace;
797 
798   opj_cparameters_t
799     parameters;
800 
801   opj_image_cmptparm_t
802     jp2_info[5];
803 
804   opj_image_t
805     *jp2_image;
806 
807   opj_stream_t
808     *jp2_stream;
809 
810   register ssize_t
811     i;
812 
813   ssize_t
814     y;
815 
816   unsigned int
817     channels;
818 
819   /*
820     Open image file.
821   */
822   assert(image_info != (const ImageInfo *) NULL);
823   assert(image_info->signature == MagickCoreSignature);
824   assert(image != (Image *) NULL);
825   assert(image->signature == MagickCoreSignature);
826   if (image->debug != MagickFalse)
827     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
828   assert(exception != (ExceptionInfo *) NULL);
829   assert(exception->signature == MagickCoreSignature);
830   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
831   if (status == MagickFalse)
832     return(status);
833   /*
834     Initialize JPEG 2000 API.
835   */
836   opj_set_default_encoder_parameters(&parameters);
837   for (i=1; i < 6; i++)
838     if (((size_t) (1UL << (i+2)) > image->columns) &&
839         ((size_t) (1UL << (i+2)) > image->rows))
840       break;
841   parameters.numresolution=i;
842   option=GetImageOption(image_info,"jp2:number-resolutions");
843   if (option != (const char *) NULL)
844     parameters.numresolution=StringToInteger(option);
845   parameters.tcp_numlayers=1;
846   parameters.tcp_rates[0]=0;  /* lossless */
847   parameters.cp_disto_alloc=1;
848   if ((image_info->quality != 0) && (image_info->quality != 100))
849     {
850       parameters.tcp_distoratio[0]=(double) image_info->quality;
851       parameters.cp_fixed_quality=OPJ_TRUE;
852     }
853   if (image_info->extract != (char *) NULL)
854     {
855       RectangleInfo
856         geometry;
857 
858       int
859         flags;
860 
861       /*
862         Set tile size.
863       */
864       flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
865       parameters.cp_tdx=(int) geometry.width;
866       parameters.cp_tdy=(int) geometry.width;
867       if ((flags & HeightValue) != 0)
868         parameters.cp_tdy=(int) geometry.height;
869       if ((flags & XValue) != 0)
870         parameters.cp_tx0=geometry.x;
871       if ((flags & YValue) != 0)
872         parameters.cp_ty0=geometry.y;
873       parameters.tile_size_on=OPJ_TRUE;
874     }
875   option=GetImageOption(image_info,"jp2:quality");
876   if (option != (const char *) NULL)
877     {
878       register const char
879         *p;
880 
881       /*
882         Set quality PSNR.
883       */
884       p=option;
885       for (i=0; sscanf(p,"%f",&parameters.tcp_distoratio[i]) == 1; i++)
886       {
887         if (i > 100)
888           break;
889         while ((*p != '\0') && (*p != ','))
890           p++;
891         if (*p == '\0')
892           break;
893         p++;
894       }
895       parameters.tcp_numlayers=i+1;
896       parameters.cp_fixed_quality=OPJ_TRUE;
897     }
898   option=GetImageOption(image_info,"jp2:progression-order");
899   if (option != (const char *) NULL)
900     {
901       if (LocaleCompare(option,"LRCP") == 0)
902         parameters.prog_order=OPJ_LRCP;
903       if (LocaleCompare(option,"RLCP") == 0)
904         parameters.prog_order=OPJ_RLCP;
905       if (LocaleCompare(option,"RPCL") == 0)
906         parameters.prog_order=OPJ_RPCL;
907       if (LocaleCompare(option,"PCRL") == 0)
908         parameters.prog_order=OPJ_PCRL;
909       if (LocaleCompare(option,"CPRL") == 0)
910         parameters.prog_order=OPJ_CPRL;
911     }
912   option=GetImageOption(image_info,"jp2:rate");
913   if (option != (const char *) NULL)
914     {
915       register const char
916         *p;
917 
918       /*
919         Set compression rate.
920       */
921       p=option;
922       for (i=0; sscanf(p,"%f",&parameters.tcp_rates[i]) == 1; i++)
923       {
924         if (i >= 100)
925           break;
926         while ((*p != '\0') && (*p != ','))
927           p++;
928         if (*p == '\0')
929           break;
930         p++;
931       }
932       parameters.tcp_numlayers=i+1;
933       parameters.cp_disto_alloc=OPJ_TRUE;
934     }
935   if (image_info->sampling_factor != (const char *) NULL)
936     (void) sscanf(image_info->sampling_factor,"%d,%d",
937       &parameters.subsampling_dx,&parameters.subsampling_dy);
938   property=GetImageProperty(image,"comment",exception);
939   if (property != (const char *) NULL)
940     parameters.cp_comment=(char *) property;
941   channels=3;
942   jp2_colorspace=OPJ_CLRSPC_SRGB;
943   if (image->colorspace == YUVColorspace)
944     {
945       jp2_colorspace=OPJ_CLRSPC_SYCC;
946       parameters.subsampling_dx=2;
947     }
948   else
949     {
950       if (IsGrayColorspace(image->colorspace) != MagickFalse)
951         {
952           channels=1;
953           jp2_colorspace=OPJ_CLRSPC_GRAY;
954         }
955       else
956         (void) TransformImageColorspace(image,sRGBColorspace,exception);
957       if (image->alpha_trait != UndefinedPixelTrait)
958         channels++;
959     }
960   parameters.tcp_mct=channels == 3 ? 1 : 0;
961   memset(jp2_info,0,sizeof(jp2_info));
962   for (i=0; i < (ssize_t) channels; i++)
963   {
964     jp2_info[i].prec=(OPJ_UINT32) image->depth;
965     jp2_info[i].bpp=(OPJ_UINT32) image->depth;
966     if ((image->depth == 1) &&
967         ((LocaleCompare(image_info->magick,"JPT") == 0) ||
968          (LocaleCompare(image_info->magick,"JP2") == 0)))
969       {
970         jp2_info[i].prec++;  /* OpenJPEG returns exception for depth @ 1 */
971         jp2_info[i].bpp++;
972       }
973     jp2_info[i].sgnd=0;
974     jp2_info[i].dx=parameters.subsampling_dx;
975     jp2_info[i].dy=parameters.subsampling_dy;
976     jp2_info[i].w=(OPJ_UINT32) image->columns;
977     jp2_info[i].h=(OPJ_UINT32) image->rows;
978   }
979   jp2_image=opj_image_create((OPJ_UINT32) channels,jp2_info,jp2_colorspace);
980   if (jp2_image == (opj_image_t *) NULL)
981     ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
982   jp2_image->x0=parameters.image_offset_x0;
983   jp2_image->y0=parameters.image_offset_y0;
984   jp2_image->x1=(unsigned int) (2*parameters.image_offset_x0+(image->columns-1)*
985     parameters.subsampling_dx+1);
986   jp2_image->y1=(unsigned int) (2*parameters.image_offset_y0+(image->rows-1)*
987     parameters.subsampling_dx+1);
988   if ((image->depth == 12) &&
989       ((image->columns == 2048) || (image->rows == 1080) ||
990        (image->columns == 4096) || (image->rows == 2160)))
991     CinemaProfileCompliance(jp2_image,&parameters);
992   if (channels == 4)
993     jp2_image->comps[3].alpha=1;
994   else
995    if ((channels == 2) && (jp2_colorspace == OPJ_CLRSPC_GRAY))
996      jp2_image->comps[1].alpha=1;
997   /*
998     Convert to JP2 pixels.
999   */
1000   for (y=0; y < (ssize_t) image->rows; y++)
1001   {
1002     register const Quantum
1003       *p;
1004 
1005     ssize_t
1006       x;
1007 
1008     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1009     if (p == (const Quantum *) NULL)
1010       break;
1011     for (x=0; x < (ssize_t) image->columns; x++)
1012     {
1013       for (i=0; i < (ssize_t) channels; i++)
1014       {
1015         double
1016           scale;
1017 
1018         register int
1019           *q;
1020 
1021         scale=(double) ((1UL << jp2_image->comps[i].prec)-1)/QuantumRange;
1022         q=jp2_image->comps[i].data+(y/jp2_image->comps[i].dy*
1023           image->columns/jp2_image->comps[i].dx+x/jp2_image->comps[i].dx);
1024         switch (i)
1025         {
1026           case 0:
1027           {
1028             if (jp2_colorspace == OPJ_CLRSPC_GRAY)
1029               {
1030                 *q=(int) (scale*GetPixelGray(image,p));
1031                 break;
1032               }
1033             *q=(int) (scale*GetPixelRed(image,p));
1034             break;
1035           }
1036           case 1:
1037           {
1038             if (jp2_colorspace == OPJ_CLRSPC_GRAY)
1039               {
1040                 *q=(int) (scale*GetPixelAlpha(image,p));
1041                 break;
1042               }
1043             *q=(int) (scale*GetPixelGreen(image,p));
1044             break;
1045           }
1046           case 2:
1047           {
1048             *q=(int) (scale*GetPixelBlue(image,p));
1049             break;
1050           }
1051           case 3:
1052           {
1053             *q=(int) (scale*GetPixelAlpha(image,p));
1054             break;
1055           }
1056         }
1057       }
1058       p+=GetPixelChannels(image);
1059     }
1060     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1061       image->rows);
1062     if (status == MagickFalse)
1063       break;
1064   }
1065   if (LocaleCompare(image_info->magick,"JPT") == 0)
1066     jp2_codec=opj_create_compress(OPJ_CODEC_JPT);
1067   else
1068     if (LocaleCompare(image_info->magick,"J2K") == 0)
1069       jp2_codec=opj_create_compress(OPJ_CODEC_J2K);
1070     else
1071       jp2_codec=opj_create_compress(OPJ_CODEC_JP2);
1072   opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
1073   opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
1074   opj_setup_encoder(jp2_codec,&parameters,jp2_image);
1075   jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,OPJ_FALSE);
1076   if (jp2_stream == (opj_stream_t *) NULL)
1077     {
1078       opj_destroy_codec(jp2_codec);
1079       opj_image_destroy(jp2_image);
1080       ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1081     }
1082   opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
1083   opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
1084   opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
1085   opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
1086   opj_stream_set_user_data(jp2_stream,image,NULL);
1087   jp2_status=opj_start_compress(jp2_codec,jp2_image,jp2_stream);
1088   if ((jp2_status == 0) || (opj_encode(jp2_codec,jp2_stream) == 0) ||
1089       (opj_end_compress(jp2_codec,jp2_stream) == 0))
1090     {
1091       opj_stream_destroy(jp2_stream);
1092       opj_destroy_codec(jp2_codec);
1093       opj_image_destroy(jp2_image);
1094       ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1095     }
1096   /*
1097     Free resources.
1098   */
1099   opj_stream_destroy(jp2_stream);
1100   opj_destroy_codec(jp2_codec);
1101   opj_image_destroy(jp2_image);
1102   (void) CloseBlob(image);
1103   return(MagickTrue);
1104 }
1105 #endif
1106