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