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