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