]> granicus.if.org Git - imagemagick/blob - coders/jp2.c
0d4878f35bc2f22a4ed25beadef102f61a73ed19
[imagemagick] / coders / jp2.c
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 %                                John Cristy                                  %
16 %                                Nathan Brown                                 %
17 %                                 June 2001                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
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
71 #endif
72 #ifndef JAS_IMAGE_CM_RGB
73 #define JAS_IMAGE_CM_RGB JAS_IMAGE_CS_RGB
74 #endif
75 #if !defined(uchar)
76 #define uchar  unsigned char
77 #endif
78 #if !defined(ushort)
79 #define ushort  unsigned short
80 #endif
81 #if !defined(uint)
82 #define uint  unsigned int
83 #endif
84 #if !defined(ssize_tssize_t)
85 #define ssize_tssize_t  long long
86 #endif
87 #if !defined(ussize_tssize_t)
88 #define ussize_tssize_t  unsigned long long
89 #endif
90
91 #undef PACKAGE_NAME
92 #undef PACKAGE_STRING
93 #undef PACKAGE_TARNAME
94 #undef PACKAGE_VERSION
95 #include "jasper/jasper.h"
96 #undef PACKAGE_NAME
97 #undef PACKAGE_STRING
98 #undef PACKAGE_TARNAME
99 #undef PACKAGE_VERSION
100
101 #endif
102 \f
103 /*
104   Forward declarations.
105 */
106 #if defined(MAGICKCORE_JP2_DELEGATE)
107 static MagickBooleanType
108   WriteJP2Image(const ImageInfo *,Image *,ExceptionInfo *);
109
110 static volatile MagickBooleanType
111   instantiate_jp2 = MagickFalse;
112 #endif
113 \f
114 /*
115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 %                                                                             %
117 %                                                                             %
118 %                                                                             %
119 %   I s J P 2                                                                 %
120 %                                                                             %
121 %                                                                             %
122 %                                                                             %
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 %
125 %  IsJP2() returns MagickTrue if the image format type, identified by the
126 %  magick string, is JP2.
127 %
128 %  The format of the IsJP2 method is:
129 %
130 %      MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
131 %
132 %  A description of each parameter follows:
133 %
134 %    o magick: compare image format pattern against these bytes.
135 %
136 %    o length: Specifies the length of the magick string.
137 %
138 */
139 static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
140 {
141   if (length < 9)
142     return(MagickFalse);
143   if (memcmp(magick+4,"\152\120\040\040\015",5) == 0)
144     return(MagickTrue);
145   return(MagickFalse);
146 }
147 \f
148 /*
149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 %                                                                             %
151 %                                                                             %
152 %                                                                             %
153 %   I s J P C                                                                 %
154 %                                                                             %
155 %                                                                             %
156 %                                                                             %
157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158 %
159 %  IsJPC()() returns MagickTrue if the image format type, identified by the
160 %  magick string, is JPC.
161 %
162 %  The format of the IsJPC method is:
163 %
164 %      MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
165 %
166 %  A description of each parameter follows:
167 %
168 %    o magick: compare image format pattern against these bytes.
169 %
170 %    o length: Specifies the length of the magick string.
171 %
172 */
173 static MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
174 {
175   if (length < 2)
176     return(MagickFalse);
177   if (memcmp(magick,"\377\117",2) == 0)
178     return(MagickTrue);
179   return(MagickFalse);
180 }
181 \f
182 /*
183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
184 %                                                                             %
185 %                                                                             %
186 %                                                                             %
187 %   R e a d J P 2 I m a g e                                                   %
188 %                                                                             %
189 %                                                                             %
190 %                                                                             %
191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 %
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.
197 %
198 %  JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
199 %
200 %  The format of the ReadJP2Image method is:
201 %
202 %      Image *ReadJP2Image(const ImageInfo *image_info,
203 %        ExceptionInfo *exception)
204 %
205 %  A description of each parameter follows:
206 %
207 %    o image_info: the image info.
208 %
209 %    o exception: return any errors or warnings in this structure.
210 %
211 */
212 #if defined(MAGICKCORE_JP2_DELEGATE)
213
214 typedef struct _StreamManager
215 {
216   jas_stream_t
217     *stream;
218
219   Image
220     *image;
221 } StreamManager;
222
223 static int BlobRead(jas_stream_obj_t *object,char *buffer,const int length)
224 {
225   ssize_t
226     count;
227
228   StreamManager
229     *source;
230
231   source=(StreamManager *) object;
232   count=ReadBlob(source->image,(size_t) length,(unsigned char *) buffer);
233   return((int) count);
234 }
235
236 static int BlobWrite(jas_stream_obj_t *object,char *buffer,const int length)
237 {
238   ssize_t
239     count;
240
241   StreamManager
242     *source;
243
244   source=(StreamManager *) object;
245   count=WriteBlob(source->image,(size_t) length,(unsigned char *) buffer);
246   return((int) count);
247 }
248
249 static long BlobSeek(jas_stream_obj_t *object,long offset,int origin)
250 {
251   StreamManager
252     *source;
253
254   source=(StreamManager *) object;
255   return((long) SeekBlob(source->image,offset,origin));
256 }
257
258 static int BlobClose(jas_stream_obj_t *object)
259 {
260   StreamManager
261     *source;
262
263   source=(StreamManager *) object;
264   (void) CloseBlob(source->image);
265   free(source);
266   source=(StreamManager *) NULL;
267   return(0);
268 }
269
270 static inline size_t MagickMax(const size_t x,const size_t y)
271 {
272   if (x > y)
273     return(x);
274   return(y);
275 }
276
277 static inline size_t MagickMin(const size_t x,const size_t y)
278 {
279   if (x < y)
280     return(x);
281   return(y);
282 }
283
284 static jas_stream_t *JP2StreamManager(Image *image)
285 {
286   static jas_stream_ops_t
287     StreamOperators =
288     {
289       BlobRead,
290       BlobWrite,
291       BlobSeek,
292       BlobClose
293     };
294
295   jas_stream_t
296     *stream;
297
298   StreamManager
299     *source;
300
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)
315     {
316       stream->bufbase_=stream->tinybuf_;
317       stream->bufsize_=1;
318     }
319   else
320     {
321       stream->bufmode_=JAS_STREAM_FREEBUF | JAS_STREAM_BUFMODEMASK;
322       stream->bufsize_=JAS_STREAM_BUFSIZE;
323     }
324   stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
325   stream->ptr_=stream->bufstart_;
326   stream->cnt_=0;
327   source=(StreamManager *) stream->obj_;
328   source->image=image;
329   return(stream);
330 }
331
332 static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
333 {
334   Image
335     *image;
336
337   jas_cmprof_t
338     *cm_profile;
339
340   jas_iccprof_t
341     *icc_profile;
342
343   jas_image_t
344     *jp2_image;
345
346   jas_matrix_t
347     *pixels[4];
348
349   jas_stream_t
350     *jp2_stream;
351
352   MagickBooleanType
353     status;
354
355   QuantumAny
356     pixel,
357     range[4];
358
359   register Quantum
360     *q;
361
362   register ssize_t
363     i,
364     x;
365
366   size_t
367     maximum_component_depth,
368     number_components,
369     x_step[4],
370     y_step[4];
371
372   ssize_t
373     components[4],
374     y;
375
376   /*
377     Open image file.
378   */
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)
389     {
390       image=DestroyImageList(image);
391       return((Image *) NULL);
392     }
393   /*
394     Initialize JPEG 2000 API.
395   */
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)
401     {
402       (void) jas_stream_close(jp2_stream);
403       ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
404     }
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)))
409   {
410     case JAS_CLRSPC_FAM_RGB:
411     {
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))
417         {
418           (void) jas_stream_close(jp2_stream);
419           jas_image_destroy(jp2_image);
420           ThrowReaderException(CorruptImageError,"MissingImageChannel");
421         }
422       number_components=3;
423       components[3]=jas_image_getcmptbytype(jp2_image,3);
424       if (components[3] > 0)
425         {
426           image->alpha_trait=BlendPixelTrait;
427           number_components++;
428         }
429       break;
430     }
431     case JAS_CLRSPC_FAM_GRAY:
432     {
433       SetImageColorspace(image,GRAYColorspace,exception);
434       components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_GRAY_Y);
435       if (components[0] < 0)
436         {
437           (void) jas_stream_close(jp2_stream);
438           jas_image_destroy(jp2_image);
439           ThrowReaderException(CorruptImageError,"MissingImageChannel");
440         }
441       number_components=1;
442       break;
443     }
444     case JAS_CLRSPC_FAM_YCBCR:
445     {
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))
451         {
452           (void) jas_stream_close(jp2_stream);
453           jas_image_destroy(jp2_image);
454           ThrowReaderException(CorruptImageError,"MissingImageChannel");
455         }
456       number_components=3;
457       components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
458       if (components[3] > 0)
459         {
460           image->alpha_trait=BlendPixelTrait;
461           number_components++;
462         }
463       break;
464     }
465     case JAS_CLRSPC_FAM_XYZ:
466     {
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))
472         {
473           (void) jas_stream_close(jp2_stream);
474           jas_image_destroy(jp2_image);
475           ThrowReaderException(CorruptImageError,"MissingImageChannel");
476         }
477       number_components=3;
478       components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
479       if (components[3] > 0)
480         {
481           image->alpha_trait=BlendPixelTrait;
482           number_components++;
483         }
484       break;
485     }
486     case JAS_CLRSPC_FAM_LAB:
487     {
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))
493         {
494           (void) jas_stream_close(jp2_stream);
495           jas_image_destroy(jp2_image);
496           ThrowReaderException(CorruptImageError,"MissingImageChannel");
497         }
498       number_components=3;
499       components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
500       if (components[3] > 0)
501         {
502           image->alpha_trait=BlendPixelTrait;
503           number_components++;
504         }
505       break;
506     }
507     default:
508     {
509       (void) jas_stream_close(jp2_stream);
510       jas_image_destroy(jp2_image);
511       ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
512     }
513   }
514   for (i=0; i < (ssize_t) number_components; i++)
515   {
516     size_t
517       height,
518       width;
519
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))
530       {
531         (void) jas_stream_close(jp2_stream);
532         jas_image_destroy(jp2_image);
533         ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported");
534       }
535   }
536   /*
537     Convert JPEG 2000 pixels.
538   */
539   image->alpha_trait=number_components > 3 ? BlendPixelTrait :
540     UndefinedPixelTrait;
541   maximum_component_depth=0;
542   for (i=0; i < (ssize_t) number_components; i++)
543   {
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)
549       {
550         for (--i; i >= 0; i--)
551           jas_matrix_destroy(pixels[i]);
552         jas_image_destroy(jp2_image);
553         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
554       }
555   }
556   image->depth=maximum_component_depth;
557   if (image_info->ping != MagickFalse)
558     {
559       (void) jas_stream_close(jp2_stream);
560       jas_image_destroy(jp2_image);
561       return(GetFirstImageInList(image));
562     }
563   for (i=0; i < (ssize_t) number_components; i++)
564     range[i]=GetQuantumRange((size_t) jas_image_cmptprec(jp2_image,
565       components[i]));
566   for (y=0; y < (ssize_t) image->rows; y++)
567   {
568     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
569     if (q == (Quantum *) NULL)
570       break;
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)
576     {
577       case 1:
578       {
579         /*
580           Grayscale.
581         */
582         for (x=0; x < (ssize_t) image->columns; x++)
583         {
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);
587         }
588         break;
589       }
590       case 3:
591       {
592         /*
593           RGB.
594         */
595         for (x=0; x < (ssize_t) image->columns; x++)
596         {
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);
604         }
605         break;
606       }
607       case 4:
608       {
609         /*
610           RGBA.
611         */
612         for (x=0; x < (ssize_t) image->columns; x++)
613         {
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);
623         }
624         break;
625       }
626     }
627     if (SyncAuthenticPixels(image,exception) == MagickFalse)
628       break;
629     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
630       image->rows);
631     if (status == MagickFalse)
632       break;
633   }
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)
639     {
640       jas_stream_t
641         *icc_stream;
642
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))
647         {
648           jas_stream_memobj_t
649             *blob;
650
651           StringInfo
652             *icc_profile,
653             *profile;
654
655           /*
656             Extract the icc profile, handle errors without much noise.
657           */
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);
668           else
669             (void) ConcatenateStringInfo(icc_profile,profile);
670           profile=DestroyStringInfo(profile);
671           (void) jas_stream_close(icc_stream);
672         }
673     }
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));
679 }
680 #endif
681 \f
682 /*
683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
684 %                                                                             %
685 %                                                                             %
686 %                                                                             %
687 %   R e g i s t e r J P 2 I m a g e                                           %
688 %                                                                             %
689 %                                                                             %
690 %                                                                             %
691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692 %
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.
698 %
699 %  The format of the RegisterJP2Image method is:
700 %
701 %      size_t RegisterJP2Image(void)
702 %
703 */
704 ModuleExport size_t RegisterJP2Image(void)
705 {
706   MagickInfo
707     *entry;
708
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;
719 #endif
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;
731 #endif
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;
743 #endif
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;
755 #endif
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;
767 #endif
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;
778 #endif
779   (void) RegisterMagickInfo(entry);
780 #if defined(MAGICKCORE_JP2_DELEGATE)
781   if (instantiate_jp2 == MagickFalse)
782     {
783       jas_init();
784       instantiate_jp2=MagickTrue;
785     }
786 #endif
787   return(MagickImageCoderSignature);
788 }
789 \f
790 /*
791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792 %                                                                             %
793 %                                                                             %
794 %                                                                             %
795 %   U n r e g i s t e r J P 2 I m a g e                                       %
796 %                                                                             %
797 %                                                                             %
798 %                                                                             %
799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
800 %
801 %  UnregisterJP2Image() removes format registrations made by the JP2 module
802 %  from the list of supported formats.
803 %
804 %  The format of the UnregisterJP2Image method is:
805 %
806 %      UnregisterJP2Image(void)
807 %
808 */
809 ModuleExport void UnregisterJP2Image(void)
810 {
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)
818     {
819       jas_cleanup();
820       instantiate_jp2=MagickFalse;
821     }
822 #endif
823 }
824 \f
825 #if defined(MAGICKCORE_JP2_DELEGATE)
826 /*
827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
828 %                                                                             %
829 %                                                                             %
830 %                                                                             %
831 %   W r i t e J P 2 I m a g e                                                 %
832 %                                                                             %
833 %                                                                             %
834 %                                                                             %
835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
836 %
837 %  WriteJP2Image() writes an image in the JPEG 2000 image format.
838 %
839 %  JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
840 %
841 %  The format of the WriteJP2Image method is:
842 %
843 %      MagickBooleanType WriteJP2Image(const ImageInfo *image_info,
844 %        Image *image,ExceptionInfo *exception)
845 %
846 %  A description of each parameter follows.
847 %
848 %    o image_info: the image info.
849 %
850 %    o image:  The image.
851 %
852 %    o exception: return any errors or warnings in this structure.
853 %
854 */
855 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
856   ExceptionInfo *exception)
857 {
858   char
859     *key,
860     magick[MaxTextExtent],
861     *options;
862
863   const char
864     *option;
865
866   jas_image_cmptparm_t
867     component_info[4];
868
869   jas_image_t
870     *jp2_image;
871
872   jas_matrix_t
873     *pixels[4];
874
875   jas_stream_t
876     *jp2_stream;
877
878   MagickBooleanType
879     status;
880
881   QuantumAny
882     range;
883
884   register const Quantum
885     *p;
886
887   register ssize_t
888     i,
889     x;
890
891   size_t
892     number_components;
893
894   ssize_t
895     format,
896     y;
897
898   /*
899     Open image file.
900   */
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)
911     return(status);
912   /*
913     Initialize JPEG 2000 API.
914   */
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)
922     number_components=1;
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++)
928   {
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;
937   }
938   jp2_image=jas_image_create((int) number_components,component_info,
939     JAS_CLRSPC_UNKNOWN);
940   if (jp2_image == (jas_image_t *) NULL)
941     ThrowWriterException(DelegateError,"UnableToCreateImage");
942   switch (image->colorspace)
943   {
944     case RGBColorspace:
945     case sRGBColorspace:
946     {
947       /*
948         RGB colorspace.
949       */
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);
959       break;
960     }
961     case GRAYColorspace:
962     {
963       /*
964         Grayscale colorspace.
965       */
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));
969       break;
970     }
971     case YCbCrColorspace:
972     {
973       /*
974         YCbCr colorspace.
975       */
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);
985       break;
986     }
987     case XYZColorspace:
988     {
989       /*
990         XYZ colorspace.
991       */
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);
1001       break;
1002     }
1003     case LabColorspace:
1004     {
1005       /*
1006         Lab colorspace.
1007       */
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);
1017       break;
1018     }
1019     default:
1020     {
1021       /*
1022         Unknow.
1023       */
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);
1033       break;
1034     }
1035   }
1036   /*
1037     Convert to JPEG 2000 pixels.
1038   */
1039   for (i=0; i < (ssize_t) number_components; i++)
1040   {
1041     pixels[i]=jas_matrix_create(1,(int) image->columns);
1042     if (pixels[i] == (jas_matrix_t *) NULL)
1043       {
1044         for (x=0; x < i; x++)
1045           jas_matrix_destroy(pixels[x]);
1046         jas_image_destroy(jp2_image);
1047         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1048       }
1049   }
1050   range=GetQuantumRange((size_t) component_info[0].prec);
1051   for (y=0; y < (ssize_t) image->rows; y++)
1052   {
1053     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1054     if (p == (const Quantum *) NULL)
1055       break;
1056     for (x=0; x < (ssize_t) image->columns; x++)
1057     {
1058       if (number_components == 1)
1059         jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1060           GetPixelIntensity(image,p),range));
1061       else
1062         {
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));
1072         }
1073       p+=GetPixelChannels(image);
1074     }
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,
1079       image->rows);
1080     if (status == MagickFalse)
1081       break;
1082   }
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))
1092   {
1093     option=GetImageOption(image_info,key);
1094     if (option == (const char *) NULL)
1095       continue;
1096     if (LocaleNCompare(key,"jp2:",4) == 0)
1097       {
1098         (void) ConcatenateString(&options,key+4);
1099         if (*option != '\0')
1100           {
1101             (void) ConcatenateString(&options,"=");
1102             (void) ConcatenateString(&options,option);
1103           }
1104         (void) ConcatenateString(&options," ");
1105       }
1106   }
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))
1113     {
1114       char
1115         option[MaxTextExtent];
1116
1117       double
1118         alpha,
1119         header_size,
1120         number_pixels,
1121         rate,
1122         target_size;
1123
1124       alpha=115.0-image->quality;
1125       rate=100.0/(alpha*alpha);
1126       header_size=550.0;
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);
1134     }
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");
1145   return(MagickTrue);
1146 }
1147 #endif