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