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