]> 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   ssize_t
351     components[4],
352     y;
353
354   MagickBooleanType
355     status;
356
357   QuantumAny
358     pixel,
359     range[4];
360
361   register ssize_t
362     i,
363     x;
364
365   register PixelPacket
366     *q;
367
368   size_t
369     maximum_component_depth,
370     number_components,
371     x_step[4],
372     y_step[4];
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           q->red=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[0]);
540           SetGreenPixelComponent(q,GetRedPixelComponent(q));
541           SetBluePixelComponent(q,GetRedPixelComponent(q));
542           q++;
543         }
544         break;
545       }
546       case 3:
547       {
548         /*
549           RGB.
550         */
551         for (x=0; x < (ssize_t) image->columns; x++)
552         {
553           pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
554           q->red=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[0]);
555           pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
556           q->green=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[1]);
557           pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
558           q->blue=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[2]);
559           q++;
560         }
561         break;
562       }
563       case 4:
564       {
565         /*
566           RGBA.
567         */
568         for (x=0; x < (ssize_t) image->columns; x++)
569         {
570           pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
571           q->red=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[0]);
572           pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
573           q->green=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[1]);
574           pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
575           q->blue=(Quantum) ScaleAnyToQuantum((QuantumAny) pixel,range[2]);
576           pixel=(QuantumAny) jas_matrix_getv(pixels[3],x/x_step[3]);
577           q->opacity=(Quantum) (QuantumRange-
578             ScaleAnyToQuantum((QuantumAny) pixel,range[3]));
579           q++;
580         }
581         break;
582       }
583     }
584     if (SyncAuthenticPixels(image,exception) == MagickFalse)
585       break;
586     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
587                 image->rows);
588     if (status == MagickFalse)
589       break;
590   }
591   cm_profile=jas_image_cmprof(jp2_image);
592   icc_profile=(jas_iccprof_t *) NULL;
593   if (cm_profile != (jas_cmprof_t *) NULL)
594     icc_profile=jas_iccprof_createfromcmprof(cm_profile);
595   if (icc_profile != (jas_iccprof_t *) NULL)
596     {
597       jas_stream_t
598         *icc_stream;
599
600       icc_stream=jas_stream_memopen(NULL,0);
601       if ((icc_stream != (jas_stream_t *) NULL) &&
602           (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
603           (jas_stream_flush(icc_stream) == 0))
604         {
605           StringInfo
606             *icc_profile,
607             *profile;
608
609           jas_stream_memobj_t
610             *blob;
611
612           /*
613             Extract the icc profile, handle errors without much noise.
614           */
615           blob=(jas_stream_memobj_t *) icc_stream->obj_;
616           if (image->debug != MagickFalse)
617             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
618               "Profile: ICC, %.20g bytes",(double) blob->len_);
619           profile=AcquireStringInfo(blob->len_);
620           SetStringInfoDatum(profile,blob->buf_);
621           icc_profile=(StringInfo *) GetImageProfile(image,"icc");
622           if (icc_profile == (StringInfo *) NULL)
623             (void) SetImageProfile(image,"icc",profile);
624           else
625             (void) ConcatenateStringInfo(icc_profile,profile);
626           profile=DestroyStringInfo(profile);
627           (void) jas_stream_close(icc_stream);
628         }
629     }
630   (void) jas_stream_close(jp2_stream);
631   jas_image_destroy(jp2_image);
632   for (i=0; i < (ssize_t) number_components; i++)
633     jas_matrix_destroy(pixels[i]);
634   return(GetFirstImageInList(image));
635 }
636 #endif
637 \f
638 /*
639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
640 %                                                                             %
641 %                                                                             %
642 %                                                                             %
643 %   R e g i s t e r J P 2 I m a g e                                           %
644 %                                                                             %
645 %                                                                             %
646 %                                                                             %
647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
648 %
649 %  RegisterJP2Image() adds attributes for the JP2 image format to the list of
650 %  supported formats.  The attributes include the image format tag, a method
651 %  method to read and/or write the format, whether the format supports the
652 %  saving of more than one frame to the same file or blob, whether the format
653 %  supports native in-memory I/O, and a brief description of the format.
654 %
655 %  The format of the RegisterJP2Image method is:
656 %
657 %      size_t RegisterJP2Image(void)
658 %
659 */
660 ModuleExport size_t RegisterJP2Image(void)
661 {
662   MagickInfo
663     *entry;
664
665   entry=SetMagickInfo("JP2");
666   entry->description=ConstantString("JPEG-2000 File Format Syntax");
667   entry->module=ConstantString("JP2");
668   entry->magick=(IsImageFormatHandler *) IsJP2;
669   entry->adjoin=MagickFalse;
670   entry->seekable_stream=MagickTrue;
671   entry->thread_support=NoThreadSupport;
672 #if defined(MAGICKCORE_JP2_DELEGATE)
673   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
674   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
675 #endif
676   (void) RegisterMagickInfo(entry);
677   entry=SetMagickInfo("JPC");
678   entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
679   entry->module=ConstantString("JP2");
680   entry->magick=(IsImageFormatHandler *) IsJPC;
681   entry->adjoin=MagickFalse;
682   entry->seekable_stream=MagickTrue;
683   entry->thread_support=NoThreadSupport;
684 #if defined(MAGICKCORE_JP2_DELEGATE)
685   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
686   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
687 #endif
688   (void) RegisterMagickInfo(entry);
689   entry=SetMagickInfo("J2C");
690   entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
691   entry->module=ConstantString("JP2");
692   entry->magick=(IsImageFormatHandler *) IsJPC;
693   entry->adjoin=MagickFalse;
694   entry->seekable_stream=MagickTrue;
695   entry->thread_support=NoThreadSupport;
696 #if defined(MAGICKCORE_JP2_DELEGATE)
697   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
698   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
699 #endif
700   (void) RegisterMagickInfo(entry);
701   entry=SetMagickInfo("JPX");
702   entry->description=ConstantString("JPEG-2000 File Format Syntax");
703   entry->module=ConstantString("JP2");
704   entry->magick=(IsImageFormatHandler *) IsJPC;
705   entry->adjoin=MagickFalse;
706   entry->seekable_stream=MagickTrue;
707   entry->thread_support=NoThreadSupport;
708 #if defined(MAGICKCORE_JP2_DELEGATE)
709   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
710   entry->encoder=(EncodeImageHandler *) WriteJP2Image;
711 #endif
712   (void) RegisterMagickInfo(entry);
713   entry=SetMagickInfo("PGX");
714   entry->description=ConstantString("JPEG-2000 VM Format");
715   entry->module=ConstantString("JP2");
716   entry->magick=(IsImageFormatHandler *) IsJPC;
717   entry->adjoin=MagickFalse;
718   entry->seekable_stream=MagickTrue;
719   entry->thread_support=NoThreadSupport;
720 #if defined(MAGICKCORE_JP2_DELEGATE)
721   entry->decoder=(DecodeImageHandler *) ReadJP2Image;
722 #endif
723   (void) RegisterMagickInfo(entry);
724 #if defined(MAGICKCORE_JP2_DELEGATE)
725   if (instantiate_jp2 == MagickFalse)
726     {
727       jas_init();
728       instantiate_jp2=MagickTrue;
729     }
730 #endif
731   return(MagickImageCoderSignature);
732 }
733 \f
734 /*
735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
736 %                                                                             %
737 %                                                                             %
738 %                                                                             %
739 %   U n r e g i s t e r J P 2 I m a g e                                       %
740 %                                                                             %
741 %                                                                             %
742 %                                                                             %
743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
744 %
745 %  UnregisterJP2Image() removes format registrations made by the JP2 module
746 %  from the list of supported formats.
747 %
748 %  The format of the UnregisterJP2Image method is:
749 %
750 %      UnregisterJP2Image(void)
751 %
752 */
753 ModuleExport void UnregisterJP2Image(void)
754 {
755   (void) UnregisterMagickInfo("PGX");
756   (void) UnregisterMagickInfo("J2C");
757   (void) UnregisterMagickInfo("JPC");
758   (void) UnregisterMagickInfo("JP2");
759 #if defined(MAGICKCORE_JP2_DELEGATE)
760   if (instantiate_jp2 != MagickFalse)
761     {
762       jas_cleanup();
763       instantiate_jp2=MagickFalse;
764     }
765 #endif
766 }
767 \f
768 #if defined(MAGICKCORE_JP2_DELEGATE)
769 /*
770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771 %                                                                             %
772 %                                                                             %
773 %                                                                             %
774 %   W r i t e J P 2 I m a g e                                                 %
775 %                                                                             %
776 %                                                                             %
777 %                                                                             %
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779 %
780 %  WriteJP2Image() writes an image in the JPEG 2000 image format.
781 %
782 %  JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
783 %
784 %  The format of the WriteJP2Image method is:
785 %
786 %      MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
787 %
788 %  A description of each parameter follows.
789 %
790 %    o image_info: the image info.
791 %
792 %    o image:  The image.
793 %
794 */
795 static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
796 {
797   char
798     *key,
799     magick[MaxTextExtent],
800     *options;
801
802   const char
803     *option;
804
805   ssize_t
806     format,
807     y;
808
809   jas_image_cmptparm_t
810     component_info[4];
811
812   jas_image_t
813     *jp2_image;
814
815   jas_matrix_t
816     *pixels[4];
817
818   jas_stream_t
819     *jp2_stream;
820
821   MagickBooleanType
822     status;
823
824   QuantumAny
825     range;
826
827   register const PixelPacket
828     *p;
829
830   register ssize_t
831     i,
832     x;
833
834   size_t
835     number_components;
836
837   /*
838     Open image file.
839   */
840   assert(image_info != (const ImageInfo *) NULL);
841   assert(image_info->signature == MagickSignature);
842   assert(image != (Image *) NULL);
843   assert(image->signature == MagickSignature);
844   if (image->debug != MagickFalse)
845     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
846   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
847   if (status == MagickFalse)
848     return(status);
849   /*
850     Intialize JPEG 2000 API.
851   */
852   if (image->colorspace != RGBColorspace)
853     (void) TransformImageColorspace(image,RGBColorspace);
854   jp2_stream=JP2StreamManager(image);
855   if (jp2_stream == (jas_stream_t *) NULL)
856     ThrowWriterException(DelegateError,"UnableToManageJP2Stream");
857   number_components=image->matte ? 4UL : 3UL;
858   if ((image_info->type != TrueColorType) &&
859       (IsGrayImage(image,&image->exception) != MagickFalse))
860     number_components=1;
861   if ((image->columns != (unsigned int) image->columns) ||
862       (image->rows != (unsigned int) image->rows))
863     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
864   (void) ResetMagickMemory(&component_info,0,sizeof(component_info));
865   for (i=0; i < (ssize_t) number_components; i++)
866   {
867     component_info[i].tlx=0;
868     component_info[i].tly=0;
869     component_info[i].hstep=1;
870     component_info[i].vstep=1;
871     component_info[i].width=(unsigned int) image->columns;
872     component_info[i].height=(unsigned int) image->rows;
873     component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2);
874     component_info[i].sgnd=MagickFalse;
875   }
876   jp2_image=jas_image_create((int) number_components,component_info,
877     JAS_CLRSPC_UNKNOWN);
878   if (jp2_image == (jas_image_t *) NULL)
879     ThrowWriterException(DelegateError,"UnableToCreateImage");
880   if (number_components == 1)
881     {
882       /*
883         sRGB Grayscale.
884       */
885       jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY);
886       jas_image_setcmpttype(jp2_image,0,
887         JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
888     }
889   else
890     {
891       /*
892         sRGB.
893       */
894       jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB);
895       jas_image_setcmpttype(jp2_image,0,
896         (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
897       jas_image_setcmpttype(jp2_image,1,
898         (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
899       jas_image_setcmpttype(jp2_image,2,
900         (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
901       if (number_components == 4)
902         jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
903     }
904   /*
905     Convert to JPEG 2000 pixels.
906   */
907   for (i=0; i < (ssize_t) number_components; i++)
908   {
909     pixels[i]=jas_matrix_create(1,(int) image->columns);
910     if (pixels[i] == (jas_matrix_t *) NULL)
911       {
912         for (x=0; x < i; x++)
913           jas_matrix_destroy(pixels[x]);
914         jas_image_destroy(jp2_image);
915         ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
916       }
917   }
918   range=GetQuantumRange((size_t) component_info[0].prec);
919   for (y=0; y < (ssize_t) image->rows; y++)
920   {
921     p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
922     if (p == (const PixelPacket *) NULL)
923       break;
924     for (x=0; x < (ssize_t) image->columns; x++)
925     {
926       if (number_components == 1)
927         jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
928           PixelIntensityToQuantum(p),range));
929       else
930         {
931           jas_matrix_setv(pixels[0],x,(jas_seqent_t)
932             ScaleQuantumToAny(GetRedPixelComponent(p),range));
933           jas_matrix_setv(pixels[1],x,(jas_seqent_t)
934             ScaleQuantumToAny(GetGreenPixelComponent(p),range));
935           jas_matrix_setv(pixels[2],x,(jas_seqent_t)
936             ScaleQuantumToAny(GetBluePixelComponent(p),range));
937           if (number_components > 3)
938             jas_matrix_setv(pixels[3],x,(jas_seqent_t)
939               ScaleQuantumToAny((Quantum) (GetAlphaPixelComponent(p)),range));
940         }
941       p++;
942     }
943     for (i=0; i < (ssize_t) number_components; i++)
944       (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y,
945         (unsigned int) image->columns,1,pixels[i]);
946     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
947                 image->rows);
948     if (status == MagickFalse)
949       break;
950   }
951   (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
952   if (LocaleCompare(magick,"J2C") == 0)
953     (void) CopyMagickString(magick,"JPC",MaxTextExtent);
954   LocaleLower(magick);
955   format=jas_image_strtofmt(magick);
956   options=(char *) NULL;
957   ResetImageOptionIterator(image_info);
958   key=GetNextImageOption(image_info);
959   for ( ; key != (char *) NULL; key=GetNextImageOption(image_info))
960   {
961     option=GetImageOption(image_info,key);
962     if (option == (const char *) NULL)
963       continue;
964     if (LocaleNCompare(key,"jp2:",4) == 0)
965       {
966         (void) ConcatenateString(&options,key+4);
967         if (*option != '\0')
968           {
969             (void) ConcatenateString(&options,"=");
970             (void) ConcatenateString(&options,option);
971           }
972         (void) ConcatenateString(&options," ");
973       }
974   }
975   option=GetImageOption(image_info,"jp2:rate");
976   if ((option == (const char *) NULL) &&
977       (image_info->compression != LosslessJPEGCompression) &&
978       (image->quality != UndefinedCompressionQuality) &&
979       ((double) image->quality <= 99.5) &&
980       ((image->rows*image->columns) > 2500))
981     {
982       char
983         option[MaxTextExtent];
984
985       double
986         alpha,
987         header_size,
988         number_pixels,
989         rate,
990         target_size;
991
992       alpha=115.0-image->quality;
993       rate=100.0/(alpha*alpha);
994       header_size=550.0;
995       header_size+=(number_components-1)*142;
996       number_pixels=(double) image->rows*image->columns*number_components*
997         (GetImageQuantumDepth(image,MagickTrue)/8);
998       target_size=(number_pixels*rate)+header_size;
999       rate=target_size/number_pixels;
1000       (void) FormatMagickString(option,MaxTextExtent,"rate=%g",rate);
1001       (void) ConcatenateString(&options,option);
1002     }
1003   status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ?
1004     MagickTrue : MagickFalse;
1005   (void) jas_stream_close(jp2_stream);
1006   for (i=0; i < (ssize_t) number_components; i++)
1007     jas_matrix_destroy(pixels[i]);
1008   jas_image_destroy(jp2_image);
1009   if (status != MagickFalse)
1010     ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1011   return(MagickTrue);
1012 }
1013 #endif