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