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