2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write JPEG-2000 Image Format %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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/quantum-private.h"
65 #include "MagickCore/static.h"
66 #include "MagickCore/statistic.h"
67 #include "MagickCore/string_.h"
68 #include "MagickCore/module.h"
69 #if defined(MAGICKCORE_JP2_DELEGATE)
70 #ifndef JAS_IMAGE_CM_GRAY
71 #define JAS_IMAGE_CM_GRAY JAS_IMAGE_CS_GRAY
73 #ifndef JAS_IMAGE_CM_RGB
74 #define JAS_IMAGE_CM_RGB JAS_IMAGE_CS_RGB
77 #define uchar unsigned char
80 #define ushort unsigned short
83 #define uint unsigned int
85 #if !defined(ssize_tssize_t)
86 #define ssize_tssize_t long long
88 #if !defined(ussize_tssize_t)
89 #define ussize_tssize_t unsigned long long
94 #undef PACKAGE_TARNAME
95 #undef PACKAGE_VERSION
96 #include "jasper/jasper.h"
99 #undef PACKAGE_TARNAME
100 #undef PACKAGE_VERSION
105 Forward declarations.
107 #if defined(MAGICKCORE_JP2_DELEGATE)
108 static MagickBooleanType
109 WriteJP2Image(const ImageInfo *,Image *,ExceptionInfo *);
111 static volatile MagickBooleanType
112 instantiate_jp2 = MagickFalse;
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 % IsJP2() returns MagickTrue if the image format type, identified by the
127 % magick string, is JP2.
129 % The format of the IsJP2 method is:
131 % MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
133 % A description of each parameter follows:
135 % o magick: compare image format pattern against these bytes.
137 % o length: Specifies the length of the magick string.
140 static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
144 if (memcmp(magick+4,"\152\120\040\040\015",5) == 0)
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % IsJPC()() returns MagickTrue if the image format type, identified by the
161 % magick string, is JPC.
163 % The format of the IsJPC method is:
165 % MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
167 % A description of each parameter follows:
169 % o magick: compare image format pattern against these bytes.
171 % o length: Specifies the length of the magick string.
174 static MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
178 if (memcmp(magick,"\377\117",2) == 0)
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 % R e a d J P 2 I m a g e %
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 % ReadJP2Image() reads a JPEG 2000 Image file (JP2) or JPEG 2000
195 % codestream (JPC) image file and returns it. It allocates the memory
196 % necessary for the new Image structure and returns a pointer to the new
197 % image or set of images.
199 % JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
201 % The format of the ReadJP2Image method is:
203 % Image *ReadJP2Image(const ImageInfo *image_info,
204 % ExceptionInfo *exception)
206 % A description of each parameter follows:
208 % o image_info: the image info.
210 % o exception: return any errors or warnings in this structure.
213 #if defined(MAGICKCORE_JP2_DELEGATE)
215 typedef struct _StreamManager
224 static int BlobRead(jas_stream_obj_t *object,char *buffer,const int length)
232 source=(StreamManager *) object;
233 count=ReadBlob(source->image,(size_t) length,(unsigned char *) buffer);
237 static int BlobWrite(jas_stream_obj_t *object,char *buffer,const int length)
245 source=(StreamManager *) object;
246 count=WriteBlob(source->image,(size_t) length,(unsigned char *) buffer);
250 static long BlobSeek(jas_stream_obj_t *object,long offset,int origin)
255 source=(StreamManager *) object;
256 return((long) SeekBlob(source->image,offset,origin));
259 static int BlobClose(jas_stream_obj_t *object)
264 source=(StreamManager *) object;
265 (void) CloseBlob(source->image);
267 source=(StreamManager *) NULL;
271 static inline size_t MagickMax(const size_t x,const size_t y)
278 static inline size_t MagickMin(const size_t x,const size_t y)
285 static jas_stream_t *JP2StreamManager(Image *image)
287 static jas_stream_ops_t
302 stream=(jas_stream_t *) jas_malloc(sizeof(*stream));
303 if (stream == (jas_stream_t *) NULL)
304 return((jas_stream_t *) NULL);
305 (void) ResetMagickMemory(stream,0,sizeof(*stream));
306 stream->rwlimit_=(-1);
307 stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
308 if (stream->obj_ == (jas_stream_obj_t *) NULL)
309 return((jas_stream_t *) NULL);
310 (void) ResetMagickMemory(stream->obj_,0,sizeof(StreamManager));
311 stream->ops_=(&StreamOperators);
312 stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
313 stream->bufbase_=(unsigned char *) jas_malloc(JAS_STREAM_BUFSIZE+
314 JAS_STREAM_MAXPUTBACK);
315 if (stream->bufbase_ == (void *) NULL)
317 stream->bufbase_=stream->tinybuf_;
322 stream->bufmode_=JAS_STREAM_FREEBUF | JAS_STREAM_BUFMODEMASK;
323 stream->bufsize_=JAS_STREAM_BUFSIZE;
325 stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
326 stream->ptr_=stream->bufstart_;
328 source=(StreamManager *) stream->obj_;
333 static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
368 maximum_component_depth,
380 assert(image_info != (const ImageInfo *) NULL);
381 assert(image_info->signature == MagickSignature);
382 if (image_info->debug != MagickFalse)
383 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
384 image_info->filename);
385 assert(exception != (ExceptionInfo *) NULL);
386 assert(exception->signature == MagickSignature);
387 image=AcquireImage(image_info,exception);
388 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
389 if (status == MagickFalse)
391 image=DestroyImageList(image);
392 return((Image *) NULL);
395 Initialize JPEG 2000 API.
397 jp2_stream=JP2StreamManager(image);
398 if (jp2_stream == (jas_stream_t *) NULL)
399 ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
400 jp2_image=jas_image_decode(jp2_stream,-1,0);
401 if (jp2_image == (jas_image_t *) NULL)
403 (void) jas_stream_close(jp2_stream);
404 ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
406 image->columns=jas_image_width(jp2_image);
407 image->rows=jas_image_height(jp2_image);
408 image->compression=JPEG2000Compression;
409 switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
411 case JAS_CLRSPC_FAM_RGB:
413 SetImageColorspace(image,RGBColorspace,exception);
414 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_R);
415 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_G);
416 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_B);
417 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
419 (void) jas_stream_close(jp2_stream);
420 jas_image_destroy(jp2_image);
421 ThrowReaderException(CorruptImageError,"MissingImageChannel");
424 components[3]=jas_image_getcmptbytype(jp2_image,3);
425 if (components[3] > 0)
427 image->alpha_trait=BlendPixelTrait;
432 case JAS_CLRSPC_FAM_GRAY:
434 SetImageColorspace(image,GRAYColorspace,exception);
435 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_GRAY_Y);
436 if (components[0] < 0)
438 (void) jas_stream_close(jp2_stream);
439 jas_image_destroy(jp2_image);
440 ThrowReaderException(CorruptImageError,"MissingImageChannel");
445 case JAS_CLRSPC_FAM_YCBCR:
447 SetImageColorspace(image,YCbCrColorspace,exception);
448 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
449 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
450 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
451 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
453 (void) jas_stream_close(jp2_stream);
454 jas_image_destroy(jp2_image);
455 ThrowReaderException(CorruptImageError,"MissingImageChannel");
458 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
459 if (components[3] > 0)
461 image->alpha_trait=BlendPixelTrait;
466 case JAS_CLRSPC_FAM_XYZ:
468 SetImageColorspace(image,XYZColorspace,exception);
469 components[0]=jas_image_getcmptbytype(jp2_image,0);
470 components[1]=jas_image_getcmptbytype(jp2_image,1);
471 components[2]=jas_image_getcmptbytype(jp2_image,2);
472 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
474 (void) jas_stream_close(jp2_stream);
475 jas_image_destroy(jp2_image);
476 ThrowReaderException(CorruptImageError,"MissingImageChannel");
479 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
480 if (components[3] > 0)
482 image->alpha_trait=BlendPixelTrait;
487 case JAS_CLRSPC_FAM_LAB:
489 SetImageColorspace(image,LabColorspace,exception);
490 components[0]=jas_image_getcmptbytype(jp2_image,0);
491 components[1]=jas_image_getcmptbytype(jp2_image,1);
492 components[2]=jas_image_getcmptbytype(jp2_image,2);
493 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
495 (void) jas_stream_close(jp2_stream);
496 jas_image_destroy(jp2_image);
497 ThrowReaderException(CorruptImageError,"MissingImageChannel");
500 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
501 if (components[3] > 0)
503 image->alpha_trait=BlendPixelTrait;
510 (void) jas_stream_close(jp2_stream);
511 jas_image_destroy(jp2_image);
512 ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
515 for (i=0; i < (ssize_t) number_components; i++)
521 width=(size_t) (jas_image_cmptwidth(jp2_image,components[i])*
522 jas_image_cmpthstep(jp2_image,components[i]));
523 height=(size_t) (jas_image_cmptheight(jp2_image,components[i])*
524 jas_image_cmptvstep(jp2_image,components[i]));
525 x_step[i]=(unsigned int) jas_image_cmpthstep(jp2_image,components[i]);
526 y_step[i]=(unsigned int) jas_image_cmptvstep(jp2_image,components[i]);
527 if ((width != image->columns) || (height != image->rows) ||
528 (jas_image_cmpttlx(jp2_image,components[i]) != 0) ||
529 (jas_image_cmpttly(jp2_image,components[i]) != 0) ||
530 (jas_image_cmptsgnd(jp2_image,components[i]) != MagickFalse))
532 (void) jas_stream_close(jp2_stream);
533 jas_image_destroy(jp2_image);
534 ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported");
538 Convert JPEG 2000 pixels.
540 image->alpha_trait=number_components > 3 ? BlendPixelTrait :
542 maximum_component_depth=0;
543 for (i=0; i < (ssize_t) number_components; i++)
545 maximum_component_depth=(unsigned int) MagickMax((size_t)
546 jas_image_cmptprec(jp2_image,components[i]),(size_t)
547 maximum_component_depth);
548 pixels[i]=jas_matrix_create(1,(int) (image->columns/x_step[i]));
549 if (pixels[i] == (jas_matrix_t *) NULL)
551 for (--i; i >= 0; i--)
552 jas_matrix_destroy(pixels[i]);
553 jas_image_destroy(jp2_image);
554 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
557 image->depth=maximum_component_depth;
558 if (image_info->ping != MagickFalse)
560 (void) jas_stream_close(jp2_stream);
561 jas_image_destroy(jp2_image);
562 return(GetFirstImageInList(image));
564 for (i=0; i < (ssize_t) number_components; i++)
565 range[i]=GetQuantumRange((size_t) jas_image_cmptprec(jp2_image,
567 for (y=0; y < (ssize_t) image->rows; y++)
569 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
570 if (q == (Quantum *) NULL)
572 for (i=0; i < (ssize_t) number_components; i++)
573 (void) jas_image_readcmpt(jp2_image,(short) components[i],0,
574 (jas_image_coord_t) (y/y_step[i]),(jas_image_coord_t) (image->columns/
575 x_step[i]),1,pixels[i]);
576 switch (number_components)
583 for (x=0; x < (ssize_t) image->columns; x++)
585 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
586 SetPixelGray(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
587 q+=GetPixelChannels(image);
596 for (x=0; x < (ssize_t) image->columns; x++)
598 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
599 SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
600 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
601 SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
602 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
603 SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
604 q+=GetPixelChannels(image);
613 for (x=0; x < (ssize_t) image->columns; x++)
615 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
616 SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
617 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
618 SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
619 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
620 SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
621 pixel=(QuantumAny) jas_matrix_getv(pixels[3],x/x_step[3]);
622 SetPixelAlpha(image,ScaleAnyToQuantum((QuantumAny) pixel,range[3]),q);
623 q+=GetPixelChannels(image);
628 if (SyncAuthenticPixels(image,exception) == MagickFalse)
630 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
632 if (status == MagickFalse)
635 cm_profile=jas_image_cmprof(jp2_image);
636 icc_profile=(jas_iccprof_t *) NULL;
637 if (cm_profile != (jas_cmprof_t *) NULL)
638 icc_profile=jas_iccprof_createfromcmprof(cm_profile);
639 if (icc_profile != (jas_iccprof_t *) NULL)
644 icc_stream=jas_stream_memopen(NULL,0);
645 if ((icc_stream != (jas_stream_t *) NULL) &&
646 (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
647 (jas_stream_flush(icc_stream) == 0))
657 Extract the icc profile, handle errors without much noise.
659 blob=(jas_stream_memobj_t *) icc_stream->obj_;
660 if (image->debug != MagickFalse)
661 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
662 "Profile: ICC, %.20g bytes",(double) blob->len_);
663 profile=BlobToStringInfo(blob->buf_,blob->len_);
664 if (profile == (StringInfo *) NULL)
665 ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");
666 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
667 if (icc_profile == (StringInfo *) NULL)
668 (void) SetImageProfile(image,"icc",profile,exception);
670 (void) ConcatenateStringInfo(icc_profile,profile);
671 profile=DestroyStringInfo(profile);
672 (void) jas_stream_close(icc_stream);
675 (void) jas_stream_close(jp2_stream);
676 jas_image_destroy(jp2_image);
677 for (i=0; i < (ssize_t) number_components; i++)
678 jas_matrix_destroy(pixels[i]);
679 return(GetFirstImageInList(image));
684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688 % R e g i s t e r J P 2 I m a g e %
692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694 % RegisterJP2Image() adds attributes for the JP2 image format to the list of
695 % supported formats. The attributes include the image format tag, a method
696 % method to read and/or write the format, whether the format supports the
697 % saving of more than one frame to the same file or blob, whether the format
698 % supports native in-memory I/O, and a brief description of the format.
700 % The format of the RegisterJP2Image method is:
702 % size_t RegisterJP2Image(void)
705 ModuleExport size_t RegisterJP2Image(void)
710 entry=SetMagickInfo("JP2");
711 entry->description=ConstantString("JPEG-2000 File Format Syntax");
712 entry->mime_type=ConstantString("image/jp2");
713 entry->module=ConstantString("JP2");
714 entry->magick=(IsImageFormatHandler *) IsJP2;
715 entry->adjoin=MagickFalse;
716 entry->seekable_stream=MagickTrue;
717 entry->thread_support=NoThreadSupport;
718 #if defined(MAGICKCORE_JP2_DELEGATE)
719 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
720 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
722 (void) RegisterMagickInfo(entry);
723 entry=SetMagickInfo("JPC");
724 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
725 entry->mime_type=ConstantString("image/jp2");
726 entry->module=ConstantString("JP2");
727 entry->magick=(IsImageFormatHandler *) IsJPC;
728 entry->adjoin=MagickFalse;
729 entry->seekable_stream=MagickTrue;
730 entry->thread_support=NoThreadSupport;
731 #if defined(MAGICKCORE_JP2_DELEGATE)
732 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
733 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
735 (void) RegisterMagickInfo(entry);
736 entry=SetMagickInfo("J2C");
737 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
738 entry->mime_type=ConstantString("image/jp2");
739 entry->module=ConstantString("JP2");
740 entry->magick=(IsImageFormatHandler *) IsJPC;
741 entry->adjoin=MagickFalse;
742 entry->seekable_stream=MagickTrue;
743 entry->thread_support=NoThreadSupport;
744 #if defined(MAGICKCORE_JP2_DELEGATE)
745 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
746 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
748 (void) RegisterMagickInfo(entry);
749 entry=SetMagickInfo("J2K");
750 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
751 entry->mime_type=ConstantString("image/jp2");
752 entry->module=ConstantString("JP2");
753 entry->magick=(IsImageFormatHandler *) IsJPC;
754 entry->adjoin=MagickFalse;
755 entry->seekable_stream=MagickTrue;
756 entry->thread_support=NoThreadSupport;
757 #if defined(MAGICKCORE_JP2_DELEGATE)
758 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
759 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
761 (void) RegisterMagickInfo(entry);
762 entry=SetMagickInfo("JPX");
763 entry->description=ConstantString("JPEG-2000 File Format Syntax");
764 entry->mime_type=ConstantString("image/jp2");
765 entry->module=ConstantString("JP2");
766 entry->magick=(IsImageFormatHandler *) IsJPC;
767 entry->adjoin=MagickFalse;
768 entry->seekable_stream=MagickTrue;
769 entry->thread_support=NoThreadSupport;
770 #if defined(MAGICKCORE_JP2_DELEGATE)
771 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
772 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
774 (void) RegisterMagickInfo(entry);
775 entry=SetMagickInfo("PGX");
776 entry->description=ConstantString("JPEG-2000 VM Format");
777 entry->mime_type=ConstantString("image/jp2");
778 entry->module=ConstantString("JP2");
779 entry->magick=(IsImageFormatHandler *) IsJPC;
780 entry->adjoin=MagickFalse;
781 entry->seekable_stream=MagickTrue;
782 entry->thread_support=NoThreadSupport;
783 #if defined(MAGICKCORE_JP2_DELEGATE)
784 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
786 (void) RegisterMagickInfo(entry);
787 #if defined(MAGICKCORE_JP2_DELEGATE)
788 if (instantiate_jp2 == MagickFalse)
791 instantiate_jp2=MagickTrue;
794 return(MagickImageCoderSignature);
798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802 % U n r e g i s t e r J P 2 I m a g e %
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808 % UnregisterJP2Image() removes format registrations made by the JP2 module
809 % from the list of supported formats.
811 % The format of the UnregisterJP2Image method is:
813 % UnregisterJP2Image(void)
816 ModuleExport void UnregisterJP2Image(void)
818 (void) UnregisterMagickInfo("PGX");
819 (void) UnregisterMagickInfo("J2K");
820 (void) UnregisterMagickInfo("J2C");
821 (void) UnregisterMagickInfo("JPC");
822 (void) UnregisterMagickInfo("JP2");
823 #if defined(MAGICKCORE_JP2_DELEGATE)
824 if (instantiate_jp2 != MagickFalse)
827 instantiate_jp2=MagickFalse;
832 #if defined(MAGICKCORE_JP2_DELEGATE)
834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838 % W r i t e J P 2 I m a g e %
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
844 % WriteJP2Image() writes an image in the JPEG 2000 image format.
846 % JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
848 % The format of the WriteJP2Image method is:
850 % MagickBooleanType WriteJP2Image(const ImageInfo *image_info,
851 % Image *image,ExceptionInfo *exception)
853 % A description of each parameter follows.
855 % o image_info: the image info.
857 % o image: The image.
859 % o exception: return any errors or warnings in this structure.
862 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
863 ExceptionInfo *exception)
867 magick[MaxTextExtent],
891 register const Quantum
908 assert(image_info != (const ImageInfo *) NULL);
909 assert(image_info->signature == MagickSignature);
910 assert(image != (Image *) NULL);
911 assert(image->signature == MagickSignature);
912 if (image->debug != MagickFalse)
913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
914 assert(exception != (ExceptionInfo *) NULL);
915 assert(exception->signature == MagickSignature);
916 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
917 if (status == MagickFalse)
920 Initialize JPEG 2000 API.
922 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
923 (void) TransformImageColorspace(image,sRGBColorspace,exception);
924 jp2_stream=JP2StreamManager(image);
925 if (jp2_stream == (jas_stream_t *) NULL)
926 ThrowWriterException(DelegateError,"UnableToManageJP2Stream");
927 number_components=image->alpha_trait ? 4UL : 3UL;
928 if (IsGrayColorspace(image->colorspace) != MagickFalse)
930 if ((image->columns != (unsigned int) image->columns) ||
931 (image->rows != (unsigned int) image->rows))
932 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
933 (void) ResetMagickMemory(&component_info,0,sizeof(component_info));
934 for (i=0; i < (ssize_t) number_components; i++)
936 component_info[i].tlx=0;
937 component_info[i].tly=0;
938 component_info[i].hstep=1;
939 component_info[i].vstep=1;
940 component_info[i].width=(unsigned int) image->columns;
941 component_info[i].height=(unsigned int) image->rows;
942 component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2);
943 component_info[i].sgnd=MagickFalse;
945 jp2_image=jas_image_create((int) number_components,component_info,
947 if (jp2_image == (jas_image_t *) NULL)
948 ThrowWriterException(DelegateError,"UnableToCreateImage");
949 switch (image->colorspace)
957 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB);
958 jas_image_setcmpttype(jp2_image,0,
959 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
960 jas_image_setcmpttype(jp2_image,1,
961 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
962 jas_image_setcmpttype(jp2_image,2,
963 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
964 if (number_components == 4)
965 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
971 Grayscale colorspace.
973 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY);
974 jas_image_setcmpttype(jp2_image,0,
975 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
978 case YCbCrColorspace:
983 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SYCBCR);
984 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
985 JAS_IMAGE_CT_COLOR(0));
986 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
987 JAS_IMAGE_CT_COLOR(1));
988 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
989 JAS_IMAGE_CT_COLOR(2));
990 if (number_components == 4)
991 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
999 jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIEXYZ);
1000 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1001 JAS_IMAGE_CT_COLOR(0));
1002 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1003 JAS_IMAGE_CT_COLOR(1));
1004 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1005 JAS_IMAGE_CT_COLOR(2));
1006 if (number_components == 4)
1007 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1015 jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIELAB);
1016 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1017 JAS_IMAGE_CT_COLOR(0));
1018 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1019 JAS_IMAGE_CT_COLOR(1));
1020 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1021 JAS_IMAGE_CT_COLOR(2));
1022 if (number_components == 4)
1023 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1031 jas_image_setclrspc(jp2_image,JAS_CLRSPC_UNKNOWN);
1032 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1033 JAS_IMAGE_CT_COLOR(0));
1034 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1035 JAS_IMAGE_CT_COLOR(1));
1036 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1037 JAS_IMAGE_CT_COLOR(2));
1038 if (number_components == 4)
1039 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1044 Convert to JPEG 2000 pixels.
1046 for (i=0; i < (ssize_t) number_components; i++)
1048 pixels[i]=jas_matrix_create(1,(int) image->columns);
1049 if (pixels[i] == (jas_matrix_t *) NULL)
1051 for (x=0; x < i; x++)
1052 jas_matrix_destroy(pixels[x]);
1053 jas_image_destroy(jp2_image);
1054 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1057 range=GetQuantumRange((size_t) component_info[0].prec);
1058 for (y=0; y < (ssize_t) image->rows; y++)
1060 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1061 if (p == (const Quantum *) NULL)
1063 for (x=0; x < (ssize_t) image->columns; x++)
1065 if (number_components == 1)
1066 jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1067 ClampToQuantum(GetPixelLuma(image,p)),range));
1070 jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1071 GetPixelRed(image,p),range));
1072 jas_matrix_setv(pixels[1],x,(jas_seqent_t) ScaleQuantumToAny(
1073 GetPixelGreen(image,p),range));
1074 jas_matrix_setv(pixels[2],x,(jas_seqent_t) ScaleQuantumToAny(
1075 GetPixelBlue(image,p),range));
1076 if (number_components > 3)
1077 jas_matrix_setv(pixels[3],x,(jas_seqent_t) ScaleQuantumToAny(
1078 GetPixelAlpha(image,p),range));
1080 p+=GetPixelChannels(image);
1082 for (i=0; i < (ssize_t) number_components; i++)
1083 (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y,
1084 (unsigned int) image->columns,1,pixels[i]);
1085 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1087 if (status == MagickFalse)
1090 (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1091 if (LocaleCompare(magick,"J2C") == 0)
1092 (void) CopyMagickString(magick,"JPC",MaxTextExtent);
1093 LocaleLower(magick);
1094 format=jas_image_strtofmt(magick);
1095 options=(char *) NULL;
1096 ResetImageOptionIterator(image_info);
1097 key=GetNextImageOption(image_info);
1098 for ( ; key != (char *) NULL; key=GetNextImageOption(image_info))
1100 option=GetImageOption(image_info,key);
1101 if (option == (const char *) NULL)
1103 if (LocaleNCompare(key,"jp2:",4) == 0)
1105 (void) ConcatenateString(&options,key+4);
1106 if (*option != '\0')
1108 (void) ConcatenateString(&options,"=");
1109 (void) ConcatenateString(&options,option);
1111 (void) ConcatenateString(&options," ");
1114 option=GetImageOption(image_info,"jp2:rate");
1115 if ((option == (const char *) NULL) &&
1116 (image_info->compression != LosslessJPEGCompression) &&
1117 (image->quality != UndefinedCompressionQuality) &&
1118 ((double) image->quality <= 99.5) &&
1119 ((image->rows*image->columns) > 2500))
1122 option[MaxTextExtent];
1131 alpha=115.0-image->quality;
1132 rate=100.0/(alpha*alpha);
1134 header_size+=(number_components-1)*142;
1135 number_pixels=(double) image->rows*image->columns*number_components*
1136 (GetImageQuantumDepth(image,MagickTrue)/8);
1137 target_size=(number_pixels*rate)+header_size;
1138 rate=target_size/number_pixels;
1139 (void) FormatLocaleString(option,MaxTextExtent,"rate=%g",rate);
1140 (void) ConcatenateString(&options,option);
1142 status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ?
1143 MagickTrue : MagickFalse;
1144 if (options != (char *) NULL)
1145 options=DestroyString(options);
1146 (void) jas_stream_close(jp2_stream);
1147 for (i=0; i < (ssize_t) number_components; i++)
1148 jas_matrix_destroy(pixels[i]);
1149 jas_image_destroy(jp2_image);
1150 if (status != MagickFalse)
1151 ThrowWriterException(DelegateError,"UnableToEncodeImageFile");