blob: 7fe539620a09ac00428164de33ac1a088ed7647a [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% %
cristyde984cd2013-12-01 14:49:27 +000015% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000016% Nathan Brown %
17% June 2001 %
18% %
19% %
cristyfe676ee2013-11-18 13:03:38 +000020% Copyright 1999-2014 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*/
cristy25997252014-01-02 13:28:18 +000042#include "magick/studio.h"
43#include "magick/artifact.h"
44#include "magick/attribute.h"
45#include "magick/blob.h"
46#include "magick/blob-private.h"
47#include "magick/cache.h"
48#include "magick/colorspace.h"
49#include "magick/colorspace-private.h"
50#include "magick/color.h"
51#include "magick/color-private.h"
52#include "magick/exception.h"
53#include "magick/exception-private.h"
54#include "magick/image.h"
55#include "magick/image-private.h"
56#include "magick/list.h"
57#include "magick/magick.h"
58#include "magick/memory_.h"
59#include "magick/monitor.h"
60#include "magick/monitor-private.h"
61#include "magick/option.h"
62#include "magick/pixel-accessor.h"
63#include "magick/profile.h"
64#include "magick/quantum-private.h"
65#include "magick/static.h"
66#include "magick/statistic.h"
67#include "magick/string_.h"
cristy77559f42014-01-02 18:54:04 +000068#include "magick/string-private.h"
cristy25997252014-01-02 13:28:18 +000069#include "magick/module.h"
70#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
71#include <openjpeg.h>
cristy3ed852e2009-09-05 21:47:34 +000072#endif
73
74/*
75 Forward declarations.
76*/
cristy25997252014-01-02 13:28:18 +000077#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
cristy3ed852e2009-09-05 21:47:34 +000078static MagickBooleanType
cristy25997252014-01-02 13:28:18 +000079 WriteJP2Image(const ImageInfo *,Image *);
cristy3ed852e2009-09-05 21:47:34 +000080#endif
81
82/*
83%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84% %
85% %
86% %
cristyb5a97912014-01-02 15:52:07 +000087% I s J 2 K %
88% %
89% %
90% %
91%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92%
93% IsJ2K() returns MagickTrue if the image format type, identified by the
94% magick string, is J2K.
95%
96% The format of the IsJ2K method is:
97%
98% MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
99%
100% A description of each parameter follows:
101%
102% o magick: compare image format pattern against these bytes.
103%
104% o length: Specifies the length of the magick string.
105%
106*/
107static MagickBooleanType IsJ2K(const unsigned char *magick,const size_t length)
108{
109 if (length < 4)
110 return(MagickFalse);
111 if (memcmp(magick,"\xff\x4f\xff\x51",4) == 0)
112 return(MagickTrue);
113 return(MagickFalse);
114}
115
116/*
117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118% %
119% %
120% %
cristy3ed852e2009-09-05 21:47:34 +0000121% I s J P 2 %
122% %
123% %
124% %
125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126%
127% IsJP2() returns MagickTrue if the image format type, identified by the
128% magick string, is JP2.
129%
130% The format of the IsJP2 method is:
131%
132% MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
133%
134% A description of each parameter follows:
135%
136% o magick: compare image format pattern against these bytes.
137%
138% o length: Specifies the length of the magick string.
139%
140*/
141static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
142{
cristyb5a97912014-01-02 15:52:07 +0000143 if (length < 12)
cristy3ed852e2009-09-05 21:47:34 +0000144 return(MagickFalse);
cristyb5a97912014-01-02 15:52:07 +0000145 if (memcmp(magick,"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a",12) == 0)
146 return(MagickTrue);
147 if (memcmp(magick,"\x0d\x0a\x87\x0a",12) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000148 return(MagickTrue);
149 return(MagickFalse);
150}
151
152/*
153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154% %
155% %
156% %
157% I s J P C %
158% %
159% %
160% %
161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162%
163% IsJPC()() returns MagickTrue if the image format type, identified by the
164% magick string, is JPC.
165%
166% The format of the IsJPC method is:
167%
168% MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
169%
170% A description of each parameter follows:
171%
172% o magick: compare image format pattern against these bytes.
173%
174% o length: Specifies the length of the magick string.
175%
176*/
177static MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
178{
cristyb5a97912014-01-02 15:52:07 +0000179 if (length < 12)
cristy3ed852e2009-09-05 21:47:34 +0000180 return(MagickFalse);
cristyb5a97912014-01-02 15:52:07 +0000181 if (memcmp(magick,"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a",12) == 0)
182 return(MagickTrue);
183 if (memcmp(magick,"\x0d\x0a\x87\x0a",12) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000184 return(MagickTrue);
185 return(MagickFalse);
186}
187
188/*
189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190% %
191% %
192% %
193% R e a d J P 2 I m a g e %
194% %
195% %
196% %
197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198%
199% ReadJP2Image() reads a JPEG 2000 Image file (JP2) or JPEG 2000
200% codestream (JPC) image file and returns it. It allocates the memory
201% necessary for the new Image structure and returns a pointer to the new
202% image or set of images.
203%
204% JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
205%
206% The format of the ReadJP2Image method is:
207%
208% Image *ReadJP2Image(const ImageInfo *image_info,
209% ExceptionInfo *exception)
210%
211% A description of each parameter follows:
212%
213% o image_info: the image info.
214%
215% o exception: return any errors or warnings in this structure.
216%
217*/
cristy25997252014-01-02 13:28:18 +0000218#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
219static void JP2ErrorHandler(const char *message,void *client_data)
cristy3ed852e2009-09-05 21:47:34 +0000220{
cristy25997252014-01-02 13:28:18 +0000221 ExceptionInfo
222 *exception;
cristy3ed852e2009-09-05 21:47:34 +0000223
cristy25997252014-01-02 13:28:18 +0000224 exception=(ExceptionInfo *) client_data;
225 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
226 message,"`%s'","OpenJP2");
227}
228
229static OPJ_SIZE_T JP2ReadHandler(void *buffer,OPJ_SIZE_T length,void *context)
230{
cristy3ed852e2009-09-05 21:47:34 +0000231 Image
232 *image;
cristy3ed852e2009-09-05 21:47:34 +0000233
cristy3ed852e2009-09-05 21:47:34 +0000234 ssize_t
235 count;
236
cristy25997252014-01-02 13:28:18 +0000237 image=(Image *) context;
238 count=ReadBlob(image,(ssize_t) length,(unsigned char *) buffer);
239 if (count == 0)
240 return(-1);
241 return((OPJ_SIZE_T) count);
cristy3ed852e2009-09-05 21:47:34 +0000242}
243
cristy25997252014-01-02 13:28:18 +0000244static OPJ_BOOL JP2SeekHandler(OPJ_OFF_T offset,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000245{
cristy25997252014-01-02 13:28:18 +0000246 Image
247 *image;
248
249 image=(Image *) context;
cristyccfccd22014-01-03 01:17:13 +0000250 return(SeekBlob(image,offset,SEEK_SET) < 0 ? 0 : 1);
cristy25997252014-01-02 13:28:18 +0000251}
252
253static OPJ_OFF_T JP2SkipHandler(OPJ_OFF_T length,void *context)
254{
255 Image
256 *image;
257
258 image=(Image *) context;
259 if (DiscardBlobBytes(image,(size_t) length) == MagickFalse)
260 return(0);
261 return(length);
262}
263
264static void JP2WarningHandler(const char *message,void *client_data)
265{
266 ExceptionInfo
267 *exception;
268
269 exception=(ExceptionInfo *) client_data;
270 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
271 message,"`%s'","OpenJP2");
272}
273
274static OPJ_SIZE_T JP2WriteHandler(void *buffer,OPJ_SIZE_T length,void *context)
275{
276 Image
277 *image;
278
cristy3ed852e2009-09-05 21:47:34 +0000279 ssize_t
280 count;
281
cristy25997252014-01-02 13:28:18 +0000282 image=(Image *) context;
283 count=WriteBlob(image,(ssize_t) length,(unsigned char *) buffer);
284 return((OPJ_SIZE_T) count);
cristy3ed852e2009-09-05 21:47:34 +0000285}
286
287static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
288{
cristy77559f42014-01-02 18:54:04 +0000289 const char
290 *option;
291
cristy3ed852e2009-09-05 21:47:34 +0000292 Image
293 *image;
294
cristy25997252014-01-02 13:28:18 +0000295 int
cristy25997252014-01-02 13:28:18 +0000296 jp2_status;
cristy3ed852e2009-09-05 21:47:34 +0000297
298 MagickBooleanType
299 status;
300
cristy25997252014-01-02 13:28:18 +0000301 opj_codec_t
302 *jp2_codec;
cristy3ed852e2009-09-05 21:47:34 +0000303
cristy6c0f1502014-01-02 13:53:25 +0000304 opj_codestream_index_t
305 *codestream_index = (opj_codestream_index_t *) NULL;
306
cristy25997252014-01-02 13:28:18 +0000307 opj_dparameters_t
308 parameters;
309
310 opj_image_t
311 *jp2_image;
312
313 opj_stream_t
314 *jp2_stream;
cristy48ac1c32012-10-19 23:55:43 +0000315
cristybb503372010-05-27 20:51:26 +0000316 register ssize_t
cristy25997252014-01-02 13:28:18 +0000317 i;
cristy3ed852e2009-09-05 21:47:34 +0000318
cristy524222d2011-04-25 00:37:06 +0000319 ssize_t
cristy524222d2011-04-25 00:37:06 +0000320 y;
321
cristy3ed852e2009-09-05 21:47:34 +0000322 /*
323 Open image file.
324 */
325 assert(image_info != (const ImageInfo *) NULL);
326 assert(image_info->signature == MagickSignature);
327 if (image_info->debug != MagickFalse)
328 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
329 image_info->filename);
330 assert(exception != (ExceptionInfo *) NULL);
331 assert(exception->signature == MagickSignature);
cristy25997252014-01-02 13:28:18 +0000332 image=AcquireImage(image_info);
cristy3ed852e2009-09-05 21:47:34 +0000333 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
334 if (status == MagickFalse)
335 {
336 image=DestroyImageList(image);
337 return((Image *) NULL);
338 }
339 /*
cristy25997252014-01-02 13:28:18 +0000340 Initialize JP2 codec.
cristy3ed852e2009-09-05 21:47:34 +0000341 */
cristy25997252014-01-02 13:28:18 +0000342 if (LocaleCompare(image_info->magick,"JPT") == 0)
343 jp2_codec=opj_create_decompress(OPJ_CODEC_JPT);
344 else
345 if (LocaleCompare(image_info->magick,"J2K") == 0)
346 jp2_codec=opj_create_decompress(OPJ_CODEC_J2K);
347 else
348 jp2_codec=opj_create_decompress(OPJ_CODEC_JP2);
349 opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
350 opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
351 opj_set_default_decoder_parameters(&parameters);
cristya13e3672014-01-02 15:24:44 +0000352 option=GetImageOption(image_info,"jp2:reduce-factor");
353 if (option != (const char *) NULL)
354 parameters.cp_reduce=StringToInteger(option);
355 option=GetImageOption(image_info,"jp2:quality-layers");
356 if (option != (const char *) NULL)
357 parameters.cp_layer=StringToInteger(option);
cristy25997252014-01-02 13:28:18 +0000358 if (opj_setup_decoder(jp2_codec,&parameters) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000359 {
cristy25997252014-01-02 13:28:18 +0000360 opj_destroy_codec(jp2_codec);
361 ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
362 }
cristy66d40562014-01-03 01:27:44 +0000363 jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,1);
cristy25997252014-01-02 13:28:18 +0000364 opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
365 opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
366 opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
367 opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
368 opj_stream_set_user_data(jp2_stream,image);
369 opj_stream_set_user_data_length(jp2_stream,GetBlobSize(image));
370 if (opj_read_header(jp2_stream,jp2_codec,&jp2_image) == 0)
371 {
372 opj_stream_set_user_data(jp2_stream,NULL);
373 opj_stream_destroy_v3(jp2_stream);
374 opj_destroy_codec(jp2_codec);
cristy3ed852e2009-09-05 21:47:34 +0000375 ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
376 }
cristya8997c22014-01-03 00:55:02 +0000377 if ((image->columns != 0) && (image->rows != 0))
cristy25997252014-01-02 13:28:18 +0000378 {
cristy56e4faf2014-01-02 17:59:34 +0000379 /*
380 Extract an area from the image.
381 */
cristya8997c22014-01-03 00:55:02 +0000382 jp2_status=opj_set_decode_area(jp2_codec,jp2_image,image->extract_info.x,
cristy707e04c2014-01-03 01:01:18 +0000383 image->extract_info.y,image->extract_info.x+image->columns,
384 image->extract_info.y+image->rows);
cristy56e4faf2014-01-02 17:59:34 +0000385 if (jp2_status == 0)
386 {
387 opj_stream_set_user_data(jp2_stream,NULL);
388 opj_stream_destroy_v3(jp2_stream);
389 opj_destroy_codec(jp2_codec);
390 opj_image_destroy(jp2_image);
391 ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
392 }
cristy25997252014-01-02 13:28:18 +0000393 }
394 if ((opj_decode(jp2_codec,jp2_stream,jp2_image) == 0) ||
395 (opj_end_decompress(jp2_codec,jp2_stream) == 0))
396 {
397 opj_stream_set_user_data(jp2_stream,NULL);
398 opj_stream_destroy_v3(jp2_stream);
399 opj_destroy_codec(jp2_codec);
400 opj_image_destroy(jp2_image);
401 ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
402 }
403 opj_stream_set_user_data(jp2_stream,NULL);
404 opj_stream_destroy_v3(jp2_stream);
405 for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
cristy3ed852e2009-09-05 21:47:34 +0000406 {
cristy25997252014-01-02 13:28:18 +0000407 if ((jp2_image->comps[i].dx == 0) || (jp2_image->comps[i].dy == 0))
cristy3ed852e2009-09-05 21:47:34 +0000408 {
cristy25997252014-01-02 13:28:18 +0000409 opj_stream_set_user_data(jp2_stream,NULL);
410 opj_destroy_codec(jp2_codec);
411 opj_image_destroy(jp2_image);
412 ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported")
cristy3ed852e2009-09-05 21:47:34 +0000413 }
cristy3ed852e2009-09-05 21:47:34 +0000414 }
415 /*
cristy25997252014-01-02 13:28:18 +0000416 Convert JP2 image.
cristy3ed852e2009-09-05 21:47:34 +0000417 */
cristy25997252014-01-02 13:28:18 +0000418 image->columns=(size_t) jp2_image->comps[0].w;
419 image->rows=(size_t) jp2_image->comps[0].h;
420 image->compression=JPEG2000Compression;
421 if (jp2_image->numcomps <= 2)
cristy30faca22009-09-29 13:49:52 +0000422 {
cristy25997252014-01-02 13:28:18 +0000423 SetImageColorspace(image,GRAYColorspace);
424 if (jp2_image->numcomps > 1)
425 image->matte=MagickTrue;
cristy30faca22009-09-29 13:49:52 +0000426 }
cristy25997252014-01-02 13:28:18 +0000427 if (jp2_image->numcomps > 3)
428 image->matte=MagickTrue;
429 for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
430 {
431 if ((jp2_image->comps[i].dx == 0) || (jp2_image->comps[i].dy == 0))
432 {
433 opj_stream_set_user_data(jp2_stream,NULL);
434 opj_destroy_codec(jp2_codec);
435 opj_image_destroy(jp2_image);
436 ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported")
437 }
438 if ((jp2_image->comps[i].dx > 1) || (jp2_image->comps[i].dy > 1))
439 image->colorspace=YUVColorspace;
440 }
cristye173c292014-01-02 13:43:12 +0000441 if (jp2_image->icc_profile_buf != (unsigned char *) NULL)
442 {
443 StringInfo
444 *profile;
445
446 profile=BlobToStringInfo(jp2_image->icc_profile_buf,
447 jp2_image->icc_profile_len);
448 if (profile != (StringInfo *) NULL)
449 SetImageProfile(image,"icc",profile);
450 }
cristybb503372010-05-27 20:51:26 +0000451 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy25997252014-01-02 13:28:18 +0000453 register PixelPacket
454 *restrict q;
455
456 register ssize_t
457 x;
458
cristy3ed852e2009-09-05 21:47:34 +0000459 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
cristy25997252014-01-02 13:28:18 +0000460 if (q == (PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000461 break;
cristy25997252014-01-02 13:28:18 +0000462 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000463 {
cristy25997252014-01-02 13:28:18 +0000464 register ssize_t
465 i;
466
467 for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
cristy3ed852e2009-09-05 21:47:34 +0000468 {
cristy25997252014-01-02 13:28:18 +0000469 double
470 pixel,
471 scale;
472
473 scale=QuantumRange/(double) ((1UL << jp2_image->comps[i].prec)-1);
474 pixel=scale*(jp2_image->comps[i].data[y/jp2_image->comps[i].dy*
475 image->columns/jp2_image->comps[i].dx+x/jp2_image->comps[i].dx]+
476 (jp2_image->comps[i].sgnd ? 1UL << (jp2_image->comps[i].prec-1) : 0));
477 switch (i)
cristy3ed852e2009-09-05 21:47:34 +0000478 {
cristy25997252014-01-02 13:28:18 +0000479 case 0:
480 {
481 SetPixelRed(image,ClampToQuantum(pixel),q);
482 SetPixelGreen(image,ClampToQuantum(pixel),q);
483 SetPixelBlue(image,ClampToQuantum(pixel),q);
484 SetPixelAlpha(image,OpaqueAlpha,q);
485 break;
486 }
487 case 1:
488 {
489 if (jp2_image->numcomps == 2)
490 {
491 SetPixelAlpha(image,ClampToQuantum(pixel),q);
492 break;
493 }
494 SetPixelGreen(image,ClampToQuantum(pixel),q);
495 break;
496 }
497 case 2:
498 {
499 SetPixelBlue(image,ClampToQuantum(pixel),q);
500 break;
501 }
502 case 3:
503 {
504 SetPixelAlpha(image,ClampToQuantum(pixel),q);
505 break;
506 }
cristy3ed852e2009-09-05 21:47:34 +0000507 }
cristy3ed852e2009-09-05 21:47:34 +0000508 }
cristy25997252014-01-02 13:28:18 +0000509 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000510 }
511 if (SyncAuthenticPixels(image,exception) == MagickFalse)
512 break;
cristycee97112010-05-28 00:44:52 +0000513 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000514 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000515 if (status == MagickFalse)
516 break;
517 }
cristy25997252014-01-02 13:28:18 +0000518 /*
519 Free resources.
520 */
521 opj_destroy_codec(jp2_codec);
522 opj_image_destroy(jp2_image);
cristy6c0f1502014-01-02 13:53:25 +0000523 opj_destroy_cstr_index(&codestream_index);
cristy3ed852e2009-09-05 21:47:34 +0000524 return(GetFirstImageInList(image));
525}
526#endif
527
528/*
529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530% %
531% %
532% %
533% R e g i s t e r J P 2 I m a g e %
534% %
535% %
536% %
537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538%
539% RegisterJP2Image() adds attributes for the JP2 image format to the list of
540% supported formats. The attributes include the image format tag, a method
541% method to read and/or write the format, whether the format supports the
542% saving of more than one frame to the same file or blob, whether the format
543% supports native in-memory I/O, and a brief description of the format.
544%
545% The format of the RegisterJP2Image method is:
546%
cristybb503372010-05-27 20:51:26 +0000547% size_t RegisterJP2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000548%
549*/
cristybb503372010-05-27 20:51:26 +0000550ModuleExport size_t RegisterJP2Image(void)
cristy3ed852e2009-09-05 21:47:34 +0000551{
552 MagickInfo
553 *entry;
554
555 entry=SetMagickInfo("JP2");
556 entry->description=ConstantString("JPEG-2000 File Format Syntax");
cristy5aefbeb2013-08-09 12:13:32 +0000557 entry->mime_type=ConstantString("image/jp2");
cristy3ed852e2009-09-05 21:47:34 +0000558 entry->module=ConstantString("JP2");
559 entry->magick=(IsImageFormatHandler *) IsJP2;
560 entry->adjoin=MagickFalse;
561 entry->seekable_stream=MagickTrue;
562 entry->thread_support=NoThreadSupport;
cristy25997252014-01-02 13:28:18 +0000563#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
cristy3ed852e2009-09-05 21:47:34 +0000564 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
565 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
566#endif
567 (void) RegisterMagickInfo(entry);
cristy9bfeb942012-05-10 12:07:32 +0000568 entry=SetMagickInfo("J2K");
569 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
cristy5aefbeb2013-08-09 12:13:32 +0000570 entry->mime_type=ConstantString("image/jp2");
cristy9bfeb942012-05-10 12:07:32 +0000571 entry->module=ConstantString("JP2");
cristyb5a97912014-01-02 15:52:07 +0000572 entry->magick=(IsImageFormatHandler *) IsJ2K;
cristy9bfeb942012-05-10 12:07:32 +0000573 entry->adjoin=MagickFalse;
574 entry->seekable_stream=MagickTrue;
575 entry->thread_support=NoThreadSupport;
cristy25997252014-01-02 13:28:18 +0000576#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
cristy9bfeb942012-05-10 12:07:32 +0000577 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
578 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
579#endif
580 (void) RegisterMagickInfo(entry);
cristy25997252014-01-02 13:28:18 +0000581 entry=SetMagickInfo("JPT");
cristy3ed852e2009-09-05 21:47:34 +0000582 entry->description=ConstantString("JPEG-2000 File Format Syntax");
cristy5aefbeb2013-08-09 12:13:32 +0000583 entry->mime_type=ConstantString("image/jp2");
cristy02f1fda2009-12-10 15:23:56 +0000584 entry->module=ConstantString("JP2");
cristy25997252014-01-02 13:28:18 +0000585 entry->magick=(IsImageFormatHandler *) IsJP2;
cristy3ed852e2009-09-05 21:47:34 +0000586 entry->adjoin=MagickFalse;
587 entry->seekable_stream=MagickTrue;
588 entry->thread_support=NoThreadSupport;
cristy25997252014-01-02 13:28:18 +0000589#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
cristy3ed852e2009-09-05 21:47:34 +0000590 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
591 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
592#endif
593 (void) RegisterMagickInfo(entry);
cristy92f84a52014-01-02 15:10:12 +0000594 entry=SetMagickInfo("JPC");
595 entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
596 entry->mime_type=ConstantString("image/jp2");
597 entry->module=ConstantString("JP2");
598 entry->magick=(IsImageFormatHandler *) IsJPC;
599 entry->adjoin=MagickFalse;
600 entry->seekable_stream=MagickTrue;
601 entry->thread_support=NoThreadSupport;
602#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
603 entry->decoder=(DecodeImageHandler *) ReadJP2Image;
604 entry->encoder=(EncodeImageHandler *) WriteJP2Image;
605#endif
606 (void) RegisterMagickInfo(entry);
cristy3ed852e2009-09-05 21:47:34 +0000607 return(MagickImageCoderSignature);
608}
609
610/*
611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
612% %
613% %
614% %
615% U n r e g i s t e r J P 2 I m a g e %
616% %
617% %
618% %
619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620%
621% UnregisterJP2Image() removes format registrations made by the JP2 module
622% from the list of supported formats.
623%
624% The format of the UnregisterJP2Image method is:
625%
626% UnregisterJP2Image(void)
627%
628*/
629ModuleExport void UnregisterJP2Image(void)
630{
cristy92f84a52014-01-02 15:10:12 +0000631 (void) UnregisterMagickInfo("JPC");
cristy25997252014-01-02 13:28:18 +0000632 (void) UnregisterMagickInfo("JPT");
cristy02f1fda2009-12-10 15:23:56 +0000633 (void) UnregisterMagickInfo("JP2");
cristy25997252014-01-02 13:28:18 +0000634 (void) UnregisterMagickInfo("J2K");
cristy3ed852e2009-09-05 21:47:34 +0000635}
636
cristy25997252014-01-02 13:28:18 +0000637#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
cristy3ed852e2009-09-05 21:47:34 +0000638/*
639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
640% %
641% %
642% %
643% W r i t e J P 2 I m a g e %
644% %
645% %
646% %
647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
648%
649% WriteJP2Image() writes an image in the JPEG 2000 image format.
650%
651% JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
652%
653% The format of the WriteJP2Image method is:
654%
cristy25997252014-01-02 13:28:18 +0000655% MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
cristy3ed852e2009-09-05 21:47:34 +0000656%
657% A description of each parameter follows.
658%
659% o image_info: the image info.
660%
661% o image: The image.
662%
663*/
cristy25997252014-01-02 13:28:18 +0000664static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
cristy3ed852e2009-09-05 21:47:34 +0000665{
cristy3ed852e2009-09-05 21:47:34 +0000666 MagickBooleanType
667 status;
668
cristy3ed852e2009-09-05 21:47:34 +0000669 /*
670 Open image file.
671 */
672 assert(image_info != (const ImageInfo *) NULL);
673 assert(image_info->signature == MagickSignature);
674 assert(image != (Image *) NULL);
675 assert(image->signature == MagickSignature);
676 if (image->debug != MagickFalse)
677 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy25997252014-01-02 13:28:18 +0000678 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +0000679 if (status == MagickFalse)
680 return(status);
681 /*
glennrpbca49a22011-07-01 12:18:22 +0000682 Initialize JPEG 2000 API.
cristy3ed852e2009-09-05 21:47:34 +0000683 */
cristy3d9f5ba2012-06-26 13:37:31 +0000684 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy25997252014-01-02 13:28:18 +0000685 (void) TransformImageColorspace(image,sRGBColorspace);
cristy3ed852e2009-09-05 21:47:34 +0000686 if (status != MagickFalse)
687 ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
688 return(MagickTrue);
689}
690#endif