2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write JPEG-2000 Image Format %
20 % Copyright 1999-2013 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/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/colorspace.h"
48 #include "MagickCore/colorspace-private.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/image.h"
54 #include "MagickCore/image-private.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/monitor.h"
59 #include "MagickCore/monitor-private.h"
60 #include "MagickCore/option.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/profile.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/static.h"
65 #include "MagickCore/statistic.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/module.h"
68 #if defined(MAGICKCORE_JP2_DELEGATE)
69 #ifndef JAS_IMAGE_CM_GRAY
70 #define JAS_IMAGE_CM_GRAY JAS_IMAGE_CS_GRAY
72 #ifndef JAS_IMAGE_CM_RGB
73 #define JAS_IMAGE_CM_RGB JAS_IMAGE_CS_RGB
76 #define uchar unsigned char
79 #define ushort unsigned short
82 #define uint unsigned int
84 #if !defined(ssize_tssize_t)
85 #define ssize_tssize_t long long
87 #if !defined(ussize_tssize_t)
88 #define ussize_tssize_t unsigned long long
93 #undef PACKAGE_TARNAME
94 #undef PACKAGE_VERSION
95 #include "jasper/jasper.h"
98 #undef PACKAGE_TARNAME
99 #undef PACKAGE_VERSION
104 Forward declarations.
106 #if defined(MAGICKCORE_JP2_DELEGATE)
107 static MagickBooleanType
108 WriteJP2Image(const ImageInfo *,Image *,ExceptionInfo *);
110 static volatile MagickBooleanType
111 instantiate_jp2 = MagickFalse;
115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 % IsJP2() returns MagickTrue if the image format type, identified by the
126 % magick string, is JP2.
128 % The format of the IsJP2 method is:
130 % MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
132 % A description of each parameter follows:
134 % o magick: compare image format pattern against these bytes.
136 % o length: Specifies the length of the magick string.
139 static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
143 if (memcmp(magick+4,"\152\120\040\040\015",5) == 0)
149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 % IsJPC()() returns MagickTrue if the image format type, identified by the
160 % magick string, is JPC.
162 % The format of the IsJPC method is:
164 % MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
166 % A description of each parameter follows:
168 % o magick: compare image format pattern against these bytes.
170 % o length: Specifies the length of the magick string.
173 static MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
177 if (memcmp(magick,"\377\117",2) == 0)
183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 % R e a d J P 2 I m a g e %
191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193 % ReadJP2Image() reads a JPEG 2000 Image file (JP2) or JPEG 2000
194 % codestream (JPC) image file and returns it. It allocates the memory
195 % necessary for the new Image structure and returns a pointer to the new
196 % image or set of images.
198 % JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
200 % The format of the ReadJP2Image method is:
202 % Image *ReadJP2Image(const ImageInfo *image_info,
203 % ExceptionInfo *exception)
205 % A description of each parameter follows:
207 % o image_info: the image info.
209 % o exception: return any errors or warnings in this structure.
212 #if defined(MAGICKCORE_JP2_DELEGATE)
214 typedef struct _StreamManager
223 static int BlobRead(jas_stream_obj_t *object,char *buffer,const int length)
231 source=(StreamManager *) object;
232 count=ReadBlob(source->image,(size_t) length,(unsigned char *) buffer);
236 static int BlobWrite(jas_stream_obj_t *object,char *buffer,const int length)
244 source=(StreamManager *) object;
245 count=WriteBlob(source->image,(size_t) length,(unsigned char *) buffer);
249 static long BlobSeek(jas_stream_obj_t *object,long offset,int origin)
254 source=(StreamManager *) object;
255 return((long) SeekBlob(source->image,offset,origin));
258 static int BlobClose(jas_stream_obj_t *object)
263 source=(StreamManager *) object;
264 (void) CloseBlob(source->image);
266 source=(StreamManager *) NULL;
270 static inline size_t MagickMax(const size_t x,const size_t y)
277 static inline size_t MagickMin(const size_t x,const size_t y)
284 static jas_stream_t *JP2StreamManager(Image *image)
286 static jas_stream_ops_t
301 stream=(jas_stream_t *) jas_malloc(sizeof(*stream));
302 if (stream == (jas_stream_t *) NULL)
303 return((jas_stream_t *) NULL);
304 (void) ResetMagickMemory(stream,0,sizeof(*stream));
305 stream->rwlimit_=(-1);
306 stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
307 if (stream->obj_ == (jas_stream_obj_t *) NULL)
308 return((jas_stream_t *) NULL);
309 (void) ResetMagickMemory(stream->obj_,0,sizeof(StreamManager));
310 stream->ops_=(&StreamOperators);
311 stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
312 stream->bufbase_=(unsigned char *) jas_malloc(JAS_STREAM_BUFSIZE+
313 JAS_STREAM_MAXPUTBACK);
314 if (stream->bufbase_ == (void *) NULL)
316 stream->bufbase_=stream->tinybuf_;
321 stream->bufmode_=JAS_STREAM_FREEBUF | JAS_STREAM_BUFMODEMASK;
322 stream->bufsize_=JAS_STREAM_BUFSIZE;
324 stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
325 stream->ptr_=stream->bufstart_;
327 source=(StreamManager *) stream->obj_;
332 static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
367 maximum_component_depth,
379 assert(image_info != (const ImageInfo *) NULL);
380 assert(image_info->signature == MagickSignature);
381 if (image_info->debug != MagickFalse)
382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
383 image_info->filename);
384 assert(exception != (ExceptionInfo *) NULL);
385 assert(exception->signature == MagickSignature);
386 image=AcquireImage(image_info,exception);
387 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
388 if (status == MagickFalse)
390 image=DestroyImageList(image);
391 return((Image *) NULL);
394 Initialize JPEG 2000 API.
396 jp2_stream=JP2StreamManager(image);
397 if (jp2_stream == (jas_stream_t *) NULL)
398 ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
399 jp2_image=jas_image_decode(jp2_stream,-1,0);
400 if (jp2_image == (jas_image_t *) NULL)
402 (void) jas_stream_close(jp2_stream);
403 ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
405 image->columns=jas_image_width(jp2_image);
406 image->rows=jas_image_height(jp2_image);
407 image->compression=JPEG2000Compression;
408 switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
410 case JAS_CLRSPC_FAM_RGB:
412 SetImageColorspace(image,RGBColorspace,exception);
413 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_R);
414 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_G);
415 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_B);
416 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
418 (void) jas_stream_close(jp2_stream);
419 jas_image_destroy(jp2_image);
420 ThrowReaderException(CorruptImageError,"MissingImageChannel");
423 components[3]=jas_image_getcmptbytype(jp2_image,3);
424 if (components[3] > 0)
426 image->alpha_trait=BlendPixelTrait;
431 case JAS_CLRSPC_FAM_GRAY:
433 SetImageColorspace(image,GRAYColorspace,exception);
434 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_GRAY_Y);
435 if (components[0] < 0)
437 (void) jas_stream_close(jp2_stream);
438 jas_image_destroy(jp2_image);
439 ThrowReaderException(CorruptImageError,"MissingImageChannel");
444 case JAS_CLRSPC_FAM_YCBCR:
446 SetImageColorspace(image,YCbCrColorspace,exception);
447 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
448 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
449 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
450 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
452 (void) jas_stream_close(jp2_stream);
453 jas_image_destroy(jp2_image);
454 ThrowReaderException(CorruptImageError,"MissingImageChannel");
457 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
458 if (components[3] > 0)
460 image->alpha_trait=BlendPixelTrait;
465 case JAS_CLRSPC_FAM_XYZ:
467 SetImageColorspace(image,XYZColorspace,exception);
468 components[0]=jas_image_getcmptbytype(jp2_image,0);
469 components[1]=jas_image_getcmptbytype(jp2_image,1);
470 components[2]=jas_image_getcmptbytype(jp2_image,2);
471 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
473 (void) jas_stream_close(jp2_stream);
474 jas_image_destroy(jp2_image);
475 ThrowReaderException(CorruptImageError,"MissingImageChannel");
478 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
479 if (components[3] > 0)
481 image->alpha_trait=BlendPixelTrait;
486 case JAS_CLRSPC_FAM_LAB:
488 SetImageColorspace(image,LabColorspace,exception);
489 components[0]=jas_image_getcmptbytype(jp2_image,0);
490 components[1]=jas_image_getcmptbytype(jp2_image,1);
491 components[2]=jas_image_getcmptbytype(jp2_image,2);
492 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
494 (void) jas_stream_close(jp2_stream);
495 jas_image_destroy(jp2_image);
496 ThrowReaderException(CorruptImageError,"MissingImageChannel");
499 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
500 if (components[3] > 0)
502 image->alpha_trait=BlendPixelTrait;
509 (void) jas_stream_close(jp2_stream);
510 jas_image_destroy(jp2_image);
511 ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
514 for (i=0; i < (ssize_t) number_components; i++)
520 width=(size_t) (jas_image_cmptwidth(jp2_image,components[i])*
521 jas_image_cmpthstep(jp2_image,components[i]));
522 height=(size_t) (jas_image_cmptheight(jp2_image,components[i])*
523 jas_image_cmptvstep(jp2_image,components[i]));
524 x_step[i]=(unsigned int) jas_image_cmpthstep(jp2_image,components[i]);
525 y_step[i]=(unsigned int) jas_image_cmptvstep(jp2_image,components[i]);
526 if ((width != image->columns) || (height != image->rows) ||
527 (jas_image_cmpttlx(jp2_image,components[i]) != 0) ||
528 (jas_image_cmpttly(jp2_image,components[i]) != 0) ||
529 (jas_image_cmptsgnd(jp2_image,components[i]) != MagickFalse))
531 (void) jas_stream_close(jp2_stream);
532 jas_image_destroy(jp2_image);
533 ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported");
537 Convert JPEG 2000 pixels.
539 image->alpha_trait=number_components > 3 ? BlendPixelTrait :
541 maximum_component_depth=0;
542 for (i=0; i < (ssize_t) number_components; i++)
544 maximum_component_depth=(unsigned int) MagickMax((size_t)
545 jas_image_cmptprec(jp2_image,components[i]),(size_t)
546 maximum_component_depth);
547 pixels[i]=jas_matrix_create(1,(int) (image->columns/x_step[i]));
548 if (pixels[i] == (jas_matrix_t *) NULL)
550 for (--i; i >= 0; i--)
551 jas_matrix_destroy(pixels[i]);
552 jas_image_destroy(jp2_image);
553 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
556 image->depth=maximum_component_depth;
557 if (image_info->ping != MagickFalse)
559 (void) jas_stream_close(jp2_stream);
560 jas_image_destroy(jp2_image);
561 return(GetFirstImageInList(image));
563 for (i=0; i < (ssize_t) number_components; i++)
564 range[i]=GetQuantumRange((size_t) jas_image_cmptprec(jp2_image,
566 for (y=0; y < (ssize_t) image->rows; y++)
568 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
569 if (q == (Quantum *) NULL)
571 for (i=0; i < (ssize_t) number_components; i++)
572 (void) jas_image_readcmpt(jp2_image,(short) components[i],0,
573 (jas_image_coord_t) (y/y_step[i]),(jas_image_coord_t) (image->columns/
574 x_step[i]),1,pixels[i]);
575 switch (number_components)
582 for (x=0; x < (ssize_t) image->columns; x++)
584 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
585 SetPixelGray(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
586 q+=GetPixelChannels(image);
595 for (x=0; x < (ssize_t) image->columns; x++)
597 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
598 SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
599 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
600 SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
601 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
602 SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
603 q+=GetPixelChannels(image);
612 for (x=0; x < (ssize_t) image->columns; x++)
614 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
615 SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
616 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
617 SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
618 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
619 SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
620 pixel=(QuantumAny) jas_matrix_getv(pixels[3],x/x_step[3]);
621 SetPixelAlpha(image,ScaleAnyToQuantum((QuantumAny) pixel,range[3]),q);
622 q+=GetPixelChannels(image);
627 if (SyncAuthenticPixels(image,exception) == MagickFalse)
629 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
631 if (status == MagickFalse)
634 cm_profile=jas_image_cmprof(jp2_image);
635 icc_profile=(jas_iccprof_t *) NULL;
636 if (cm_profile != (jas_cmprof_t *) NULL)
637 icc_profile=jas_iccprof_createfromcmprof(cm_profile);
638 if (icc_profile != (jas_iccprof_t *) NULL)
643 icc_stream=jas_stream_memopen(NULL,0);
644 if ((icc_stream != (jas_stream_t *) NULL) &&
645 (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
646 (jas_stream_flush(icc_stream) == 0))
656 Extract the icc profile, handle errors without much noise.
658 blob=(jas_stream_memobj_t *) icc_stream->obj_;
659 if (image->debug != MagickFalse)
660 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
661 "Profile: ICC, %.20g bytes",(double) blob->len_);
662 profile=BlobToStringInfo(blob->buf_,blob->len_);
663 if (profile == (StringInfo *) NULL)
664 ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");
665 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
666 if (icc_profile == (StringInfo *) NULL)
667 (void) SetImageProfile(image,"icc",profile,exception);
669 (void) ConcatenateStringInfo(icc_profile,profile);
670 profile=DestroyStringInfo(profile);
671 (void) jas_stream_close(icc_stream);
674 (void) jas_stream_close(jp2_stream);
675 jas_image_destroy(jp2_image);
676 for (i=0; i < (ssize_t) number_components; i++)
677 jas_matrix_destroy(pixels[i]);
678 return(GetFirstImageInList(image));
683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
687 % R e g i s t e r J P 2 I m a g e %
691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
693 % RegisterJP2Image() adds attributes for the JP2 image format to the list of
694 % supported formats. The attributes include the image format tag, a method
695 % method to read and/or write the format, whether the format supports the
696 % saving of more than one frame to the same file or blob, whether the format
697 % supports native in-memory I/O, and a brief description of the format.
699 % The format of the RegisterJP2Image method is:
701 % size_t RegisterJP2Image(void)
704 ModuleExport size_t RegisterJP2Image(void)
709 entry=SetMagickInfo("JP2");
710 entry->description=ConstantString("JPEG-2000 File Format Syntax");
711 entry->module=ConstantString("JP2");
712 entry->magick=(IsImageFormatHandler *) IsJP2;
713 entry->adjoin=MagickFalse;
714 entry->seekable_stream=MagickTrue;
715 entry->thread_support=NoThreadSupport;
716 #if defined(MAGICKCORE_JP2_DELEGATE)
717 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
718 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
720 (void) RegisterMagickInfo(entry);
721 entry=SetMagickInfo("JPC");
722 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
723 entry->module=ConstantString("JP2");
724 entry->magick=(IsImageFormatHandler *) IsJPC;
725 entry->adjoin=MagickFalse;
726 entry->seekable_stream=MagickTrue;
727 entry->thread_support=NoThreadSupport;
728 #if defined(MAGICKCORE_JP2_DELEGATE)
729 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
730 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
732 (void) RegisterMagickInfo(entry);
733 entry=SetMagickInfo("J2C");
734 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
735 entry->module=ConstantString("JP2");
736 entry->magick=(IsImageFormatHandler *) IsJPC;
737 entry->adjoin=MagickFalse;
738 entry->seekable_stream=MagickTrue;
739 entry->thread_support=NoThreadSupport;
740 #if defined(MAGICKCORE_JP2_DELEGATE)
741 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
742 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
744 (void) RegisterMagickInfo(entry);
745 entry=SetMagickInfo("J2K");
746 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
747 entry->module=ConstantString("JP2");
748 entry->magick=(IsImageFormatHandler *) IsJPC;
749 entry->adjoin=MagickFalse;
750 entry->seekable_stream=MagickTrue;
751 entry->thread_support=NoThreadSupport;
752 #if defined(MAGICKCORE_JP2_DELEGATE)
753 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
754 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
756 (void) RegisterMagickInfo(entry);
757 entry=SetMagickInfo("JPX");
758 entry->description=ConstantString("JPEG-2000 File Format Syntax");
759 entry->module=ConstantString("JP2");
760 entry->magick=(IsImageFormatHandler *) IsJPC;
761 entry->adjoin=MagickFalse;
762 entry->seekable_stream=MagickTrue;
763 entry->thread_support=NoThreadSupport;
764 #if defined(MAGICKCORE_JP2_DELEGATE)
765 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
766 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
768 (void) RegisterMagickInfo(entry);
769 entry=SetMagickInfo("PGX");
770 entry->description=ConstantString("JPEG-2000 VM Format");
771 entry->module=ConstantString("JP2");
772 entry->magick=(IsImageFormatHandler *) IsJPC;
773 entry->adjoin=MagickFalse;
774 entry->seekable_stream=MagickTrue;
775 entry->thread_support=NoThreadSupport;
776 #if defined(MAGICKCORE_JP2_DELEGATE)
777 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
779 (void) RegisterMagickInfo(entry);
780 #if defined(MAGICKCORE_JP2_DELEGATE)
781 if (instantiate_jp2 == MagickFalse)
784 instantiate_jp2=MagickTrue;
787 return(MagickImageCoderSignature);
791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 % U n r e g i s t e r J P 2 I m a g e %
799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
801 % UnregisterJP2Image() removes format registrations made by the JP2 module
802 % from the list of supported formats.
804 % The format of the UnregisterJP2Image method is:
806 % UnregisterJP2Image(void)
809 ModuleExport void UnregisterJP2Image(void)
811 (void) UnregisterMagickInfo("PGX");
812 (void) UnregisterMagickInfo("J2K");
813 (void) UnregisterMagickInfo("J2C");
814 (void) UnregisterMagickInfo("JPC");
815 (void) UnregisterMagickInfo("JP2");
816 #if defined(MAGICKCORE_JP2_DELEGATE)
817 if (instantiate_jp2 != MagickFalse)
820 instantiate_jp2=MagickFalse;
825 #if defined(MAGICKCORE_JP2_DELEGATE)
827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
831 % W r i t e J P 2 I m a g e %
835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
837 % WriteJP2Image() writes an image in the JPEG 2000 image format.
839 % JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
841 % The format of the WriteJP2Image method is:
843 % MagickBooleanType WriteJP2Image(const ImageInfo *image_info,
844 % Image *image,ExceptionInfo *exception)
846 % A description of each parameter follows.
848 % o image_info: the image info.
850 % o image: The image.
852 % o exception: return any errors or warnings in this structure.
855 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
856 ExceptionInfo *exception)
860 magick[MaxTextExtent],
884 register const Quantum
901 assert(image_info != (const ImageInfo *) NULL);
902 assert(image_info->signature == MagickSignature);
903 assert(image != (Image *) NULL);
904 assert(image->signature == MagickSignature);
905 if (image->debug != MagickFalse)
906 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
907 assert(exception != (ExceptionInfo *) NULL);
908 assert(exception->signature == MagickSignature);
909 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
910 if (status == MagickFalse)
913 Initialize JPEG 2000 API.
915 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
916 (void) TransformImageColorspace(image,sRGBColorspace,exception);
917 jp2_stream=JP2StreamManager(image);
918 if (jp2_stream == (jas_stream_t *) NULL)
919 ThrowWriterException(DelegateError,"UnableToManageJP2Stream");
920 number_components=image->alpha_trait ? 4UL : 3UL;
921 if (IsGrayColorspace(image->colorspace) != MagickFalse)
923 if ((image->columns != (unsigned int) image->columns) ||
924 (image->rows != (unsigned int) image->rows))
925 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
926 (void) ResetMagickMemory(&component_info,0,sizeof(component_info));
927 for (i=0; i < (ssize_t) number_components; i++)
929 component_info[i].tlx=0;
930 component_info[i].tly=0;
931 component_info[i].hstep=1;
932 component_info[i].vstep=1;
933 component_info[i].width=(unsigned int) image->columns;
934 component_info[i].height=(unsigned int) image->rows;
935 component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2);
936 component_info[i].sgnd=MagickFalse;
938 jp2_image=jas_image_create((int) number_components,component_info,
940 if (jp2_image == (jas_image_t *) NULL)
941 ThrowWriterException(DelegateError,"UnableToCreateImage");
942 switch (image->colorspace)
950 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB);
951 jas_image_setcmpttype(jp2_image,0,
952 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
953 jas_image_setcmpttype(jp2_image,1,
954 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
955 jas_image_setcmpttype(jp2_image,2,
956 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
957 if (number_components == 4)
958 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
964 Grayscale colorspace.
966 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY);
967 jas_image_setcmpttype(jp2_image,0,
968 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
971 case YCbCrColorspace:
976 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SYCBCR);
977 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
978 JAS_IMAGE_CT_COLOR(0));
979 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
980 JAS_IMAGE_CT_COLOR(1));
981 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
982 JAS_IMAGE_CT_COLOR(2));
983 if (number_components == 4)
984 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
992 jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIEXYZ);
993 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
994 JAS_IMAGE_CT_COLOR(0));
995 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
996 JAS_IMAGE_CT_COLOR(1));
997 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
998 JAS_IMAGE_CT_COLOR(2));
999 if (number_components == 4)
1000 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1008 jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIELAB);
1009 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1010 JAS_IMAGE_CT_COLOR(0));
1011 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1012 JAS_IMAGE_CT_COLOR(1));
1013 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1014 JAS_IMAGE_CT_COLOR(2));
1015 if (number_components == 4)
1016 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1024 jas_image_setclrspc(jp2_image,JAS_CLRSPC_UNKNOWN);
1025 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1026 JAS_IMAGE_CT_COLOR(0));
1027 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1028 JAS_IMAGE_CT_COLOR(1));
1029 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1030 JAS_IMAGE_CT_COLOR(2));
1031 if (number_components == 4)
1032 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1037 Convert to JPEG 2000 pixels.
1039 for (i=0; i < (ssize_t) number_components; i++)
1041 pixels[i]=jas_matrix_create(1,(int) image->columns);
1042 if (pixels[i] == (jas_matrix_t *) NULL)
1044 for (x=0; x < i; x++)
1045 jas_matrix_destroy(pixels[x]);
1046 jas_image_destroy(jp2_image);
1047 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1050 range=GetQuantumRange((size_t) component_info[0].prec);
1051 for (y=0; y < (ssize_t) image->rows; y++)
1053 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1054 if (p == (const Quantum *) NULL)
1056 for (x=0; x < (ssize_t) image->columns; x++)
1058 if (number_components == 1)
1059 jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1060 GetPixelIntensity(image,p),range));
1063 jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1064 GetPixelRed(image,p),range));
1065 jas_matrix_setv(pixels[1],x,(jas_seqent_t) ScaleQuantumToAny(
1066 GetPixelGreen(image,p),range));
1067 jas_matrix_setv(pixels[2],x,(jas_seqent_t) ScaleQuantumToAny(
1068 GetPixelBlue(image,p),range));
1069 if (number_components > 3)
1070 jas_matrix_setv(pixels[3],x,(jas_seqent_t) ScaleQuantumToAny(
1071 GetPixelAlpha(image,p),range));
1073 p+=GetPixelChannels(image);
1075 for (i=0; i < (ssize_t) number_components; i++)
1076 (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y,
1077 (unsigned int) image->columns,1,pixels[i]);
1078 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1080 if (status == MagickFalse)
1083 (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1084 if (LocaleCompare(magick,"J2C") == 0)
1085 (void) CopyMagickString(magick,"JPC",MaxTextExtent);
1086 LocaleLower(magick);
1087 format=jas_image_strtofmt(magick);
1088 options=(char *) NULL;
1089 ResetImageOptionIterator(image_info);
1090 key=GetNextImageOption(image_info);
1091 for ( ; key != (char *) NULL; key=GetNextImageOption(image_info))
1093 option=GetImageOption(image_info,key);
1094 if (option == (const char *) NULL)
1096 if (LocaleNCompare(key,"jp2:",4) == 0)
1098 (void) ConcatenateString(&options,key+4);
1099 if (*option != '\0')
1101 (void) ConcatenateString(&options,"=");
1102 (void) ConcatenateString(&options,option);
1104 (void) ConcatenateString(&options," ");
1107 option=GetImageOption(image_info,"jp2:rate");
1108 if ((option == (const char *) NULL) &&
1109 (image_info->compression != LosslessJPEGCompression) &&
1110 (image->quality != UndefinedCompressionQuality) &&
1111 ((double) image->quality <= 99.5) &&
1112 ((image->rows*image->columns) > 2500))
1115 option[MaxTextExtent];
1124 alpha=115.0-image->quality;
1125 rate=100.0/(alpha*alpha);
1127 header_size+=(number_components-1)*142;
1128 number_pixels=(double) image->rows*image->columns*number_components*
1129 (GetImageQuantumDepth(image,MagickTrue)/8);
1130 target_size=(number_pixels*rate)+header_size;
1131 rate=target_size/number_pixels;
1132 (void) FormatLocaleString(option,MaxTextExtent,"rate=%g",rate);
1133 (void) ConcatenateString(&options,option);
1135 status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ?
1136 MagickTrue : MagickFalse;
1137 if (options != (char *) NULL)
1138 options=DestroyString(options);
1139 (void) jas_stream_close(jp2_stream);
1140 for (i=0; i < (ssize_t) number_components; i++)
1141 jas_matrix_destroy(pixels[i]);
1142 jas_image_destroy(jp2_image);
1143 if (status != MagickFalse)
1144 ThrowWriterException(DelegateError,"UnableToEncodeImageFile");