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