2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write JPEG-2000 Image Format %
20 % Copyright 1999-2010 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 "magick/studio.h"
43 #include "magick/attribute.h"
44 #include "magick/blob.h"
45 #include "magick/blob-private.h"
46 #include "magick/cache.h"
47 #include "magick/colorspace.h"
48 #include "magick/color.h"
49 #include "magick/color-private.h"
50 #include "magick/exception.h"
51 #include "magick/exception-private.h"
52 #include "magick/image.h"
53 #include "magick/image-private.h"
54 #include "magick/list.h"
55 #include "magick/magick.h"
56 #include "magick/memory_.h"
57 #include "magick/monitor.h"
58 #include "magick/monitor-private.h"
59 #include "magick/option.h"
60 #include "magick/profile.h"
61 #include "magick/quantum-private.h"
62 #include "magick/static.h"
63 #include "magick/statistic.h"
64 #include "magick/string_.h"
65 #include "magick/module.h"
66 #if defined(MAGICKCORE_JP2_DELEGATE)
67 #ifndef JAS_IMAGE_CM_GRAY
68 #define JAS_IMAGE_CM_GRAY JAS_IMAGE_CS_GRAY
70 #ifndef JAS_IMAGE_CM_RGB
71 #define JAS_IMAGE_CM_RGB JAS_IMAGE_CS_RGB
74 #define uchar unsigned char
77 #define ushort unsigned short
80 #define uint unsigned int
82 #if !defined(longlong)
83 #define longlong long long
85 #if !defined(ulonglong)
86 #define ulonglong unsigned long long
90 #define JAS_VERSION 1.700.0
91 #define PACKAGE jasper
92 #define VERSION 1.700.0
96 #undef PACKAGE_TARNAME
97 #undef PACKAGE_VERSION
98 #include "jasper/jasper.h"
100 #undef PACKAGE_STRING
101 #undef PACKAGE_TARNAME
102 #undef PACKAGE_VERSION
107 Forward declarations.
109 #if defined(MAGICKCORE_JP2_DELEGATE)
110 static MagickBooleanType
111 WriteJP2Image(const ImageInfo *,Image *);
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);
265 source=(StreamManager *) RelinquishMagickMemory(source);
269 static inline size_t MagickMax(const size_t x,const size_t y)
276 static inline size_t MagickMin(const size_t x,const size_t y)
283 static jas_stream_t *JP2StreamManager(Image *image)
285 static jas_stream_ops_t
300 stream=(jas_stream_t *) jas_malloc(sizeof(*stream));
301 if (stream == (jas_stream_t *) NULL)
302 return((jas_stream_t *) NULL);
303 (void) ResetMagickMemory(stream,0,sizeof(*stream));
304 stream->rwlimit_=(-1);
305 stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
306 if (stream->obj_ == (jas_stream_obj_t *) NULL)
307 return((jas_stream_t *) NULL);
308 (void) ResetMagickMemory(stream->obj_,0,sizeof(StreamManager));
309 stream->ops_=(&StreamOperators);
310 stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
311 stream->bufbase_=(unsigned char *) jas_malloc(JAS_STREAM_BUFSIZE+
312 JAS_STREAM_MAXPUTBACK);
313 if (stream->bufbase_ == (void *) NULL)
315 stream->bufbase_=stream->tinybuf_;
320 stream->bufmode_=JAS_STREAM_FREEBUF | JAS_STREAM_BUFMODEMASK;
321 stream->bufsize_=JAS_STREAM_BUFSIZE;
323 stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
324 stream->ptr_=stream->bufstart_;
326 source=(StreamManager *) stream->obj_;
331 static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
370 maximum_component_depth,
378 assert(image_info != (const ImageInfo *) NULL);
379 assert(image_info->signature == MagickSignature);
380 if (image_info->debug != MagickFalse)
381 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
382 image_info->filename);
383 assert(exception != (ExceptionInfo *) NULL);
384 assert(exception->signature == MagickSignature);
385 image=AcquireImage(image_info);
386 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
387 if (status == MagickFalse)
389 image=DestroyImageList(image);
390 return((Image *) NULL);
393 Initialize JPEG 2000 API.
395 jp2_stream=JP2StreamManager(image);
396 if (jp2_stream == (jas_stream_t *) NULL)
397 ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
398 jp2_image=jas_image_decode(jp2_stream,-1,0);
399 if (jp2_image == (jas_image_t *) NULL)
401 (void) jas_stream_close(jp2_stream);
402 ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
404 switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
406 case JAS_CLRSPC_FAM_RGB:
408 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_R);
409 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_G);
410 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_B);
411 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
413 (void) jas_stream_close(jp2_stream);
414 jas_image_destroy(jp2_image);
415 ThrowReaderException(CorruptImageError,"MissingImageChannel");
418 components[3]=jas_image_getcmptbytype(jp2_image,3);
419 if (components[3] > 0)
421 image->matte=MagickTrue;
426 case JAS_CLRSPC_FAM_GRAY:
428 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_GRAY_Y);
429 if (components[0] < 0)
431 (void) jas_stream_close(jp2_stream);
432 jas_image_destroy(jp2_image);
433 ThrowReaderException(CorruptImageError,"MissingImageChannel");
438 case JAS_CLRSPC_FAM_YCBCR:
440 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
441 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
442 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
443 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
445 (void) jas_stream_close(jp2_stream);
446 jas_image_destroy(jp2_image);
447 ThrowReaderException(CorruptImageError,"MissingImageChannel");
450 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
451 if (components[3] > 0)
453 image->matte=MagickTrue;
456 image->colorspace=YCbCrColorspace;
461 (void) jas_stream_close(jp2_stream);
462 jas_image_destroy(jp2_image);
463 ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
466 image->columns=jas_image_width(jp2_image);
467 image->rows=jas_image_height(jp2_image);
468 image->compression=JPEG2000Compression;
469 for (i=0; i < (long) number_components; i++)
475 width=(unsigned long) (jas_image_cmptwidth(jp2_image,components[i])*
476 jas_image_cmpthstep(jp2_image,components[i]));
477 height=(unsigned long) (jas_image_cmptheight(jp2_image,components[i])*
478 jas_image_cmptvstep(jp2_image,components[i]));
479 x_step[i]=(unsigned int) jas_image_cmpthstep(jp2_image,components[i]);
480 y_step[i]=(unsigned int) jas_image_cmptvstep(jp2_image,components[i]);
481 if ((width != image->columns) || (height != image->rows) ||
482 (jas_image_cmpttlx(jp2_image,components[i]) != 0) ||
483 (jas_image_cmpttly(jp2_image,components[i]) != 0) ||
484 (x_step[i] != 1) || (y_step[i] != 1) ||
485 (jas_image_cmptsgnd(jp2_image,components[i]) != MagickFalse))
487 (void) jas_stream_close(jp2_stream);
488 jas_image_destroy(jp2_image);
489 ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported");
493 Convert JPEG 2000 pixels.
495 image->matte=number_components > 3 ? MagickTrue : MagickFalse;
496 maximum_component_depth=0;
497 for (i=0; i < (long) number_components; i++)
499 maximum_component_depth=(unsigned int) MagickMax((size_t)
500 jas_image_cmptprec(jp2_image,components[i]),(size_t)
501 maximum_component_depth);
502 pixels[i]=jas_matrix_create(1,(int) (image->columns/x_step[i]));
503 if (pixels[i] == (jas_matrix_t *) NULL)
505 for (--i; i >= 0; i--)
506 jas_matrix_destroy(pixels[i]);
507 jas_image_destroy(jp2_image);
508 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
511 image->depth=maximum_component_depth;
512 if (image_info->ping != MagickFalse)
514 (void) jas_stream_close(jp2_stream);
515 jas_image_destroy(jp2_image);
516 return(GetFirstImageInList(image));
518 for (i=0; i < (long) number_components; i++)
519 range[i]=GetQuantumRange((unsigned long) jas_image_cmptprec(jp2_image,
521 for (y=0; y < (long) image->rows; y++)
523 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
524 if (q == (PixelPacket *) NULL)
526 for (i=0; i < (long) number_components; i++)
527 (void) jas_image_readcmpt(jp2_image,(short) components[i],0,
528 ((unsigned int) y)/y_step[i],((unsigned int) image->columns)/x_step[i],
530 switch (number_components)
537 for (x=0; x < (long) image->columns; x++)
539 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
540 q->red=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[0]);
552 for (x=0; x < (long) image->columns; x++)
554 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
555 q->red=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[0]);
556 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
557 q->green=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[1]);
558 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
559 q->blue=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[2]);
569 for (x=0; x < (long) image->columns; x++)
571 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
572 q->red=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[0]);
573 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
574 q->green=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[1]);
575 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
576 q->blue=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[2]);
577 pixel=(QuantumAny) jas_matrix_getv(pixels[3],x/x_step[3]);
578 q->opacity=(Quantum) (QuantumRange-
579 ScaleAnyToQuantum((QuantumAny) pixel,range[3]));
585 if (SyncAuthenticPixels(image,exception) == MagickFalse)
587 status=SetImageProgress(image,LoadImageTag,y,image->rows);
588 if (status == MagickFalse)
591 cm_profile=jas_image_cmprof(jp2_image);
592 icc_profile=(jas_iccprof_t *) NULL;
593 if (cm_profile != (jas_cmprof_t *) NULL)
594 icc_profile=jas_iccprof_createfromcmprof(cm_profile);
595 if (icc_profile != (jas_iccprof_t *) NULL)
600 icc_stream=jas_stream_memopen(NULL,0);
601 if ((icc_stream != (jas_stream_t *) NULL) &&
602 (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
603 (jas_stream_flush(icc_stream) == 0))
613 Extract the icc profile, handle errors without much noise.
615 blob=(jas_stream_memobj_t *) icc_stream->obj_;
616 if (image->debug != MagickFalse)
617 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
618 "Profile: ICC, %lu bytes",(unsigned long) blob->len_);
619 profile=AcquireStringInfo(blob->len_);
620 SetStringInfoDatum(profile,blob->buf_);
621 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
622 if (icc_profile == (StringInfo *) NULL)
623 (void) SetImageProfile(image,"icc",profile);
625 (void) ConcatenateStringInfo(icc_profile,profile);
626 profile=DestroyStringInfo(profile);
627 (void) jas_stream_close(icc_stream);
630 (void) jas_stream_close(jp2_stream);
631 jas_image_destroy(jp2_image);
632 for (i=0; i < (long) number_components; i++)
633 jas_matrix_destroy(pixels[i]);
634 return(GetFirstImageInList(image));
639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
643 % R e g i s t e r J P 2 I m a g e %
647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649 % RegisterJP2Image() adds attributes for the JP2 image format to the list of
650 % supported formats. The attributes include the image format tag, a method
651 % method to read and/or write the format, whether the format supports the
652 % saving of more than one frame to the same file or blob, whether the format
653 % supports native in-memory I/O, and a brief description of the format.
655 % The format of the RegisterJP2Image method is:
657 % unsigned long RegisterJP2Image(void)
660 ModuleExport unsigned long RegisterJP2Image(void)
665 entry=SetMagickInfo("JP2");
666 entry->description=ConstantString("JPEG-2000 File Format Syntax");
667 entry->module=ConstantString("JP2");
668 entry->magick=(IsImageFormatHandler *) IsJP2;
669 entry->adjoin=MagickFalse;
670 entry->seekable_stream=MagickTrue;
671 entry->thread_support=NoThreadSupport;
672 #if defined(MAGICKCORE_JP2_DELEGATE)
673 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
674 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
676 (void) RegisterMagickInfo(entry);
677 entry=SetMagickInfo("JPC");
678 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
679 entry->module=ConstantString("JP2");
680 entry->magick=(IsImageFormatHandler *) IsJPC;
681 entry->adjoin=MagickFalse;
682 entry->seekable_stream=MagickTrue;
683 entry->thread_support=NoThreadSupport;
684 #if defined(MAGICKCORE_JP2_DELEGATE)
685 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
686 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
688 (void) RegisterMagickInfo(entry);
689 entry=SetMagickInfo("J2C");
690 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
691 entry->module=ConstantString("JP2");
692 entry->magick=(IsImageFormatHandler *) IsJPC;
693 entry->adjoin=MagickFalse;
694 entry->seekable_stream=MagickTrue;
695 entry->thread_support=NoThreadSupport;
696 #if defined(MAGICKCORE_JP2_DELEGATE)
697 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
698 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
700 (void) RegisterMagickInfo(entry);
701 entry=SetMagickInfo("JPX");
702 entry->description=ConstantString("JPEG-2000 File Format Syntax");
703 entry->module=ConstantString("JP2");
704 entry->magick=(IsImageFormatHandler *) IsJPC;
705 entry->adjoin=MagickFalse;
706 entry->seekable_stream=MagickTrue;
707 entry->thread_support=NoThreadSupport;
708 #if defined(MAGICKCORE_JP2_DELEGATE)
709 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
710 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
712 (void) RegisterMagickInfo(entry);
713 entry=SetMagickInfo("PGX");
714 entry->description=ConstantString("JPEG-2000 VM Format");
715 entry->module=ConstantString("JP2");
716 entry->magick=(IsImageFormatHandler *) IsJPC;
717 entry->adjoin=MagickFalse;
718 entry->seekable_stream=MagickTrue;
719 entry->thread_support=NoThreadSupport;
720 #if defined(MAGICKCORE_JP2_DELEGATE)
721 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
723 (void) RegisterMagickInfo(entry);
724 #if defined(MAGICKCORE_JP2_DELEGATE)
727 return(MagickImageCoderSignature);
731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735 % U n r e g i s t e r J P 2 I m a g e %
739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
741 % UnregisterJP2Image() removes format registrations made by the JP2 module
742 % from the list of supported formats.
744 % The format of the UnregisterJP2Image method is:
746 % UnregisterJP2Image(void)
749 ModuleExport void UnregisterJP2Image(void)
751 (void) UnregisterMagickInfo("PGX");
752 (void) UnregisterMagickInfo("J2C");
753 (void) UnregisterMagickInfo("JPC");
754 (void) UnregisterMagickInfo("JP2");
755 #if defined(MAGICKCORE_JP2_DELEGATE)
760 #if defined(MAGICKCORE_JP2_DELEGATE)
762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 % W r i t e J P 2 I m a g e %
770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772 % WriteJP2Image() writes an image in the JPEG 2000 image format.
774 % JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
776 % The format of the WriteJP2Image method is:
778 % MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
780 % A description of each parameter follows.
782 % o image_info: the image info.
784 % o image: The image.
787 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
791 magick[MaxTextExtent],
819 register const PixelPacket
832 assert(image_info != (const ImageInfo *) NULL);
833 assert(image_info->signature == MagickSignature);
834 assert(image != (Image *) NULL);
835 assert(image->signature == MagickSignature);
836 if (image->debug != MagickFalse)
837 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
838 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
839 if (status == MagickFalse)
842 Intialize JPEG 2000 API.
844 if (image->colorspace != RGBColorspace)
845 (void) TransformImageColorspace(image,RGBColorspace);
846 jp2_stream=JP2StreamManager(image);
847 if (jp2_stream == (jas_stream_t *) NULL)
848 ThrowWriterException(DelegateError,"UnableToManageJP2Stream");
849 number_components=image->matte ? 4UL : 3UL;
850 if ((image_info->type != TrueColorType) &&
851 IsGrayImage(image,&image->exception))
853 if ((image->columns != (unsigned int) image->columns) ||
854 (image->rows != (unsigned int) image->rows))
855 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
856 (void) ResetMagickMemory(&component_info,0,sizeof(component_info));
857 for (i=0; i < (long) number_components; i++)
859 component_info[i].tlx=0;
860 component_info[i].tly=0;
861 component_info[i].hstep=1;
862 component_info[i].vstep=1;
863 component_info[i].width=(unsigned int) image->columns;
864 component_info[i].height=(unsigned int) image->rows;
865 component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2);
866 component_info[i].sgnd=MagickFalse;
868 jp2_image=jas_image_create((int) number_components,component_info,
870 if (jp2_image == (jas_image_t *) NULL)
871 ThrowWriterException(DelegateError,"UnableToCreateImage");
872 if (number_components == 1)
877 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY);
878 jas_image_setcmpttype(jp2_image,0,
879 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
886 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB);
887 jas_image_setcmpttype(jp2_image,0,
888 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
889 jas_image_setcmpttype(jp2_image,1,
890 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
891 jas_image_setcmpttype(jp2_image,2,
892 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
893 if (number_components == 4)
894 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
897 Convert to JPEG 2000 pixels.
899 for (i=0; i < (long) number_components; i++)
901 pixels[i]=jas_matrix_create(1,(int) image->columns);
902 if (pixels[i] == (jas_matrix_t *) NULL)
904 for (x=0; x < i; x++)
905 jas_matrix_destroy(pixels[x]);
906 jas_image_destroy(jp2_image);
907 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
910 range=GetQuantumRange((unsigned long) component_info[0].prec);
911 for (y=0; y < (long) image->rows; y++)
913 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
914 if (p == (const PixelPacket *) NULL)
916 for (x=0; x < (long) image->columns; x++)
918 if (number_components == 1)
919 jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
920 PixelIntensityToQuantum(p),range));
923 jas_matrix_setv(pixels[0],x,(jas_seqent_t)
924 ScaleQuantumToAny(p->red,range));
925 jas_matrix_setv(pixels[1],x,(jas_seqent_t)
926 ScaleQuantumToAny(p->green,range));
927 jas_matrix_setv(pixels[2],x,(jas_seqent_t)
928 ScaleQuantumToAny(p->blue,range));
929 if (number_components > 3)
930 jas_matrix_setv(pixels[3],x,(jas_seqent_t)
931 ScaleQuantumToAny((Quantum) (QuantumRange-p->opacity),range));
935 for (i=0; i < (long) number_components; i++)
936 (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y,
937 (unsigned int) image->columns,1,pixels[i]);
938 status=SetImageProgress(image,SaveImageTag,y,image->rows);
939 if (status == MagickFalse)
942 (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
943 if (LocaleCompare(magick,"J2C") == 0)
944 (void) CopyMagickString(magick,"JPC",MaxTextExtent);
946 format=jas_image_strtofmt(magick);
947 options=(char *) NULL;
948 ResetImageOptionIterator(image_info);
949 key=GetNextImageOption(image_info);
950 for ( ; key != (char *) NULL; key=GetNextImageOption(image_info))
952 option=GetImageOption(image_info,key);
953 if (option == (const char *) NULL)
955 if (LocaleNCompare(key,"jp2:",4) == 0)
957 (void) ConcatenateString(&options,key+4);
960 (void) ConcatenateString(&options,"=");
961 (void) ConcatenateString(&options,option);
963 (void) ConcatenateString(&options," ");
966 option=GetImageOption(image_info,"jp2:rate");
967 if ((option == (const char *) NULL) &&
968 (image_info->compression != LosslessJPEGCompression) &&
969 (image->quality != UndefinedCompressionQuality) &&
970 ((double) image->quality <= 99.5) &&
971 ((image->rows*image->columns) > 2500))
974 option[MaxTextExtent];
983 alpha=115.0-image->quality;
984 rate=100.0/(alpha*alpha);
986 header_size+=(number_components-1)*142;
987 number_pixels=(double) image->rows*image->columns*number_components*
988 (GetImageQuantumDepth(image,MagickTrue)/8);
989 target_size=(number_pixels*rate)+header_size;
990 rate=target_size/number_pixels;
991 (void) FormatMagickString(option,MaxTextExtent,"rate=%g",rate);
992 (void) ConcatenateString(&options,option);
994 status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ?
995 MagickTrue : MagickFalse;
996 (void) jas_stream_close(jp2_stream);
997 for (i=0; i < (long) number_components; i++)
998 jas_matrix_destroy(pixels[i]);
999 jas_image_destroy(jp2_image);
1000 if (status != MagickFalse)
1001 ThrowWriterException(DelegateError,"UnableToEncodeImageFile");