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