]> granicus.if.org Git - imagemagick/blob - coders/jp2.c
(no commit message)
[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-2014 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/artifact.h"
44 #include "MagickCore/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/colorspace.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel-accessor.h"
63 #include "MagickCore/profile.h"
64 #include "MagickCore/quantum-private.h"
65 #include "MagickCore/static.h"
66 #include "MagickCore/statistic.h"
67 #include "MagickCore/string_.h"
68 #include "MagickCore/module.h"
69 #if defined(MAGICKCORE_JP2_DELEGATE)
70 #ifndef JAS_IMAGE_CM_GRAY
71 #define JAS_IMAGE_CM_GRAY JAS_IMAGE_CS_GRAY
72 #endif
73 #ifndef JAS_IMAGE_CM_RGB
74 #define JAS_IMAGE_CM_RGB JAS_IMAGE_CS_RGB
75 #endif
76 #if !defined(uchar)
77 #define uchar  unsigned char
78 #endif
79 #if !defined(ushort)
80 #define ushort  unsigned short
81 #endif
82 #if !defined(uint)
83 #define uint  unsigned int
84 #endif
85 #if !defined(ssize_tssize_t)
86 #define ssize_tssize_t  long long
87 #endif
88 #if !defined(ussize_tssize_t)
89 #define ussize_tssize_t  unsigned long long
90 #endif
91
92 #undef PACKAGE_NAME
93 #undef PACKAGE_STRING
94 #undef PACKAGE_TARNAME
95 #undef PACKAGE_VERSION
96 #include "jasper/jasper.h"
97 #undef PACKAGE_NAME
98 #undef PACKAGE_STRING
99 #undef PACKAGE_TARNAME
100 #undef PACKAGE_VERSION
101
102 #endif
103 \f
104 /*
105   Forward declarations.
106 */
107 #if defined(MAGICKCORE_JP2_DELEGATE)
108 static MagickBooleanType
109   WriteJP2Image(const ImageInfo *,Image *,ExceptionInfo *);
110
111 static volatile MagickBooleanType
112   instantiate_jp2 = MagickFalse;
113 #endif
114 \f
115 /*
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117 %                                                                             %
118 %                                                                             %
119 %                                                                             %
120 %   I s J P 2                                                                 %
121 %                                                                             %
122 %                                                                             %
123 %                                                                             %
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 %
126 %  IsJP2() returns MagickTrue if the image format type, identified by the
127 %  magick string, is JP2.
128 %
129 %  The format of the IsJP2 method is:
130 %
131 %      MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
132 %
133 %  A description of each parameter follows:
134 %
135 %    o magick: compare image format pattern against these bytes.
136 %
137 %    o length: Specifies the length of the magick string.
138 %
139 */
140 static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
141 {
142   if (length < 9)
143     return(MagickFalse);
144   if (memcmp(magick+4,"\152\120\040\040\015",5) == 0)
145     return(MagickTrue);
146   return(MagickFalse);
147 }
148 \f
149 /*
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151 %                                                                             %
152 %                                                                             %
153 %                                                                             %
154 %   I s J P C                                                                 %
155 %                                                                             %
156 %                                                                             %
157 %                                                                             %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 %
160 %  IsJPC()() returns MagickTrue if the image format type, identified by the
161 %  magick string, is JPC.
162 %
163 %  The format of the IsJPC method is:
164 %
165 %      MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
166 %
167 %  A description of each parameter follows:
168 %
169 %    o magick: compare image format pattern against these bytes.
170 %
171 %    o length: Specifies the length of the magick string.
172 %
173 */
174 static MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
175 {
176   if (length < 2)
177     return(MagickFalse);
178   if (memcmp(magick,"\377\117",2) == 0)
179     return(MagickTrue);
180   return(MagickFalse);
181 }
182 \f
183 /*
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 %                                                                             %
186 %                                                                             %
187 %                                                                             %
188 %   R e a d J P 2 I m a g e                                                   %
189 %                                                                             %
190 %                                                                             %
191 %                                                                             %
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193 %
194 %  ReadJP2Image() reads a JPEG 2000 Image file (JP2) or JPEG 2000
195 %  codestream (JPC) image file and returns it.  It allocates the memory
196 %  necessary for the new Image structure and returns a pointer to the new
197 %  image or set of images.
198 %
199 %  JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
200 %
201 %  The format of the ReadJP2Image method is:
202 %
203 %      Image *ReadJP2Image(const ImageInfo *image_info,
204 %        ExceptionInfo *exception)
205 %
206 %  A description of each parameter follows:
207 %
208 %    o image_info: the image info.
209 %
210 %    o exception: return any errors or warnings in this structure.
211 %
212 */
213 #if defined(MAGICKCORE_JP2_DELEGATE)
214
215 typedef struct _StreamManager
216 {
217   jas_stream_t
218     *stream;
219
220   Image
221     *image;
222 } StreamManager;
223
224 static int BlobRead(jas_stream_obj_t *object,char *buffer,const int length)
225 {
226   ssize_t
227     count;
228
229   StreamManager
230     *source;
231
232   source=(StreamManager *) object;
233   count=ReadBlob(source->image,(size_t) length,(unsigned char *) buffer);
234   return((int) count);
235 }
236
237 static int BlobWrite(jas_stream_obj_t *object,char *buffer,const int length)
238 {
239   ssize_t
240     count;
241
242   StreamManager
243     *source;
244
245   source=(StreamManager *) object;
246   count=WriteBlob(source->image,(size_t) length,(unsigned char *) buffer);
247   return((int) count);
248 }
249
250 static long BlobSeek(jas_stream_obj_t *object,long offset,int origin)
251 {
252   StreamManager
253     *source;
254
255   source=(StreamManager *) object;
256   return((long) SeekBlob(source->image,offset,origin));
257 }
258
259 static int BlobClose(jas_stream_obj_t *object)
260 {
261   StreamManager
262     *source;
263
264   source=(StreamManager *) object;
265   (void) CloseBlob(source->image);
266   free(source);
267   source=(StreamManager *) NULL;
268   return(0);
269 }
270
271 static inline size_t MagickMax(const size_t x,const size_t y)
272 {
273   if (x > y)
274     return(x);
275   return(y);
276 }
277
278 static inline size_t MagickMin(const size_t x,const size_t y)
279 {
280   if (x < y)
281     return(x);
282   return(y);
283 }
284
285 static jas_stream_t *JP2StreamManager(Image *image)
286 {
287   static jas_stream_ops_t
288     StreamOperators =
289     {
290       BlobRead,
291       BlobWrite,
292       BlobSeek,
293       BlobClose
294     };
295
296   jas_stream_t
297     *stream;
298
299   StreamManager
300     *source;
301
302   stream=(jas_stream_t *) jas_malloc(sizeof(*stream));
303   if (stream == (jas_stream_t *) NULL)
304     return((jas_stream_t *) NULL);
305   (void) ResetMagickMemory(stream,0,sizeof(*stream));
306   stream->rwlimit_=(-1);
307   stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
308   if (stream->obj_ == (jas_stream_obj_t *) NULL)
309     return((jas_stream_t *) NULL);
310   (void) ResetMagickMemory(stream->obj_,0,sizeof(StreamManager));
311   stream->ops_=(&StreamOperators);
312   stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
313   stream->bufbase_=(unsigned char *) jas_malloc(JAS_STREAM_BUFSIZE+
314     JAS_STREAM_MAXPUTBACK);
315   if (stream->bufbase_ == (void *) NULL)
316     {
317       stream->bufbase_=stream->tinybuf_;
318       stream->bufsize_=1;
319     }
320   else
321     {
322       stream->bufmode_=JAS_STREAM_FREEBUF | JAS_STREAM_BUFMODEMASK;
323       stream->bufsize_=JAS_STREAM_BUFSIZE;
324     }
325   stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
326   stream->ptr_=stream->bufstart_;
327   stream->cnt_=0;
328   source=(StreamManager *) stream->obj_;
329   source->image=image;
330   return(stream);
331 }
332
333 static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
334 {
335   Image
336     *image;
337
338   jas_cmprof_t
339     *cm_profile;
340
341   jas_iccprof_t
342     *icc_profile;
343
344   jas_image_t
345     *jp2_image;
346
347   jas_matrix_t
348     *pixels[4];
349
350   jas_stream_t
351     *jp2_stream;
352
353   MagickBooleanType
354     status;
355
356   QuantumAny
357     pixel,
358     range[4];
359
360   register Quantum
361     *q;
362
363   register ssize_t
364     i,
365     x;
366
367   size_t
368     maximum_component_depth,
369     number_components,
370     x_step[4],
371     y_step[4];
372
373   ssize_t
374     components[4],
375     y;
376
377   /*
378     Open image file.
379   */
380   assert(image_info != (const ImageInfo *) NULL);
381   assert(image_info->signature == MagickSignature);
382   if (image_info->debug != MagickFalse)
383     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
384       image_info->filename);
385   assert(exception != (ExceptionInfo *) NULL);
386   assert(exception->signature == MagickSignature);
387   image=AcquireImage(image_info,exception);
388   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
389   if (status == MagickFalse)
390     {
391       image=DestroyImageList(image);
392       return((Image *) NULL);
393     }
394   /*
395     Initialize JPEG 2000 API.
396   */
397   jp2_stream=JP2StreamManager(image);
398   if (jp2_stream == (jas_stream_t *) NULL)
399     ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
400   jp2_image=jas_image_decode(jp2_stream,-1,0);
401   if (jp2_image == (jas_image_t *) NULL)
402     {
403       (void) jas_stream_close(jp2_stream);
404       ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
405     }
406   image->columns=jas_image_width(jp2_image);
407   image->rows=jas_image_height(jp2_image);
408   image->compression=JPEG2000Compression;
409   switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
410   {
411     case JAS_CLRSPC_FAM_RGB:
412     {
413       SetImageColorspace(image,RGBColorspace,exception);
414       components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_R);
415       components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_G);
416       components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_B);
417       if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
418         {
419           (void) jas_stream_close(jp2_stream);
420           jas_image_destroy(jp2_image);
421           ThrowReaderException(CorruptImageError,"MissingImageChannel");
422         }
423       number_components=3;
424       components[3]=jas_image_getcmptbytype(jp2_image,3);
425       if (components[3] > 0)
426         {
427           image->alpha_trait=BlendPixelTrait;
428           number_components++;
429         }
430       break;
431     }
432     case JAS_CLRSPC_FAM_GRAY:
433     {
434       SetImageColorspace(image,GRAYColorspace,exception);
435       components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_GRAY_Y);
436       if (components[0] < 0)
437         {
438           (void) jas_stream_close(jp2_stream);
439           jas_image_destroy(jp2_image);
440           ThrowReaderException(CorruptImageError,"MissingImageChannel");
441         }
442       number_components=1;
443       break;
444     }
445     case JAS_CLRSPC_FAM_YCBCR:
446     {
447       SetImageColorspace(image,YCbCrColorspace,exception);
448       components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
449       components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
450       components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
451       if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
452         {
453           (void) jas_stream_close(jp2_stream);
454           jas_image_destroy(jp2_image);
455           ThrowReaderException(CorruptImageError,"MissingImageChannel");
456         }
457       number_components=3;
458       components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
459       if (components[3] > 0)
460         {
461           image->alpha_trait=BlendPixelTrait;
462           number_components++;
463         }
464       break;
465     }
466     case JAS_CLRSPC_FAM_XYZ:
467     {
468       SetImageColorspace(image,XYZColorspace,exception);
469       components[0]=jas_image_getcmptbytype(jp2_image,0);
470       components[1]=jas_image_getcmptbytype(jp2_image,1);
471       components[2]=jas_image_getcmptbytype(jp2_image,2);
472       if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
473         {
474           (void) jas_stream_close(jp2_stream);
475           jas_image_destroy(jp2_image);
476           ThrowReaderException(CorruptImageError,"MissingImageChannel");
477         }
478       number_components=3;
479       components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
480       if (components[3] > 0)
481         {
482           image->alpha_trait=BlendPixelTrait;
483           number_components++;
484         }
485       break;
486     }
487     case JAS_CLRSPC_FAM_LAB:
488     {
489       SetImageColorspace(image,LabColorspace,exception);
490       components[0]=jas_image_getcmptbytype(jp2_image,0);
491       components[1]=jas_image_getcmptbytype(jp2_image,1);
492       components[2]=jas_image_getcmptbytype(jp2_image,2);
493       if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
494         {
495           (void) jas_stream_close(jp2_stream);
496           jas_image_destroy(jp2_image);
497           ThrowReaderException(CorruptImageError,"MissingImageChannel");
498         }
499       number_components=3;
500       components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
501       if (components[3] > 0)
502         {
503           image->alpha_trait=BlendPixelTrait;
504           number_components++;
505         }
506       break;
507     }
508     default:
509     {
510       (void) jas_stream_close(jp2_stream);
511       jas_image_destroy(jp2_image);
512       ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
513     }
514   }
515   for (i=0; i < (ssize_t) number_components; i++)
516   {
517     size_t
518       height,
519       width;
520
521     width=(size_t) (jas_image_cmptwidth(jp2_image,components[i])*
522       jas_image_cmpthstep(jp2_image,components[i]));
523     height=(size_t) (jas_image_cmptheight(jp2_image,components[i])*
524       jas_image_cmptvstep(jp2_image,components[i]));
525     x_step[i]=(unsigned int) jas_image_cmpthstep(jp2_image,components[i]);
526     y_step[i]=(unsigned int) jas_image_cmptvstep(jp2_image,components[i]);
527     if ((width != image->columns) || (height != image->rows) ||
528         (jas_image_cmpttlx(jp2_image,components[i]) != 0) ||
529         (jas_image_cmpttly(jp2_image,components[i]) != 0) ||
530         (jas_image_cmptsgnd(jp2_image,components[i]) != MagickFalse))
531       {
532         (void) jas_stream_close(jp2_stream);
533         jas_image_destroy(jp2_image);
534         ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported");
535       }
536   }
537   /*
538     Convert JPEG 2000 pixels.
539   */
540   image->alpha_trait=number_components > 3 ? BlendPixelTrait :
541     UndefinedPixelTrait;
542   maximum_component_depth=0;
543   for (i=0; i < (ssize_t) number_components; i++)
544   {
545     maximum_component_depth=(unsigned int) MagickMax((size_t)
546       jas_image_cmptprec(jp2_image,components[i]),(size_t)
547       maximum_component_depth);
548     pixels[i]=jas_matrix_create(1,(int) (image->columns/x_step[i]));
549     if (pixels[i] == (jas_matrix_t *) NULL)
550       {
551         for (--i; i >= 0; i--)
552           jas_matrix_destroy(pixels[i]);
553         jas_image_destroy(jp2_image);
554         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
555       }
556   }
557   image->depth=maximum_component_depth;
558   if (image_info->ping != MagickFalse)
559     {
560       (void) jas_stream_close(jp2_stream);
561       jas_image_destroy(jp2_image);
562       return(GetFirstImageInList(image));
563     }
564   for (i=0; i < (ssize_t) number_components; i++)
565     range[i]=GetQuantumRange((size_t) jas_image_cmptprec(jp2_image,
566       components[i]));
567   for (y=0; y < (ssize_t) image->rows; y++)
568   {
569     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
570     if (q == (Quantum *) NULL)
571       break;
572     for (i=0; i < (ssize_t) number_components; i++)
573       (void) jas_image_readcmpt(jp2_image,(short) components[i],0,
574         (jas_image_coord_t) (y/y_step[i]),(jas_image_coord_t) (image->columns/
575         x_step[i]),1,pixels[i]);
576     switch (number_components)
577     {
578       case 1:
579       {
580         /*
581           Grayscale.
582         */
583         for (x=0; x < (ssize_t) image->columns; x++)
584         {
585           pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
586           SetPixelGray(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
587           q+=GetPixelChannels(image);
588         }
589         break;
590       }
591       case 3:
592       {
593         /*
594           RGB.
595         */
596         for (x=0; x < (ssize_t) image->columns; x++)
597         {
598           pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
599           SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
600           pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
601           SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
602           pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
603           SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
604           q+=GetPixelChannels(image);
605         }
606         break;
607       }
608       case 4:
609       {
610         /*
611           RGBA.
612         */
613         for (x=0; x < (ssize_t) image->columns; x++)
614         {
615           pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
616           SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
617           pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
618           SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
619           pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
620           SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
621           pixel=(QuantumAny) jas_matrix_getv(pixels[3],x/x_step[3]);
622           SetPixelAlpha(image,ScaleAnyToQuantum((QuantumAny) pixel,range[3]),q);
623           q+=GetPixelChannels(image);
624         }
625         break;
626       }
627     }
628     if (SyncAuthenticPixels(image,exception) == MagickFalse)
629       break;
630     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
631       image->rows);
632     if (status == MagickFalse)
633       break;
634   }
635   cm_profile=jas_image_cmprof(jp2_image);
636   icc_profile=(jas_iccprof_t *) NULL;
637   if (cm_profile != (jas_cmprof_t *) NULL)
638     icc_profile=jas_iccprof_createfromcmprof(cm_profile);
639   if (icc_profile != (jas_iccprof_t *) NULL)
640     {
641       jas_stream_t
642         *icc_stream;
643
644       icc_stream=jas_stream_memopen(NULL,0);
645       if ((icc_stream != (jas_stream_t *) NULL) &&
646           (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
647           (jas_stream_flush(icc_stream) == 0))
648         {
649           jas_stream_memobj_t
650             *blob;
651
652           StringInfo
653             *icc_profile,
654             *profile;
655
656           /*
657             Extract the icc profile, handle errors without much noise.
658           */
659           blob=(jas_stream_memobj_t *) icc_stream->obj_;
660           if (image->debug != MagickFalse)
661             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
662               "Profile: ICC, %.20g bytes",(double) blob->len_);
663           profile=BlobToStringInfo(blob->buf_,blob->len_);
664           if (profile == (StringInfo *) NULL)
665             ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");
666           icc_profile=(StringInfo *) GetImageProfile(image,"icc");
667           if (icc_profile == (StringInfo *) NULL)
668             (void) SetImageProfile(image,"icc",profile,exception);
669           else
670             (void) ConcatenateStringInfo(icc_profile,profile);
671           profile=DestroyStringInfo(profile);
672           (void) jas_stream_close(icc_stream);
673         }
674     }
675   (void) jas_stream_close(jp2_stream);
676   jas_image_destroy(jp2_image);
677   for (i=0; i < (ssize_t) number_components; i++)
678     jas_matrix_destroy(pixels[i]);
679   return(GetFirstImageInList(image));
680 }
681 #endif
682 \f
683 /*
684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
685 %                                                                             %
686 %                                                                             %
687 %                                                                             %
688 %   R e g i s t e r J P 2 I m a g e                                           %
689 %                                                                             %
690 %                                                                             %
691 %                                                                             %
692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
693 %
694 %  RegisterJP2Image() adds attributes for the JP2 image format to the list of
695 %  supported formats.  The attributes include the image format tag, a method
696 %  method to read and/or write the format, whether the format supports the
697 %  saving of more than one frame to the same file or blob, whether the format
698 %  supports native in-memory I/O, and a brief description of the format.
699 %
700 %  The format of the RegisterJP2Image method is:
701 %
702 %      size_t RegisterJP2Image(void)
703 %
704 */
705 ModuleExport size_t RegisterJP2Image(void)
706 {
707   MagickInfo
708     *entry;
709
710   entry=SetMagickInfo("JP2");
711   entry->description=ConstantString("JPEG-2000 File Format Syntax");
712   entry->mime_type=ConstantString("image/jp2");
713   entry->module=ConstantString("JP2");
714   entry->magick=(IsImageFormatHandler *) IsJP2;
715   entry->adjoin=MagickFalse;
716   entry->seekable_stream=MagickTrue;
717   entry->thread_support=NoThreadSupport;
718 #if defined(MAGICKCORE_JP2_DELEGATE)
719   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
720   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
721 #endif
722   (void) RegisterMagickInfo(entry);
723   entry=SetMagickInfo("JPC");
724   entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
725   entry->mime_type=ConstantString("image/jp2");
726   entry->module=ConstantString("JP2");
727   entry->magick=(IsImageFormatHandler *) IsJPC;
728   entry->adjoin=MagickFalse;
729   entry->seekable_stream=MagickTrue;
730   entry->thread_support=NoThreadSupport;
731 #if defined(MAGICKCORE_JP2_DELEGATE)
732   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
733   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
734 #endif
735   (void) RegisterMagickInfo(entry);
736   entry=SetMagickInfo("J2C");
737   entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
738   entry->mime_type=ConstantString("image/jp2");
739   entry->module=ConstantString("JP2");
740   entry->magick=(IsImageFormatHandler *) IsJPC;
741   entry->adjoin=MagickFalse;
742   entry->seekable_stream=MagickTrue;
743   entry->thread_support=NoThreadSupport;
744 #if defined(MAGICKCORE_JP2_DELEGATE)
745   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
746   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
747 #endif
748   (void) RegisterMagickInfo(entry);
749   entry=SetMagickInfo("J2K");
750   entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
751   entry->mime_type=ConstantString("image/jp2");
752   entry->module=ConstantString("JP2");
753   entry->magick=(IsImageFormatHandler *) IsJPC;
754   entry->adjoin=MagickFalse;
755   entry->seekable_stream=MagickTrue;
756   entry->thread_support=NoThreadSupport;
757 #if defined(MAGICKCORE_JP2_DELEGATE)
758   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
759   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
760 #endif
761   (void) RegisterMagickInfo(entry);
762   entry=SetMagickInfo("JPX");
763   entry->description=ConstantString("JPEG-2000 File Format Syntax");
764   entry->mime_type=ConstantString("image/jp2");
765   entry->module=ConstantString("JP2");
766   entry->magick=(IsImageFormatHandler *) IsJPC;
767   entry->adjoin=MagickFalse;
768   entry->seekable_stream=MagickTrue;
769   entry->thread_support=NoThreadSupport;
770 #if defined(MAGICKCORE_JP2_DELEGATE)
771   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
772   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
773 #endif
774   (void) RegisterMagickInfo(entry);
775   entry=SetMagickInfo("PGX");
776   entry->description=ConstantString("JPEG-2000 VM Format");
777   entry->mime_type=ConstantString("image/jp2");
778   entry->module=ConstantString("JP2");
779   entry->magick=(IsImageFormatHandler *) IsJPC;
780   entry->adjoin=MagickFalse;
781   entry->seekable_stream=MagickTrue;
782   entry->thread_support=NoThreadSupport;
783 #if defined(MAGICKCORE_JP2_DELEGATE)
784   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
785 #endif
786   (void) RegisterMagickInfo(entry);
787 #if defined(MAGICKCORE_JP2_DELEGATE)
788   if (instantiate_jp2 == MagickFalse)
789     {
790       jas_init();
791       instantiate_jp2=MagickTrue;
792     }
793 #endif
794   return(MagickImageCoderSignature);
795 }
796 \f
797 /*
798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799 %                                                                             %
800 %                                                                             %
801 %                                                                             %
802 %   U n r e g i s t e r J P 2 I m a g e                                       %
803 %                                                                             %
804 %                                                                             %
805 %                                                                             %
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807 %
808 %  UnregisterJP2Image() removes format registrations made by the JP2 module
809 %  from the list of supported formats.
810 %
811 %  The format of the UnregisterJP2Image method is:
812 %
813 %      UnregisterJP2Image(void)
814 %
815 */
816 ModuleExport void UnregisterJP2Image(void)
817 {
818   (void) UnregisterMagickInfo("PGX");
819   (void) UnregisterMagickInfo("J2K");
820   (void) UnregisterMagickInfo("J2C");
821   (void) UnregisterMagickInfo("JPC");
822   (void) UnregisterMagickInfo("JP2");
823 #if defined(MAGICKCORE_JP2_DELEGATE)
824   if (instantiate_jp2 != MagickFalse)
825     {
826       jas_cleanup();
827       instantiate_jp2=MagickFalse;
828     }
829 #endif
830 }
831 \f
832 #if defined(MAGICKCORE_JP2_DELEGATE)
833 /*
834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835 %                                                                             %
836 %                                                                             %
837 %                                                                             %
838 %   W r i t e J P 2 I m a g e                                                 %
839 %                                                                             %
840 %                                                                             %
841 %                                                                             %
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843 %
844 %  WriteJP2Image() writes an image in the JPEG 2000 image format.
845 %
846 %  JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
847 %
848 %  The format of the WriteJP2Image method is:
849 %
850 %      MagickBooleanType WriteJP2Image(const ImageInfo *image_info,
851 %        Image *image,ExceptionInfo *exception)
852 %
853 %  A description of each parameter follows.
854 %
855 %    o image_info: the image info.
856 %
857 %    o image:  The image.
858 %
859 %    o exception: return any errors or warnings in this structure.
860 %
861 */
862 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
863   ExceptionInfo *exception)
864 {
865   char
866     *key,
867     magick[MaxTextExtent],
868     *options;
869
870   const char
871     *option;
872
873   jas_image_cmptparm_t
874     component_info[4];
875
876   jas_image_t
877     *jp2_image;
878
879   jas_matrix_t
880     *pixels[4];
881
882   jas_stream_t
883     *jp2_stream;
884
885   MagickBooleanType
886     status;
887
888   QuantumAny
889     range;
890
891   register const Quantum
892     *p;
893
894   register ssize_t
895     i,
896     x;
897
898   size_t
899     number_components;
900
901   ssize_t
902     format,
903     y;
904
905   /*
906     Open image file.
907   */
908   assert(image_info != (const ImageInfo *) NULL);
909   assert(image_info->signature == MagickSignature);
910   assert(image != (Image *) NULL);
911   assert(image->signature == MagickSignature);
912   if (image->debug != MagickFalse)
913     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
914   assert(exception != (ExceptionInfo *) NULL);
915   assert(exception->signature == MagickSignature);
916   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
917   if (status == MagickFalse)
918     return(status);
919   /*
920     Initialize JPEG 2000 API.
921   */
922   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
923     (void) TransformImageColorspace(image,sRGBColorspace,exception);
924   jp2_stream=JP2StreamManager(image);
925   if (jp2_stream == (jas_stream_t *) NULL)
926     ThrowWriterException(DelegateError,"UnableToManageJP2Stream");
927   number_components=image->alpha_trait ? 4UL : 3UL;
928   if (IsGrayColorspace(image->colorspace) != MagickFalse)
929     number_components=1;
930   if ((image->columns != (unsigned int) image->columns) ||
931       (image->rows != (unsigned int) image->rows))
932     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
933   (void) ResetMagickMemory(&component_info,0,sizeof(component_info));
934   for (i=0; i < (ssize_t) number_components; i++)
935   {
936     component_info[i].tlx=0;
937     component_info[i].tly=0;
938     component_info[i].hstep=1;
939     component_info[i].vstep=1;
940     component_info[i].width=(unsigned int) image->columns;
941     component_info[i].height=(unsigned int) image->rows;
942     component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2);
943     component_info[i].sgnd=MagickFalse;
944   }
945   jp2_image=jas_image_create((int) number_components,component_info,
946     JAS_CLRSPC_UNKNOWN);
947   if (jp2_image == (jas_image_t *) NULL)
948     ThrowWriterException(DelegateError,"UnableToCreateImage");
949   switch (image->colorspace)
950   {
951     case RGBColorspace:
952     case sRGBColorspace:
953     {
954       /*
955         RGB colorspace.
956       */
957       jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB);
958       jas_image_setcmpttype(jp2_image,0,
959         (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
960       jas_image_setcmpttype(jp2_image,1,
961         (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
962       jas_image_setcmpttype(jp2_image,2,
963         (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
964       if (number_components == 4)
965         jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
966       break;
967     }
968     case GRAYColorspace:
969     {
970       /*
971         Grayscale colorspace.
972       */
973       jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY);
974       jas_image_setcmpttype(jp2_image,0,
975         JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
976       break;
977     }
978     case YCbCrColorspace:
979     {
980       /*
981         YCbCr colorspace.
982       */
983       jas_image_setclrspc(jp2_image,JAS_CLRSPC_SYCBCR);
984       jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
985         JAS_IMAGE_CT_COLOR(0));
986       jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
987         JAS_IMAGE_CT_COLOR(1));
988       jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
989         JAS_IMAGE_CT_COLOR(2));
990       if (number_components == 4)
991         jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
992       break;
993     }
994     case XYZColorspace:
995     {
996       /*
997         XYZ colorspace.
998       */
999       jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIEXYZ);
1000       jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1001         JAS_IMAGE_CT_COLOR(0));
1002       jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1003         JAS_IMAGE_CT_COLOR(1));
1004       jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1005         JAS_IMAGE_CT_COLOR(2));
1006       if (number_components == 4)
1007         jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1008       break;
1009     }
1010     case LabColorspace:
1011     {
1012       /*
1013         Lab colorspace.
1014       */
1015       jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIELAB);
1016       jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1017         JAS_IMAGE_CT_COLOR(0));
1018       jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1019         JAS_IMAGE_CT_COLOR(1));
1020       jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1021         JAS_IMAGE_CT_COLOR(2));
1022       if (number_components == 4)
1023         jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1024       break;
1025     }
1026     default:
1027     {
1028       /*
1029         Unknow.
1030       */
1031       jas_image_setclrspc(jp2_image,JAS_CLRSPC_UNKNOWN);
1032       jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1033         JAS_IMAGE_CT_COLOR(0));
1034       jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1035         JAS_IMAGE_CT_COLOR(1));
1036       jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1037         JAS_IMAGE_CT_COLOR(2));
1038       if (number_components == 4)
1039         jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1040       break;
1041     }
1042   }
1043   /*
1044     Convert to JPEG 2000 pixels.
1045   */
1046   for (i=0; i < (ssize_t) number_components; i++)
1047   {
1048     pixels[i]=jas_matrix_create(1,(int) image->columns);
1049     if (pixels[i] == (jas_matrix_t *) NULL)
1050       {
1051         for (x=0; x < i; x++)
1052           jas_matrix_destroy(pixels[x]);
1053         jas_image_destroy(jp2_image);
1054         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1055       }
1056   }
1057   range=GetQuantumRange((size_t) component_info[0].prec);
1058   for (y=0; y < (ssize_t) image->rows; y++)
1059   {
1060     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1061     if (p == (const Quantum *) NULL)
1062       break;
1063     for (x=0; x < (ssize_t) image->columns; x++)
1064     {
1065       if (number_components == 1)
1066         jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1067           ClampToQuantum(GetPixelLuma(image,p)),range));
1068       else
1069         {
1070           jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1071             GetPixelRed(image,p),range));
1072           jas_matrix_setv(pixels[1],x,(jas_seqent_t) ScaleQuantumToAny(
1073             GetPixelGreen(image,p),range));
1074           jas_matrix_setv(pixels[2],x,(jas_seqent_t) ScaleQuantumToAny(
1075             GetPixelBlue(image,p),range));
1076           if (number_components > 3)
1077             jas_matrix_setv(pixels[3],x,(jas_seqent_t) ScaleQuantumToAny(
1078               GetPixelAlpha(image,p),range));
1079         }
1080       p+=GetPixelChannels(image);
1081     }
1082     for (i=0; i < (ssize_t) number_components; i++)
1083       (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y,
1084         (unsigned int) image->columns,1,pixels[i]);
1085     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1086       image->rows);
1087     if (status == MagickFalse)
1088       break;
1089   }
1090   (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1091   if (LocaleCompare(magick,"J2C") == 0)
1092     (void) CopyMagickString(magick,"JPC",MaxTextExtent);
1093   LocaleLower(magick);
1094   format=jas_image_strtofmt(magick);
1095   options=(char *) NULL;
1096   ResetImageOptionIterator(image_info);
1097   key=GetNextImageOption(image_info);
1098   for ( ; key != (char *) NULL; key=GetNextImageOption(image_info))
1099   {
1100     option=GetImageOption(image_info,key);
1101     if (option == (const char *) NULL)
1102       continue;
1103     if (LocaleNCompare(key,"jp2:",4) == 0)
1104       {
1105         (void) ConcatenateString(&options,key+4);
1106         if (*option != '\0')
1107           {
1108             (void) ConcatenateString(&options,"=");
1109             (void) ConcatenateString(&options,option);
1110           }
1111         (void) ConcatenateString(&options," ");
1112       }
1113   }
1114   option=GetImageOption(image_info,"jp2:rate");
1115   if ((option == (const char *) NULL) &&
1116       (image_info->compression != LosslessJPEGCompression) &&
1117       (image->quality != UndefinedCompressionQuality) &&
1118       ((double) image->quality <= 99.5) &&
1119       ((image->rows*image->columns) > 2500))
1120     {
1121       char
1122         option[MaxTextExtent];
1123
1124       double
1125         alpha,
1126         header_size,
1127         number_pixels,
1128         rate,
1129         target_size;
1130
1131       alpha=115.0-image->quality;
1132       rate=100.0/(alpha*alpha);
1133       header_size=550.0;
1134       header_size+=(number_components-1)*142;
1135       number_pixels=(double) image->rows*image->columns*number_components*
1136         (GetImageQuantumDepth(image,MagickTrue)/8);
1137       target_size=(number_pixels*rate)+header_size;
1138       rate=target_size/number_pixels;
1139       (void) FormatLocaleString(option,MaxTextExtent,"rate=%g",rate);
1140       (void) ConcatenateString(&options,option);
1141     }
1142   status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ?
1143     MagickTrue : MagickFalse;
1144   if (options != (char *) NULL)
1145     options=DestroyString(options);
1146   (void) jas_stream_close(jp2_stream);
1147   for (i=0; i < (ssize_t) number_components; i++)
1148     jas_matrix_destroy(pixels[i]);
1149   jas_image_destroy(jp2_image);
1150   if (status != MagickFalse)
1151     ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1152   return(MagickTrue);
1153 }
1154 #endif