blob: 18c36c5b50c7555810598c44ae9815f81d18a828 [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/attribute.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000048#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000049#include "MagickCore/color.h"
50#include "MagickCore/color-private.h"
51#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
53#include "MagickCore/image.h"
54#include "MagickCore/image-private.h"
55#include "MagickCore/list.h"
56#include "MagickCore/magick.h"
57#include "MagickCore/memory_.h"
58#include "MagickCore/monitor.h"
59#include "MagickCore/monitor-private.h"
60#include "MagickCore/option.h"
61#include "MagickCore/pixel-accessor.h"
62#include "MagickCore/profile.h"
63#include "MagickCore/quantum-private.h"
64#include "MagickCore/static.h"
65#include "MagickCore/statistic.h"
66#include "MagickCore/string_.h"
67#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000068#if defined(MAGICKCORE_JP2_DELEGATE)
69#ifndef JAS_IMAGE_CM_GRAY
70#define JAS_IMAGE_CM_GRAY JAS_IMAGE_CS_GRAY
71#endif
72#ifndef JAS_IMAGE_CM_RGB
73#define JAS_IMAGE_CM_RGB JAS_IMAGE_CS_RGB
74#endif
75#if !defined(uchar)
76#define uchar unsigned char
77#endif
78#if !defined(ushort)
79#define ushort unsigned short
80#endif
81#if !defined(uint)
82#define uint unsigned int
83#endif
cristybb503372010-05-27 20:51:26 +000084#if !defined(ssize_tssize_t)
85#define ssize_tssize_t long long
cristy3ed852e2009-09-05 21:47:34 +000086#endif
cristybb503372010-05-27 20:51:26 +000087#if !defined(ussize_tssize_t)
88#define ussize_tssize_t unsigned long long
cristy3ed852e2009-09-05 21:47:34 +000089#endif
90
cristy30faca22009-09-29 13:49:52 +000091#undef PACKAGE_NAME
92#undef PACKAGE_STRING
93#undef PACKAGE_TARNAME
94#undef PACKAGE_VERSION
cristy3ed852e2009-09-05 21:47:34 +000095#include "jasper/jasper.h"
cristy30faca22009-09-29 13:49:52 +000096#undef PACKAGE_NAME
97#undef PACKAGE_STRING
98#undef PACKAGE_TARNAME
99#undef PACKAGE_VERSION
100
cristy3ed852e2009-09-05 21:47:34 +0000101#endif
102
103/*
104 Forward declarations.
105*/
106#if defined(MAGICKCORE_JP2_DELEGATE)
107static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000108 WriteJP2Image(const ImageInfo *,Image *,ExceptionInfo *);
cristy1e09ca22009-12-27 18:04:58 +0000109
110static volatile MagickBooleanType
111 instantiate_jp2 = MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000112#endif
113
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*/
139static 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
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*/
173static 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
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
214typedef struct _StreamManager
215{
216 jas_stream_t
217 *stream;
218
219 Image
220 *image;
221} StreamManager;
222
223static 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
236static 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
cristyf1d91242010-05-28 02:23:19 +0000249static long BlobSeek(jas_stream_obj_t *object,long offset,int origin)
cristy3ed852e2009-09-05 21:47:34 +0000250{
251 StreamManager
252 *source;
253
254 source=(StreamManager *) object;
cristyf1d91242010-05-28 02:23:19 +0000255 return((long) SeekBlob(source->image,offset,origin));
cristy3ed852e2009-09-05 21:47:34 +0000256}
257
258static int BlobClose(jas_stream_obj_t *object)
259{
260 StreamManager
261 *source;
262
263 source=(StreamManager *) object;
264 (void) CloseBlob(source->image);
cristyb41ee102010-10-04 16:46:15 +0000265 free(source);
266 source=(StreamManager *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000267 return(0);
268}
269
270static inline size_t MagickMax(const size_t x,const size_t y)
271{
272 if (x > y)
273 return(x);
274 return(y);
275}
276
277static inline size_t MagickMin(const size_t x,const size_t y)
278{
279 if (x < y)
280 return(x);
281 return(y);
282}
283
284static jas_stream_t *JP2StreamManager(Image *image)
285{
286 static jas_stream_ops_t
287 StreamOperators =
288 {
289 BlobRead,
290 BlobWrite,
291 BlobSeek,
292 BlobClose
293 };
294
295 jas_stream_t
296 *stream;
297
298 StreamManager
299 *source;
300
301 stream=(jas_stream_t *) jas_malloc(sizeof(*stream));
302 if (stream == (jas_stream_t *) NULL)
303 return((jas_stream_t *) NULL);
304 (void) ResetMagickMemory(stream,0,sizeof(*stream));
305 stream->rwlimit_=(-1);
306 stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
307 if (stream->obj_ == (jas_stream_obj_t *) NULL)
308 return((jas_stream_t *) NULL);
309 (void) ResetMagickMemory(stream->obj_,0,sizeof(StreamManager));
310 stream->ops_=(&StreamOperators);
311 stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
312 stream->bufbase_=(unsigned char *) jas_malloc(JAS_STREAM_BUFSIZE+
313 JAS_STREAM_MAXPUTBACK);
314 if (stream->bufbase_ == (void *) NULL)
315 {
316 stream->bufbase_=stream->tinybuf_;
317 stream->bufsize_=1;
318 }
319 else
320 {
321 stream->bufmode_=JAS_STREAM_FREEBUF | JAS_STREAM_BUFMODEMASK;
322 stream->bufsize_=JAS_STREAM_BUFSIZE;
323 }
324 stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
325 stream->ptr_=stream->bufstart_;
326 stream->cnt_=0;
327 source=(StreamManager *) stream->obj_;
328 source->image=image;
329 return(stream);
330}
331
332static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
333{
334 Image
335 *image;
336
cristy3ed852e2009-09-05 21:47:34 +0000337 jas_cmprof_t
338 *cm_profile;
339
340 jas_iccprof_t
341 *icc_profile;
342
343 jas_image_t
344 *jp2_image;
345
346 jas_matrix_t
347 *pixels[4];
348
349 jas_stream_t
350 *jp2_stream;
351
352 MagickBooleanType
353 status;
354
355 QuantumAny
cristy30faca22009-09-29 13:49:52 +0000356 pixel,
cristy722af032009-12-04 01:50:06 +0000357 range[4];
cristy3ed852e2009-09-05 21:47:34 +0000358
cristybb503372010-05-27 20:51:26 +0000359 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000360 i,
361 x;
362
cristy4c08aed2011-07-01 19:47:50 +0000363 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000364 *q;
365
cristybb503372010-05-27 20:51:26 +0000366 size_t
cristy3ed852e2009-09-05 21:47:34 +0000367 maximum_component_depth,
368 number_components,
cristy3ed852e2009-09-05 21:47:34 +0000369 x_step[4],
370 y_step[4];
371
cristy524222d2011-04-25 00:37:06 +0000372 ssize_t
373 components[4],
374 y;
375
cristy3ed852e2009-09-05 21:47:34 +0000376 /*
377 Open image file.
378 */
379 assert(image_info != (const ImageInfo *) NULL);
380 assert(image_info->signature == MagickSignature);
381 if (image_info->debug != MagickFalse)
382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
383 image_info->filename);
384 assert(exception != (ExceptionInfo *) NULL);
385 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000386 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000387 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
388 if (status == MagickFalse)
389 {
390 image=DestroyImageList(image);
391 return((Image *) NULL);
392 }
393 /*
394 Initialize JPEG 2000 API.
395 */
396 jp2_stream=JP2StreamManager(image);
397 if (jp2_stream == (jas_stream_t *) NULL)
398 ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
399 jp2_image=jas_image_decode(jp2_stream,-1,0);
400 if (jp2_image == (jas_image_t *) NULL)
401 {
402 (void) jas_stream_close(jp2_stream);
403 ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
404 }
cristy2f040d02012-05-24 18:14:16 +0000405 image->columns=jas_image_width(jp2_image);
406 image->rows=jas_image_height(jp2_image);
407 image->compression=JPEG2000Compression;
cristy3ed852e2009-09-05 21:47:34 +0000408 switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
409 {
410 case JAS_CLRSPC_FAM_RGB:
411 {
cristy2f040d02012-05-24 18:14:16 +0000412 SetImageColorspace(image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000413 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_R);
414 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_G);
415 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_B);
416 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
417 {
418 (void) jas_stream_close(jp2_stream);
419 jas_image_destroy(jp2_image);
420 ThrowReaderException(CorruptImageError,"MissingImageChannel");
421 }
422 number_components=3;
423 components[3]=jas_image_getcmptbytype(jp2_image,3);
424 if (components[3] > 0)
425 {
426 image->matte=MagickTrue;
427 number_components++;
428 }
429 break;
430 }
431 case JAS_CLRSPC_FAM_GRAY:
432 {
cristy2f040d02012-05-24 18:14:16 +0000433 SetImageColorspace(image,GRAYColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000434 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_GRAY_Y);
435 if (components[0] < 0)
436 {
437 (void) jas_stream_close(jp2_stream);
438 jas_image_destroy(jp2_image);
439 ThrowReaderException(CorruptImageError,"MissingImageChannel");
440 }
441 number_components=1;
442 break;
443 }
444 case JAS_CLRSPC_FAM_YCBCR:
445 {
cristy2f040d02012-05-24 18:14:16 +0000446 SetImageColorspace(image,YCbCrColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000447 components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
448 components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
449 components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
450 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
451 {
452 (void) jas_stream_close(jp2_stream);
453 jas_image_destroy(jp2_image);
454 ThrowReaderException(CorruptImageError,"MissingImageChannel");
455 }
456 number_components=3;
457 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
458 if (components[3] > 0)
459 {
460 image->matte=MagickTrue;
461 number_components++;
462 }
cristy3ed852e2009-09-05 21:47:34 +0000463 break;
464 }
cristy0ea80f82012-05-24 18:47:10 +0000465 case JAS_CLRSPC_FAM_XYZ:
466 {
467 SetImageColorspace(image,XYZColorspace,exception);
468 components[0]=jas_image_getcmptbytype(jp2_image,0);
469 components[1]=jas_image_getcmptbytype(jp2_image,1);
470 components[2]=jas_image_getcmptbytype(jp2_image,2);
471 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
472 {
473 (void) jas_stream_close(jp2_stream);
474 jas_image_destroy(jp2_image);
475 ThrowReaderException(CorruptImageError,"MissingImageChannel");
476 }
477 number_components=3;
478 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
479 if (components[3] > 0)
480 {
481 image->matte=MagickTrue;
482 number_components++;
483 }
484 break;
485 }
486 case JAS_CLRSPC_FAM_LAB:
487 {
488 SetImageColorspace(image,LabColorspace,exception);
489 components[0]=jas_image_getcmptbytype(jp2_image,0);
490 components[1]=jas_image_getcmptbytype(jp2_image,1);
491 components[2]=jas_image_getcmptbytype(jp2_image,2);
492 if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
493 {
494 (void) jas_stream_close(jp2_stream);
495 jas_image_destroy(jp2_image);
496 ThrowReaderException(CorruptImageError,"MissingImageChannel");
497 }
498 number_components=3;
499 components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
500 if (components[3] > 0)
501 {
502 image->matte=MagickTrue;
503 number_components++;
504 }
505 break;
506 }
cristy3ed852e2009-09-05 21:47:34 +0000507 default:
508 {
509 (void) jas_stream_close(jp2_stream);
510 jas_image_destroy(jp2_image);
511 ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
512 }
513 }
cristybb503372010-05-27 20:51:26 +0000514 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000515 {
cristybb503372010-05-27 20:51:26 +0000516 size_t
cristy3ed852e2009-09-05 21:47:34 +0000517 height,
518 width;
519
cristybb503372010-05-27 20:51:26 +0000520 width=(size_t) (jas_image_cmptwidth(jp2_image,components[i])*
cristy3ed852e2009-09-05 21:47:34 +0000521 jas_image_cmpthstep(jp2_image,components[i]));
cristybb503372010-05-27 20:51:26 +0000522 height=(size_t) (jas_image_cmptheight(jp2_image,components[i])*
cristy3ed852e2009-09-05 21:47:34 +0000523 jas_image_cmptvstep(jp2_image,components[i]));
cristy30faca22009-09-29 13:49:52 +0000524 x_step[i]=(unsigned int) jas_image_cmpthstep(jp2_image,components[i]);
525 y_step[i]=(unsigned int) jas_image_cmptvstep(jp2_image,components[i]);
cristy3ed852e2009-09-05 21:47:34 +0000526 if ((width != image->columns) || (height != image->rows) ||
527 (jas_image_cmpttlx(jp2_image,components[i]) != 0) ||
cristy30faca22009-09-29 13:49:52 +0000528 (jas_image_cmpttly(jp2_image,components[i]) != 0) ||
cristy30faca22009-09-29 13:49:52 +0000529 (jas_image_cmptsgnd(jp2_image,components[i]) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +0000530 {
531 (void) jas_stream_close(jp2_stream);
532 jas_image_destroy(jp2_image);
533 ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported");
534 }
cristy3ed852e2009-09-05 21:47:34 +0000535 }
536 /*
537 Convert JPEG 2000 pixels.
538 */
539 image->matte=number_components > 3 ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000540 maximum_component_depth=0;
cristybb503372010-05-27 20:51:26 +0000541 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000542 {
543 maximum_component_depth=(unsigned int) MagickMax((size_t)
544 jas_image_cmptprec(jp2_image,components[i]),(size_t)
545 maximum_component_depth);
546 pixels[i]=jas_matrix_create(1,(int) (image->columns/x_step[i]));
547 if (pixels[i] == (jas_matrix_t *) NULL)
548 {
cristy30faca22009-09-29 13:49:52 +0000549 for (--i; i >= 0; i--)
550 jas_matrix_destroy(pixels[i]);
cristy3ed852e2009-09-05 21:47:34 +0000551 jas_image_destroy(jp2_image);
552 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
553 }
554 }
cristy30faca22009-09-29 13:49:52 +0000555 image->depth=maximum_component_depth;
556 if (image_info->ping != MagickFalse)
557 {
558 (void) jas_stream_close(jp2_stream);
559 jas_image_destroy(jp2_image);
560 return(GetFirstImageInList(image));
561 }
cristybb503372010-05-27 20:51:26 +0000562 for (i=0; i < (ssize_t) number_components; i++)
563 range[i]=GetQuantumRange((size_t) jas_image_cmptprec(jp2_image,
cristy3ed852e2009-09-05 21:47:34 +0000564 components[i]));
cristybb503372010-05-27 20:51:26 +0000565 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000566 {
567 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000568 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000569 break;
cristybb503372010-05-27 20:51:26 +0000570 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000571 (void) jas_image_readcmpt(jp2_image,(short) components[i],0,
cristyf6fe0a12010-05-30 00:44:47 +0000572 (jas_image_coord_t) (y/y_step[i]),(jas_image_coord_t) (image->columns/
573 x_step[i]),1,pixels[i]);
cristy3ed852e2009-09-05 21:47:34 +0000574 switch (number_components)
575 {
576 case 1:
577 {
578 /*
579 Grayscale.
580 */
cristybb503372010-05-27 20:51:26 +0000581 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000582 {
583 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
cristyaf6eb932012-01-01 01:22:59 +0000584 SetPixelGray(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
cristyed231572011-07-14 02:18:59 +0000585 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000586 }
587 break;
588 }
589 case 3:
590 {
591 /*
592 RGB.
593 */
cristybb503372010-05-27 20:51:26 +0000594 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000595 {
596 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
cristy4c08aed2011-07-01 19:47:50 +0000597 SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
cristy3ed852e2009-09-05 21:47:34 +0000598 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
cristy4c08aed2011-07-01 19:47:50 +0000599 SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
cristy3ed852e2009-09-05 21:47:34 +0000600 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
cristy4c08aed2011-07-01 19:47:50 +0000601 SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
cristyed231572011-07-14 02:18:59 +0000602 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000603 }
604 break;
605 }
606 case 4:
607 {
608 /*
609 RGBA.
610 */
cristybb503372010-05-27 20:51:26 +0000611 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000612 {
613 pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
cristy4c08aed2011-07-01 19:47:50 +0000614 SetPixelRed(image,ScaleAnyToQuantum((QuantumAny) pixel,range[0]),q);
cristy3ed852e2009-09-05 21:47:34 +0000615 pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
cristy4c08aed2011-07-01 19:47:50 +0000616 SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny) pixel,range[1]),q);
cristy3ed852e2009-09-05 21:47:34 +0000617 pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
cristy4c08aed2011-07-01 19:47:50 +0000618 SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny) pixel,range[2]),q);
cristy3ed852e2009-09-05 21:47:34 +0000619 pixel=(QuantumAny) jas_matrix_getv(pixels[3],x/x_step[3]);
cristy4c08aed2011-07-01 19:47:50 +0000620 SetPixelAlpha(image,ScaleAnyToQuantum((QuantumAny) pixel,range[3]),q);
cristyed231572011-07-14 02:18:59 +0000621 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000622 }
623 break;
624 }
625 }
626 if (SyncAuthenticPixels(image,exception) == MagickFalse)
627 break;
cristycee97112010-05-28 00:44:52 +0000628 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000629 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000630 if (status == MagickFalse)
631 break;
632 }
633 cm_profile=jas_image_cmprof(jp2_image);
634 icc_profile=(jas_iccprof_t *) NULL;
635 if (cm_profile != (jas_cmprof_t *) NULL)
636 icc_profile=jas_iccprof_createfromcmprof(cm_profile);
637 if (icc_profile != (jas_iccprof_t *) NULL)
638 {
639 jas_stream_t
640 *icc_stream;
641
642 icc_stream=jas_stream_memopen(NULL,0);
643 if ((icc_stream != (jas_stream_t *) NULL) &&
644 (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
645 (jas_stream_flush(icc_stream) == 0))
646 {
647 StringInfo
648 *icc_profile,
649 *profile;
650
651 jas_stream_memobj_t
652 *blob;
653
654 /*
655 Extract the icc profile, handle errors without much noise.
656 */
657 blob=(jas_stream_memobj_t *) icc_stream->obj_;
658 if (image->debug != MagickFalse)
659 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000660 "Profile: ICC, %.20g bytes",(double) blob->len_);
cristy9631d122011-09-01 13:28:16 +0000661 profile=BlobToStringInfo(blob->buf_,blob->len_);
662 if (profile == (StringInfo *) NULL)
663 ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000664 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
665 if (icc_profile == (StringInfo *) NULL)
cristyd15e6592011-10-15 00:13:06 +0000666 (void) SetImageProfile(image,"icc",profile,exception);
cristy3ed852e2009-09-05 21:47:34 +0000667 else
668 (void) ConcatenateStringInfo(icc_profile,profile);
669 profile=DestroyStringInfo(profile);
670 (void) jas_stream_close(icc_stream);
671 }
672 }
673 (void) jas_stream_close(jp2_stream);
674 jas_image_destroy(jp2_image);
cristybb503372010-05-27 20:51:26 +0000675 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000676 jas_matrix_destroy(pixels[i]);
677 return(GetFirstImageInList(image));
678}
679#endif
680
681/*
682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683% %
684% %
685% %
686% R e g i s t e r J P 2 I m a g e %
687% %
688% %
689% %
690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691%
692% RegisterJP2Image() adds attributes for the JP2 image format to the list of
693% supported formats. The attributes include the image format tag, a method
694% method to read and/or write the format, whether the format supports the
695% saving of more than one frame to the same file or blob, whether the format
696% supports native in-memory I/O, and a brief description of the format.
697%
698% The format of the RegisterJP2Image method is:
699%
cristybb503372010-05-27 20:51:26 +0000700% size_t RegisterJP2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000701%
702*/
cristybb503372010-05-27 20:51:26 +0000703ModuleExport size_t RegisterJP2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000704{
705 MagickInfo
706 *entry;
707
708 entry=SetMagickInfo("JP2");
709 entry->description=ConstantString("JPEG-2000 File Format Syntax");
710 entry->module=ConstantString("JP2");
711 entry->magick=(IsImageFormatHandler *) IsJP2;
712 entry->adjoin=MagickFalse;
713 entry->seekable_stream=MagickTrue;
714 entry->thread_support=NoThreadSupport;
715#if defined(MAGICKCORE_JP2_DELEGATE)
716 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
717 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
718#endif
719 (void) RegisterMagickInfo(entry);
720 entry=SetMagickInfo("JPC");
721 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
cristy02f1fda2009-12-10 15:23:56 +0000722 entry->module=ConstantString("JP2");
723 entry->magick=(IsImageFormatHandler *) IsJPC;
724 entry->adjoin=MagickFalse;
725 entry->seekable_stream=MagickTrue;
726 entry->thread_support=NoThreadSupport;
727#if defined(MAGICKCORE_JP2_DELEGATE)
728 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
729 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
730#endif
731 (void) RegisterMagickInfo(entry);
732 entry=SetMagickInfo("J2C");
733 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
734 entry->module=ConstantString("JP2");
cristy3ed852e2009-09-05 21:47:34 +0000735 entry->magick=(IsImageFormatHandler *) IsJPC;
736 entry->adjoin=MagickFalse;
737 entry->seekable_stream=MagickTrue;
738 entry->thread_support=NoThreadSupport;
739#if defined(MAGICKCORE_JP2_DELEGATE)
740 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
741 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
742#endif
743 (void) RegisterMagickInfo(entry);
cristy9bfeb942012-05-10 12:07:32 +0000744 entry=SetMagickInfo("J2K");
745 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
746 entry->module=ConstantString("JP2");
747 entry->magick=(IsImageFormatHandler *) IsJPC;
748 entry->adjoin=MagickFalse;
749 entry->seekable_stream=MagickTrue;
750 entry->thread_support=NoThreadSupport;
751#if defined(MAGICKCORE_JP2_DELEGATE)
752 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
753 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
754#endif
755 (void) RegisterMagickInfo(entry);
cristy3ed852e2009-09-05 21:47:34 +0000756 entry=SetMagickInfo("JPX");
757 entry->description=ConstantString("JPEG-2000 File Format Syntax");
cristy02f1fda2009-12-10 15:23:56 +0000758 entry->module=ConstantString("JP2");
cristy3ed852e2009-09-05 21:47:34 +0000759 entry->magick=(IsImageFormatHandler *) IsJPC;
760 entry->adjoin=MagickFalse;
761 entry->seekable_stream=MagickTrue;
762 entry->thread_support=NoThreadSupport;
763#if defined(MAGICKCORE_JP2_DELEGATE)
764 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
765 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
766#endif
767 (void) RegisterMagickInfo(entry);
768 entry=SetMagickInfo("PGX");
769 entry->description=ConstantString("JPEG-2000 VM Format");
cristy02f1fda2009-12-10 15:23:56 +0000770 entry->module=ConstantString("JP2");
cristy3ed852e2009-09-05 21:47:34 +0000771 entry->magick=(IsImageFormatHandler *) IsJPC;
772 entry->adjoin=MagickFalse;
773 entry->seekable_stream=MagickTrue;
774 entry->thread_support=NoThreadSupport;
775#if defined(MAGICKCORE_JP2_DELEGATE)
776 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
777#endif
778 (void) RegisterMagickInfo(entry);
779#if defined(MAGICKCORE_JP2_DELEGATE)
cristy1e09ca22009-12-27 18:04:58 +0000780 if (instantiate_jp2 == MagickFalse)
781 {
782 jas_init();
783 instantiate_jp2=MagickTrue;
784 }
cristy3ed852e2009-09-05 21:47:34 +0000785#endif
786 return(MagickImageCoderSignature);
787}
788
789/*
790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
791% %
792% %
793% %
794% U n r e g i s t e r J P 2 I m a g e %
795% %
796% %
797% %
798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799%
800% UnregisterJP2Image() removes format registrations made by the JP2 module
801% from the list of supported formats.
802%
803% The format of the UnregisterJP2Image method is:
804%
805% UnregisterJP2Image(void)
806%
807*/
808ModuleExport void UnregisterJP2Image(void)
809{
cristy3ed852e2009-09-05 21:47:34 +0000810 (void) UnregisterMagickInfo("PGX");
cristy9bfeb942012-05-10 12:07:32 +0000811 (void) UnregisterMagickInfo("J2K");
cristy02f1fda2009-12-10 15:23:56 +0000812 (void) UnregisterMagickInfo("J2C");
813 (void) UnregisterMagickInfo("JPC");
814 (void) UnregisterMagickInfo("JP2");
cristy3ed852e2009-09-05 21:47:34 +0000815#if defined(MAGICKCORE_JP2_DELEGATE)
cristy1e09ca22009-12-27 18:04:58 +0000816 if (instantiate_jp2 != MagickFalse)
817 {
cristy992729d2010-01-01 15:45:06 +0000818 jas_cleanup();
cristy1e09ca22009-12-27 18:04:58 +0000819 instantiate_jp2=MagickFalse;
820 }
cristy3ed852e2009-09-05 21:47:34 +0000821#endif
822}
823
824#if defined(MAGICKCORE_JP2_DELEGATE)
825/*
826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
827% %
828% %
829% %
830% W r i t e J P 2 I m a g e %
831% %
832% %
833% %
834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835%
836% WriteJP2Image() writes an image in the JPEG 2000 image format.
837%
838% JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
839%
840% The format of the WriteJP2Image method is:
841%
cristy1e178e72011-08-28 19:44:34 +0000842% MagickBooleanType WriteJP2Image(const ImageInfo *image_info,
843% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000844%
845% A description of each parameter follows.
846%
847% o image_info: the image info.
848%
849% o image: The image.
850%
cristy1e178e72011-08-28 19:44:34 +0000851% o exception: return any errors or warnings in this structure.
852%
cristy3ed852e2009-09-05 21:47:34 +0000853*/
cristy1e178e72011-08-28 19:44:34 +0000854static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
855 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000856{
857 char
858 *key,
859 magick[MaxTextExtent],
860 *options;
861
862 const char
863 *option;
864
cristy3ed852e2009-09-05 21:47:34 +0000865 jas_image_cmptparm_t
866 component_info[4];
867
868 jas_image_t
869 *jp2_image;
870
871 jas_matrix_t
872 *pixels[4];
873
874 jas_stream_t
875 *jp2_stream;
876
877 MagickBooleanType
878 status;
879
cristy18f8ee42009-09-30 01:04:36 +0000880 QuantumAny
881 range;
882
cristy4c08aed2011-07-01 19:47:50 +0000883 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000884 *p;
885
cristybb503372010-05-27 20:51:26 +0000886 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000887 i,
888 x;
889
cristybb503372010-05-27 20:51:26 +0000890 size_t
cristy3ed852e2009-09-05 21:47:34 +0000891 number_components;
892
cristy524222d2011-04-25 00:37:06 +0000893 ssize_t
894 format,
895 y;
896
cristy3ed852e2009-09-05 21:47:34 +0000897 /*
898 Open image file.
899 */
900 assert(image_info != (const ImageInfo *) NULL);
901 assert(image_info->signature == MagickSignature);
902 assert(image != (Image *) NULL);
903 assert(image->signature == MagickSignature);
904 if (image->debug != MagickFalse)
905 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000906 assert(exception != (ExceptionInfo *) NULL);
907 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000908 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000909 if (status == MagickFalse)
910 return(status);
911 /*
glennrpbca49a22011-07-01 12:18:22 +0000912 Initialize JPEG 2000 API.
cristy3ed852e2009-09-05 21:47:34 +0000913 */
cristyd9ecd042012-06-17 18:26:12 +0000914 if ((IssRGBColorspace(image->colorspace) == MagickFalse) &&
915 (IsImageGray(image,exception) == MagickFalse))
cristy8d951092012-02-08 18:54:56 +0000916 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000917 jp2_stream=JP2StreamManager(image);
918 if (jp2_stream == (jas_stream_t *) NULL)
919 ThrowWriterException(DelegateError,"UnableToManageJP2Stream");
920 number_components=image->matte ? 4UL : 3UL;
cristy0ea80f82012-05-24 18:47:10 +0000921 if (IsGrayColorspace(image->colorspace) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000922 number_components=1;
923 if ((image->columns != (unsigned int) image->columns) ||
924 (image->rows != (unsigned int) image->rows))
925 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
cristy30faca22009-09-29 13:49:52 +0000926 (void) ResetMagickMemory(&component_info,0,sizeof(component_info));
cristybb503372010-05-27 20:51:26 +0000927 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000928 {
929 component_info[i].tlx=0;
930 component_info[i].tly=0;
931 component_info[i].hstep=1;
932 component_info[i].vstep=1;
933 component_info[i].width=(unsigned int) image->columns;
934 component_info[i].height=(unsigned int) image->rows;
cristy30faca22009-09-29 13:49:52 +0000935 component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2);
cristy3ed852e2009-09-05 21:47:34 +0000936 component_info[i].sgnd=MagickFalse;
937 }
938 jp2_image=jas_image_create((int) number_components,component_info,
939 JAS_CLRSPC_UNKNOWN);
940 if (jp2_image == (jas_image_t *) NULL)
941 ThrowWriterException(DelegateError,"UnableToCreateImage");
cristy0ea80f82012-05-24 18:47:10 +0000942 switch (image->colorspace)
943 {
944 case RGBColorspace:
945 case sRGBColorspace:
cristy3ed852e2009-09-05 21:47:34 +0000946 {
947 /*
cristya2ad7242012-05-25 12:57:25 +0000948 RGB colorspace.
cristy3ed852e2009-09-05 21:47:34 +0000949 */
cristy3ed852e2009-09-05 21:47:34 +0000950 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB);
951 jas_image_setcmpttype(jp2_image,0,
cristy722af032009-12-04 01:50:06 +0000952 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
cristy3ed852e2009-09-05 21:47:34 +0000953 jas_image_setcmpttype(jp2_image,1,
cristy722af032009-12-04 01:50:06 +0000954 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
cristy3ed852e2009-09-05 21:47:34 +0000955 jas_image_setcmpttype(jp2_image,2,
cristy722af032009-12-04 01:50:06 +0000956 (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
cristy30faca22009-09-29 13:49:52 +0000957 if (number_components == 4)
958 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
cristy0ea80f82012-05-24 18:47:10 +0000959 break;
cristy3ed852e2009-09-05 21:47:34 +0000960 }
cristy0ea80f82012-05-24 18:47:10 +0000961 case GRAYColorspace:
962 {
963 /*
cristya2ad7242012-05-25 12:57:25 +0000964 Grayscale colorspace.
cristy0ea80f82012-05-24 18:47:10 +0000965 */
966 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY);
967 jas_image_setcmpttype(jp2_image,0,
968 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
969 break;
970 }
971 case YCbCrColorspace:
972 {
973 /*
cristya2ad7242012-05-25 12:57:25 +0000974 YCbCr colorspace.
cristy0ea80f82012-05-24 18:47:10 +0000975 */
976 jas_image_setclrspc(jp2_image,JAS_CLRSPC_SYCBCR);
977 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
978 JAS_IMAGE_CT_COLOR(0));
979 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
980 JAS_IMAGE_CT_COLOR(1));
981 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
982 JAS_IMAGE_CT_COLOR(2));
983 if (number_components == 4)
984 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
985 break;
986 }
987 case XYZColorspace:
988 {
989 /*
cristya2ad7242012-05-25 12:57:25 +0000990 XYZ colorspace.
cristy0ea80f82012-05-24 18:47:10 +0000991 */
992 jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIEXYZ);
993 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
994 JAS_IMAGE_CT_COLOR(0));
995 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
996 JAS_IMAGE_CT_COLOR(1));
997 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
998 JAS_IMAGE_CT_COLOR(2));
999 if (number_components == 4)
1000 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1001 break;
1002 }
1003 case LabColorspace:
1004 {
1005 /*
cristya2ad7242012-05-25 12:57:25 +00001006 Lab colorspace.
cristy0ea80f82012-05-24 18:47:10 +00001007 */
1008 jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIELAB);
1009 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1010 JAS_IMAGE_CT_COLOR(0));
1011 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1012 JAS_IMAGE_CT_COLOR(1));
1013 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1014 JAS_IMAGE_CT_COLOR(2));
1015 if (number_components == 4)
1016 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1017 break;
1018 }
1019 default:
1020 {
1021 /*
1022 Unknow.
1023 */
1024 jas_image_setclrspc(jp2_image,JAS_CLRSPC_UNKNOWN);
1025 jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t)
1026 JAS_IMAGE_CT_COLOR(0));
1027 jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t)
1028 JAS_IMAGE_CT_COLOR(1));
1029 jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t)
1030 JAS_IMAGE_CT_COLOR(2));
1031 if (number_components == 4)
1032 jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
1033 break;
1034 }
1035 }
cristy3ed852e2009-09-05 21:47:34 +00001036 /*
1037 Convert to JPEG 2000 pixels.
1038 */
cristybb503372010-05-27 20:51:26 +00001039 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001040 {
1041 pixels[i]=jas_matrix_create(1,(int) image->columns);
1042 if (pixels[i] == (jas_matrix_t *) NULL)
1043 {
1044 for (x=0; x < i; x++)
1045 jas_matrix_destroy(pixels[x]);
1046 jas_image_destroy(jp2_image);
1047 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1048 }
1049 }
cristybb503372010-05-27 20:51:26 +00001050 range=GetQuantumRange((size_t) component_info[0].prec);
1051 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001052 {
cristy1e178e72011-08-28 19:44:34 +00001053 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001054 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001055 break;
cristybb503372010-05-27 20:51:26 +00001056 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001057 {
1058 if (number_components == 1)
cristy722af032009-12-04 01:50:06 +00001059 jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
cristy4c08aed2011-07-01 19:47:50 +00001060 GetPixelIntensity(image,p),range));
cristy3ed852e2009-09-05 21:47:34 +00001061 else
1062 {
cristy4c08aed2011-07-01 19:47:50 +00001063 jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
1064 GetPixelRed(image,p),range));
1065 jas_matrix_setv(pixels[1],x,(jas_seqent_t) ScaleQuantumToAny(
1066 GetPixelGreen(image,p),range));
1067 jas_matrix_setv(pixels[2],x,(jas_seqent_t) ScaleQuantumToAny(
1068 GetPixelBlue(image,p),range));
cristy3ed852e2009-09-05 21:47:34 +00001069 if (number_components > 3)
cristy4c08aed2011-07-01 19:47:50 +00001070 jas_matrix_setv(pixels[3],x,(jas_seqent_t) ScaleQuantumToAny(
1071 GetPixelAlpha(image,p),range));
cristy3ed852e2009-09-05 21:47:34 +00001072 }
cristyed231572011-07-14 02:18:59 +00001073 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001074 }
cristybb503372010-05-27 20:51:26 +00001075 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001076 (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y,
1077 (unsigned int) image->columns,1,pixels[i]);
cristycee97112010-05-28 00:44:52 +00001078 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +00001079 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001080 if (status == MagickFalse)
1081 break;
1082 }
1083 (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
cristy02f1fda2009-12-10 15:23:56 +00001084 if (LocaleCompare(magick,"J2C") == 0)
1085 (void) CopyMagickString(magick,"JPC",MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00001086 LocaleLower(magick);
1087 format=jas_image_strtofmt(magick);
1088 options=(char *) NULL;
1089 ResetImageOptionIterator(image_info);
1090 key=GetNextImageOption(image_info);
cristy722af032009-12-04 01:50:06 +00001091 for ( ; key != (char *) NULL; key=GetNextImageOption(image_info))
cristy3ed852e2009-09-05 21:47:34 +00001092 {
1093 option=GetImageOption(image_info,key);
cristy722af032009-12-04 01:50:06 +00001094 if (option == (const char *) NULL)
1095 continue;
1096 if (LocaleNCompare(key,"jp2:",4) == 0)
cristy3ed852e2009-09-05 21:47:34 +00001097 {
cristy722af032009-12-04 01:50:06 +00001098 (void) ConcatenateString(&options,key+4);
1099 if (*option != '\0')
cristy3ed852e2009-09-05 21:47:34 +00001100 {
cristy722af032009-12-04 01:50:06 +00001101 (void) ConcatenateString(&options,"=");
1102 (void) ConcatenateString(&options,option);
cristy3ed852e2009-09-05 21:47:34 +00001103 }
cristy722af032009-12-04 01:50:06 +00001104 (void) ConcatenateString(&options," ");
1105 }
cristy3ed852e2009-09-05 21:47:34 +00001106 }
1107 option=GetImageOption(image_info,"jp2:rate");
1108 if ((option == (const char *) NULL) &&
1109 (image_info->compression != LosslessJPEGCompression) &&
1110 (image->quality != UndefinedCompressionQuality) &&
cristy30faca22009-09-29 13:49:52 +00001111 ((double) image->quality <= 99.5) &&
1112 ((image->rows*image->columns) > 2500))
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 char
1115 option[MaxTextExtent];
1116
1117 double
1118 alpha,
1119 header_size,
1120 number_pixels,
1121 rate,
1122 target_size;
1123
1124 alpha=115.0-image->quality;
1125 rate=100.0/(alpha*alpha);
1126 header_size=550.0;
1127 header_size+=(number_components-1)*142;
1128 number_pixels=(double) image->rows*image->columns*number_components*
1129 (GetImageQuantumDepth(image,MagickTrue)/8);
1130 target_size=(number_pixels*rate)+header_size;
1131 rate=target_size/number_pixels;
cristyb51dff52011-05-19 16:55:47 +00001132 (void) FormatLocaleString(option,MaxTextExtent,"rate=%g",rate);
cristy3ed852e2009-09-05 21:47:34 +00001133 (void) ConcatenateString(&options,option);
1134 }
1135 status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ?
1136 MagickTrue : MagickFalse;
cristy3dfccb22011-12-28 21:47:20 +00001137 if (options != (char *) NULL)
1138 options=DestroyString(options);
cristy3ed852e2009-09-05 21:47:34 +00001139 (void) jas_stream_close(jp2_stream);
cristybb503372010-05-27 20:51:26 +00001140 for (i=0; i < (ssize_t) number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001141 jas_matrix_destroy(pixels[i]);
1142 jas_image_destroy(jp2_image);
1143 if (status != MagickFalse)
1144 ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1145 return(MagickTrue);
1146}
1147#endif