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