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