Coverage Report

Created: 2026-11-12 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/jp2.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                              JJJ  PPPP    222                               %
7
%                               J   P   P  2   2                              %
8
%                               J   PPPP     22                               %
9
%                            J  J   P       2                                 %
10
%                             JJ    P      22222                              %
11
%                                                                             %
12
%                                                                             %
13
%                     Read/Write JPEG-2000 Image Format                       %
14
%                                                                             %
15
%                                   Cristy                                    %
16
%                                Nathan Brown                                 %
17
%                                 June 2001                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 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
%    https://imagemagick.org/license/                                         %
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 "MagickCore/studio.h"
43
#include "MagickCore/artifact.h"
44
#include "MagickCore/attribute.h"
45
#include "MagickCore/blob.h"
46
#include "MagickCore/blob-private.h"
47
#include "MagickCore/cache.h"
48
#include "MagickCore/colorspace.h"
49
#include "MagickCore/colorspace-private.h"
50
#include "MagickCore/color.h"
51
#include "MagickCore/color-private.h"
52
#include "MagickCore/exception.h"
53
#include "MagickCore/exception-private.h"
54
#include "MagickCore/image.h"
55
#include "MagickCore/image-private.h"
56
#include "MagickCore/list.h"
57
#include "MagickCore/magick.h"
58
#include "MagickCore/memory_.h"
59
#include "MagickCore/monitor.h"
60
#include "MagickCore/monitor-private.h"
61
#include "MagickCore/option.h"
62
#include "MagickCore/pixel-accessor.h"
63
#include "MagickCore/profile-private.h"
64
#include "MagickCore/property.h"
65
#include "MagickCore/quantum-private.h"
66
#include "MagickCore/resource_.h"
67
#include "MagickCore/semaphore.h"
68
#include "MagickCore/static.h"
69
#include "MagickCore/statistic.h"
70
#include "MagickCore/string_.h"
71
#include "MagickCore/string-private.h"
72
#include "MagickCore/module.h"
73
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
74
#include <openjpeg.h>
75
76
#define OPJ_COMPUTE_NUMERIC_VERSION(major,minor,patch) ((major<<24) | (minor<<16) | (patch<<8) | 0)
77
#define OPJ_NUMERIC_VERSION OPJ_COMPUTE_NUMERIC_VERSION(OPJ_VERSION_MAJOR,OPJ_VERSION_MINOR,OPJ_VERSION_BUILD)
78
#endif
79
80
/*
81
  Typedef declarations.
82
*/
83
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
84
typedef struct _JP2CompsInfo
85
{
86
  double
87
    scale;
88
89
  ssize_t
90
    addition,
91
    pad,
92
    y_index;
93
} JP2CompsInfo;
94
#endif
95

96
/*
97
  Forward declarations.
98
*/
99
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
100
static MagickBooleanType
101
  WriteJP2Image(const ImageInfo *,Image *,ExceptionInfo *);
102
#endif
103

104
/*
105
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106
%                                                                             %
107
%                                                                             %
108
%                                                                             %
109
%   I s J 2 K                                                                 %
110
%                                                                             %
111
%                                                                             %
112
%                                                                             %
113
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114
%
115
%  IsJ2K() returns MagickTrue if the image format type, identified by the
116
%  magick string, is J2K.
117
%
118
%  The format of the IsJ2K method is:
119
%
120
%      MagickBooleanType IsJ2K(const unsigned char *magick,const size_t length)
121
%
122
%  A description of each parameter follows:
123
%
124
%    o magick: compare image format pattern against these bytes.
125
%
126
%    o length: Specifies the length of the magick string.
127
%
128
*/
129
static MagickBooleanType IsJ2K(const unsigned char *magick,const size_t length)
130
26.8k
{
131
26.8k
  if (length < 4)
132
0
    return(MagickFalse);
133
26.8k
  if (memcmp(magick,"\xff\x4f\xff\x51",4) == 0)
134
23.1k
    return(MagickTrue);
135
3.68k
  return(MagickFalse);
136
26.8k
}
137

138
/*
139
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140
%                                                                             %
141
%                                                                             %
142
%                                                                             %
143
%   I s J P 2                                                                 %
144
%                                                                             %
145
%                                                                             %
146
%                                                                             %
147
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148
%
149
%  IsJP2() returns MagickTrue if the image format type, identified by the
150
%  magick string, is JP2.
151
%
152
%  The format of the IsJP2 method is:
153
%
154
%      MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
155
%
156
%  A description of each parameter follows:
157
%
158
%    o magick: compare image format pattern against these bytes.
159
%
160
%    o length: Specifies the length of the magick string.
161
%
162
*/
163
static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
164
3.68k
{
165
3.68k
  if (length < 4)
166
0
    return(MagickFalse);
167
3.68k
  if (memcmp(magick,"\x0d\x0a\x87\x0a",4) == 0)
168
283
    return(MagickTrue);
169
3.40k
  if (length < 12)
170
0
    return(MagickFalse);
171
3.40k
  if (memcmp(magick,"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a",12) == 0)
172
3.30k
    return(MagickTrue);
173
92
  return(MagickFalse);
174
3.40k
}
175

176
/*
177
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178
%                                                                             %
179
%                                                                             %
180
%                                                                             %
181
%   R e a d J P 2 I m a g e                                                   %
182
%                                                                             %
183
%                                                                             %
184
%                                                                             %
185
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186
%
187
%  ReadJP2Image() reads a JPEG 2000 Image file (JP2) or JPEG 2000
188
%  codestream (JPC) image file and returns it.  It allocates the memory
189
%  necessary for the new Image structure and returns a pointer to the new
190
%  image or set of images.
191
%
192
%  JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
193
%
194
%  The format of the ReadJP2Image method is:
195
%
196
%      Image *ReadJP2Image(const ImageInfo *image_info,
197
%        ExceptionInfo *exception)
198
%
199
%  A description of each parameter follows:
200
%
201
%    o image_info: the image info.
202
%
203
%    o exception: return any errors or warnings in this structure.
204
%
205
*/
206
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
207
static void JP2ErrorHandler(const char *message,void *client_data)
208
34.0k
{
209
34.0k
  ExceptionInfo
210
34.0k
    *exception;
211
212
34.0k
  exception=(ExceptionInfo *) client_data;
213
34.0k
  (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
214
34.0k
    message,"`%s'","OpenJP2");
215
34.0k
}
216
217
static OPJ_SIZE_T JP2ReadHandler(void *buffer,OPJ_SIZE_T length,void *context)
218
31.5k
{
219
31.5k
  Image
220
31.5k
    *image;
221
222
31.5k
  ssize_t
223
31.5k
    count;
224
225
31.5k
  image=(Image *) context;
226
31.5k
  count=ReadBlob(image,(size_t) length,(unsigned char *) buffer);
227
31.5k
  if (count == 0)
228
4.13k
    return((OPJ_SIZE_T) -1);
229
27.3k
  return((OPJ_SIZE_T) count);
230
31.5k
}
231
232
static OPJ_BOOL JP2SeekHandler(OPJ_OFF_T offset,void *context)
233
8.70k
{
234
8.70k
  Image
235
8.70k
    *image;
236
237
8.70k
  image=(Image *) context;
238
8.70k
  return(SeekBlob(image,offset,SEEK_SET) < 0 ? OPJ_FALSE : OPJ_TRUE);
239
8.70k
}
240
241
static OPJ_OFF_T JP2SkipHandler(OPJ_OFF_T offset,void *context)
242
3.26k
{
243
3.26k
  Image
244
3.26k
    *image;
245
246
3.26k
  image=(Image *) context;
247
3.26k
  return(SeekBlob(image,offset,SEEK_CUR) < 0 ? -1 : offset);
248
3.26k
}
249
250
static void JP2WarningHandler(const char *message,void *client_data)
251
12.1M
{
252
12.1M
  ExceptionInfo
253
12.1M
    *exception;
254
255
12.1M
  exception=(ExceptionInfo *) client_data;
256
12.1M
  (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
257
12.1M
    message,"`%s'","OpenJP2");
258
12.1M
}
259
260
static OPJ_SIZE_T JP2WriteHandler(void *buffer,OPJ_SIZE_T length,void *context)
261
13.2k
{
262
13.2k
  Image
263
13.2k
    *image;
264
265
13.2k
  ssize_t
266
13.2k
    count;
267
268
13.2k
  image=(Image *) context;
269
13.2k
  count=WriteBlob(image,(size_t) length,(unsigned char *) buffer);
270
13.2k
  return((OPJ_SIZE_T) count);
271
13.2k
}
272
273
static MagickBooleanType JP2ComponentHasAlpha(const ImageInfo* image_info,
274
  opj_image_comp_t comp)
275
515
{
276
515
  const char
277
515
    *option;
278
279
515
  if (comp.alpha != 0)
280
74
    return(MagickTrue);
281
441
  option=GetImageOption(image_info,"jp2:assume-alpha");
282
441
  return(IsStringTrue(option));
283
515
}
284
285
static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
286
26.8k
{
287
26.8k
  const char
288
26.8k
    *option;
289
290
26.8k
  Image
291
26.8k
    *image;
292
293
26.8k
  int
294
26.8k
    jp2_status;
295
296
26.8k
  JP2CompsInfo
297
26.8k
    comps_info[MaxPixelChannels];
298
299
26.8k
  MagickBooleanType
300
26.8k
    status;
301
302
26.8k
  opj_codec_t
303
26.8k
    *jp2_codec;
304
305
26.8k
  opj_codestream_info_v2_t
306
26.8k
    *jp2_codestream_info;
307
308
26.8k
  opj_dparameters_t
309
26.8k
    parameters;
310
311
26.8k
  opj_image_t
312
26.8k
    *jp2_image;
313
314
26.8k
  opj_stream_t
315
26.8k
    *jp2_stream;
316
317
26.8k
  ssize_t
318
26.8k
    i,
319
26.8k
    y;
320
321
26.8k
  unsigned char
322
26.8k
    magick[16];
323
324
  /*
325
    Open image file.
326
  */
327
26.8k
  assert(image_info != (const ImageInfo *) NULL);
328
26.8k
  assert(image_info->signature == MagickCoreSignature);
329
26.8k
  assert(exception != (ExceptionInfo *) NULL);
330
26.8k
  assert(exception->signature == MagickCoreSignature);
331
26.8k
  if (IsEventLogging() != MagickFalse)
332
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
333
0
      image_info->filename);
334
26.8k
  image=AcquireImage(image_info,exception);
335
26.8k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
336
26.8k
  if (status == MagickFalse)
337
0
    {
338
0
      image=DestroyImageList(image);
339
0
      return((Image *) NULL);
340
0
    }
341
  /*
342
    Initialize JP2 codec.
343
  */
344
26.8k
  if (ReadBlob(image,sizeof(magick),magick) != sizeof(magick))
345
26
    {
346
26
      image=DestroyImageList(image);
347
26
      return((Image *) NULL);
348
26
    }
349
26.8k
  (void) SeekBlob(image,SEEK_SET,0);
350
26.8k
  if (LocaleCompare(image_info->magick,"JPT") == 0)
351
33
    jp2_codec=opj_create_decompress(OPJ_CODEC_JPT);
352
26.8k
  else
353
26.8k
    if (IsJ2K(magick,sizeof(magick)) != MagickFalse)
354
23.1k
      jp2_codec=opj_create_decompress(OPJ_CODEC_J2K);
355
3.68k
    else
356
3.68k
      if (IsJP2(magick,sizeof(magick)) != MagickFalse)
357
3.59k
        jp2_codec=opj_create_decompress(OPJ_CODEC_JP2);
358
92
      else
359
26.7k
        ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
360
26.7k
  opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
361
26.7k
  opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
362
26.7k
  opj_set_default_decoder_parameters(&parameters);
363
26.7k
  option=GetImageOption(image_info,"jp2:reduce-factor");
364
26.7k
  if (option != (const char *) NULL)
365
0
    parameters.cp_reduce=(unsigned int) StringToInteger(option);
366
26.7k
  option=GetImageOption(image_info,"jp2:quality-layers");
367
26.7k
  if (option != (const char *) NULL)
368
0
    parameters.cp_layer=(unsigned int) StringToInteger(option);
369
26.7k
  if (opj_setup_decoder(jp2_codec,&parameters) == 0)
370
33
    {
371
33
      opj_destroy_codec(jp2_codec);
372
33
      ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
373
0
    }
374
26.7k
  jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,1);
375
26.7k
  opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
376
26.7k
  opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
377
26.7k
  opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
378
26.7k
  opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
379
26.7k
  opj_stream_set_user_data(jp2_stream,image,NULL);
380
26.7k
  opj_stream_set_user_data_length(jp2_stream,GetBlobSize(image));
381
26.7k
  jp2_image=(opj_image_t *) NULL;
382
26.7k
  if (opj_read_header(jp2_stream,jp2_codec,&jp2_image) == 0)
383
6.71k
    {
384
6.71k
      opj_stream_destroy(jp2_stream);
385
6.71k
      opj_destroy_codec(jp2_codec);
386
6.71k
      ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
387
0
    }
388
20.0k
  jp2_codestream_info=opj_get_cstr_info(jp2_codec);
389
20.0k
  if (AcquireMagickResource(ListLengthResource,(MagickSizeType)
390
20.0k
       jp2_codestream_info->m_default_tile_info.numlayers) == MagickFalse)
391
170
    {
392
170
      opj_destroy_cstr_info(&jp2_codestream_info);
393
170
      opj_stream_destroy(jp2_stream);
394
170
      opj_destroy_codec(jp2_codec);
395
170
      opj_image_destroy(jp2_image);
396
170
      ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
397
0
    }
398
19.8k
  opj_destroy_cstr_info(&jp2_codestream_info);
399
19.8k
  jp2_status=OPJ_TRUE;
400
19.8k
  if ((AcquireMagickResource(WidthResource,(size_t) jp2_image->comps[0].w) == MagickFalse) ||
401
19.6k
      (AcquireMagickResource(WidthResource,(size_t) jp2_image->x1) == MagickFalse) ||
402
19.6k
      (AcquireMagickResource(HeightResource,(size_t) jp2_image->comps[0].h) == MagickFalse) ||
403
19.6k
      (AcquireMagickResource(HeightResource,(size_t) jp2_image->y1) == MagickFalse))
404
250
    {
405
250
      opj_stream_destroy(jp2_stream);
406
250
      opj_destroy_codec(jp2_codec);
407
250
      opj_image_destroy(jp2_image);
408
250
      ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
409
0
    }
410
19.5k
  if (image->ping == MagickFalse)
411
19.5k
    {
412
19.5k
      if ((image->columns != 0) && (image->rows != 0))
413
        /*
414
          Extract an area from the image.
415
        */
416
0
        jp2_status=opj_set_decode_area(jp2_codec,jp2_image,
417
0
          (OPJ_INT32) image->extract_info.x,(OPJ_INT32) image->extract_info.y,
418
0
          (OPJ_INT32) (image->extract_info.x+(ssize_t) image->columns),
419
0
          (OPJ_INT32) (image->extract_info.y+(ssize_t) image->rows));
420
19.5k
      else
421
19.5k
        jp2_status=opj_set_decode_area(jp2_codec,jp2_image,0,0,
422
19.5k
          (int) jp2_image->comps[0].w,(int) jp2_image->comps[0].h);
423
19.5k
      if (jp2_status == OPJ_FALSE)
424
15
        {
425
15
          opj_stream_destroy(jp2_stream);
426
15
          opj_destroy_codec(jp2_codec);
427
15
          opj_image_destroy(jp2_image);
428
15
          ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
429
0
        }
430
19.5k
    }
431
19.5k
  if ((image_info->number_scenes != 0) && (image_info->scene != 0))
432
0
    jp2_status=opj_get_decoded_tile(jp2_codec,jp2_stream,jp2_image,
433
0
      (unsigned int) image_info->scene-1);
434
19.5k
  else
435
19.5k
    if (image->ping == MagickFalse)
436
19.5k
      {
437
19.5k
        jp2_status=opj_decode(jp2_codec,jp2_stream,jp2_image);
438
19.5k
        if (jp2_status != OPJ_FALSE)
439
14.6k
          jp2_status=opj_end_decompress(jp2_codec,jp2_stream);
440
19.5k
      }
441
19.5k
  if (jp2_status == OPJ_FALSE)
442
4.93k
    {
443
4.93k
      opj_stream_destroy(jp2_stream);
444
4.93k
      opj_destroy_codec(jp2_codec);
445
4.93k
      opj_image_destroy(jp2_image);
446
4.93k
      ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
447
0
    }
448
14.6k
  if (jp2_image->numcomps >= MaxPixelChannels)
449
26
    {
450
26
      opj_stream_destroy(jp2_stream);
451
26
      opj_destroy_codec(jp2_codec);
452
26
      opj_image_destroy(jp2_image);
453
26
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
454
0
    }
455
32.1k
  for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
456
17.6k
  {
457
17.6k
    if ((jp2_image->comps[i].dx == 0) || (jp2_image->comps[i].dy == 0) ||
458
17.6k
        (jp2_image->comps[0].prec != jp2_image->comps[i].prec) ||
459
17.5k
        (jp2_image->comps[0].prec > 64) ||
460
17.5k
        (jp2_image->comps[0].sgnd != jp2_image->comps[i].sgnd))
461
97
      {
462
97
        opj_stream_destroy(jp2_stream);
463
97
        opj_destroy_codec(jp2_codec);
464
97
        opj_image_destroy(jp2_image);
465
97
        ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported")
466
97
      }
467
17.6k
  }
468
14.5k
  opj_stream_destroy(jp2_stream);
469
14.5k
  if (image->ping == MagickFalse)
470
14.5k
    {
471
31.8k
      for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
472
17.3k
        if (jp2_image->comps[i].data == NULL)
473
0
          {
474
0
            opj_destroy_codec(jp2_codec);
475
0
            opj_image_destroy(jp2_image);
476
0
            ThrowReaderException(CoderError,
477
0
              "IrregularChannelGeometryNotSupported")
478
0
          }
479
14.5k
    }
480
  /*
481
    Convert JP2 image.
482
  */
483
14.5k
  image->columns=(size_t) jp2_image->comps[0].w;
484
14.5k
  image->rows=(size_t) jp2_image->comps[0].h;
485
14.5k
  image->depth=jp2_image->comps[0].prec;
486
14.5k
  image->compression=JPEG2000Compression;
487
14.5k
  if (jp2_image->numcomps == 1)
488
13.4k
    SetImageColorspace(image,GRAYColorspace,exception);
489
1.04k
  else
490
1.04k
    if (jp2_image->color_space == 2)
491
35
      SetImageColorspace(image,GRAYColorspace,exception);
492
1.00k
    else
493
1.00k
      if (jp2_image->color_space == 3)
494
119
        SetImageColorspace(image,Rec601YCbCrColorspace,exception);
495
14.5k
  if (jp2_image->numcomps > 3)
496
419
    {
497
419
      size_t
498
419
        number_meta_channels;
499
500
419
      number_meta_channels=jp2_image->numcomps-3;
501
419
      if (JP2ComponentHasAlpha(image_info,jp2_image->comps[3]) != MagickFalse)
502
34
        {
503
34
          image->alpha_trait=BlendPixelTrait;
504
34
          number_meta_channels-=1;
505
34
        }
506
419
      if (number_meta_channels > 0)
507
395
        {
508
395
          status=SetPixelMetaChannels(image,(size_t) number_meta_channels,
509
395
            exception);
510
395
          if (status == MagickFalse)
511
0
            {
512
0
              opj_destroy_codec(jp2_codec);
513
0
              opj_image_destroy(jp2_image);
514
0
              return(DestroyImageList(image));
515
0
            }
516
395
        }
517
419
    }
518
14.1k
  else if (jp2_image->numcomps == 2)
519
96
    {
520
96
      if (JP2ComponentHasAlpha(image_info,jp2_image->comps[1]) != MagickFalse)
521
40
        image->alpha_trait=BlendPixelTrait;
522
96
    }
523
14.0k
  else if ((jp2_image->numcomps == 1) && (jp2_image->comps[0].alpha != 0))
524
24
    image->alpha_trait=BlendPixelTrait;
525
14.5k
  if (jp2_image->icc_profile_buf != (unsigned char *) NULL)
526
352
    {
527
352
      StringInfo
528
352
        *profile;
529
530
352
      profile=BlobToProfileStringInfo("icc",jp2_image->icc_profile_buf,
531
352
        jp2_image->icc_profile_len,exception);
532
352
      (void) SetImageProfilePrivate(image,profile,exception);
533
352
    }
534
14.5k
  if (image->ping != MagickFalse)
535
5
    {
536
5
      opj_destroy_codec(jp2_codec);
537
5
      opj_image_destroy(jp2_image);
538
5
      return(GetFirstImageInList(image));
539
5
    }
540
14.5k
  status=SetImageExtent(image,image->columns,image->rows,exception);
541
14.5k
  if (status == MagickFalse)
542
0
    {
543
0
      opj_destroy_codec(jp2_codec);
544
0
      opj_image_destroy(jp2_image);
545
0
      return(DestroyImageList(image));
546
0
    }
547
14.5k
  memset(comps_info,0,MaxPixelChannels*sizeof(JP2CompsInfo));
548
31.8k
  for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
549
17.3k
  {
550
17.3k
    comps_info[i].scale=(double) QuantumRange/(double) 
551
17.3k
      ((MagickULLConstant(1) << jp2_image->comps[i].prec)-1);
552
17.3k
    comps_info[i].addition=(jp2_image->comps[i].sgnd ?
553
15.9k
      MagickULLConstant(1) << (jp2_image->comps[i].prec-1) : 0);
554
17.3k
    comps_info[i].pad=(ssize_t) image->columns % jp2_image->comps[i].dx;
555
17.3k
  }
556
5.58M
  for (y=0; y < (ssize_t) image->rows; y++)
557
5.57M
  {
558
5.57M
    Quantum
559
5.57M
      *magick_restrict q;
560
561
5.57M
    ssize_t
562
5.57M
      x;
563
564
11.4M
    for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
565
5.87M
    {
566
5.87M
      comps_info[i].y_index=y/jp2_image->comps[i].dy*((ssize_t) image->columns+
567
5.87M
        comps_info[i].pad);
568
5.87M
    }
569
5.57M
    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
570
5.57M
    if (q == (Quantum *) NULL)
571
0
      break;
572
5.87G
    for (x=0; x < (ssize_t) image->columns; x++)
573
5.86G
    {
574
11.8G
      for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
575
5.97G
      {
576
5.97G
        double
577
5.97G
          pixel;
578
579
5.97G
        ssize_t
580
5.97G
          index;
581
582
5.97G
        index=comps_info[i].y_index/jp2_image->comps[i].dx+x/
583
5.97G
          jp2_image->comps[i].dx;
584
5.97G
        if ((index < 0) ||
585
5.97G
            (index >= (ssize_t) (jp2_image->comps[i].h*jp2_image->comps[i].w)))
586
98
          {
587
98
            opj_destroy_codec(jp2_codec);
588
98
            opj_image_destroy(jp2_image);
589
98
            ThrowReaderException(CoderError,
590
98
              "IrregularChannelGeometryNotSupported")
591
98
          }
592
5.97G
        pixel=comps_info[i].scale*(jp2_image->comps[i].data[index]+
593
5.97G
          comps_info[i].addition);
594
5.97G
        switch (i)
595
5.97G
        {
596
5.86G
          case 0:
597
5.86G
          {
598
5.86G
            if (jp2_image->numcomps == 1)
599
5.81G
              {
600
5.81G
                SetPixelGray(image,ClampToQuantum(pixel),q);
601
5.81G
                if (jp2_image->comps[i].alpha != 0)
602
1.57k
                  SetPixelAlpha(image,ClampToQuantum(pixel),q);
603
5.81G
                break;
604
5.81G
              }
605
54.9M
            SetPixelRed(image,ClampToQuantum(pixel),q);
606
54.9M
            if (jp2_image->numcomps == 2)
607
96.4k
              {
608
96.4k
                SetPixelGreen(image,ClampToQuantum(pixel),q);
609
96.4k
                SetPixelBlue(image,ClampToQuantum(pixel),q);
610
96.4k
              }
611
54.9M
            break;
612
5.86G
          }
613
54.9M
          case 1:
614
54.9M
          {
615
54.9M
            if ((jp2_image->numcomps == 2) && (jp2_image->comps[i].alpha != 0))
616
4.47k
              {
617
4.47k
                SetPixelAlpha(image,ClampToQuantum(pixel),q);
618
4.47k
                break;
619
4.47k
              }
620
54.9M
            SetPixelGreen(image,ClampToQuantum(pixel),q);
621
54.9M
            break;
622
54.9M
          }
623
54.8M
          case 2:
624
54.8M
          {
625
54.8M
            SetPixelBlue(image,ClampToQuantum(pixel),q);
626
54.8M
            break;
627
54.9M
          }
628
515k
          case 3:
629
515k
          {
630
515k
            if ((image->alpha_trait & BlendPixelTrait) != 0)
631
64.1k
              SetPixelAlpha(image,ClampToQuantum(pixel),q);
632
450k
            else
633
450k
              SetPixelChannel(image,MetaPixelChannels,ClampToQuantum(pixel),q);
634
515k
            break;
635
54.9M
          }
636
1.61M
          default:
637
1.61M
          {
638
1.61M
            ssize_t
639
1.61M
              offset = MetaPixelChannels+i-3;
640
641
1.61M
            if ((image->alpha_trait & BlendPixelTrait) != 0)
642
59.9k
              offset--;
643
1.61M
            SetPixelChannel(image,(PixelChannel) offset,ClampToQuantum(pixel),
644
1.61M
              q);
645
1.61M
            break;
646
54.9M
          }
647
5.97G
        }
648
5.97G
      }
649
5.86G
      q+=(ptrdiff_t) GetPixelChannels(image);
650
5.86G
    }
651
5.57M
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
652
0
      break;
653
5.57M
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
654
5.57M
      image->rows);
655
5.57M
    if (status == MagickFalse)
656
0
      break;
657
5.57M
  }
658
  /*
659
    Free resources.
660
  */
661
14.4k
  opj_destroy_codec(jp2_codec);
662
14.4k
  opj_image_destroy(jp2_image);
663
14.4k
  (void) CloseBlob(image);
664
14.4k
  if ((image_info->number_scenes != 0) && (image_info->scene != 0))
665
0
    AppendImageToList(&image,CloneImage(image,0,0,MagickTrue,exception));
666
14.4k
  return(GetFirstImageInList(image));
667
14.5k
}
668
#endif
669

670
/*
671
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672
%                                                                             %
673
%                                                                             %
674
%                                                                             %
675
%   R e g i s t e r J P 2 I m a g e                                           %
676
%                                                                             %
677
%                                                                             %
678
%                                                                             %
679
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680
%
681
%  RegisterJP2Image() adds attributes for the JP2 image format to the list of
682
%  supported formats.  The attributes include the image format tag, a method
683
%  method to read and/or write the format, whether the format supports the
684
%  saving of more than one frame to the same file or blob, whether the format
685
%  supports native in-memory I/O, and a brief description of the format.
686
%
687
%  The format of the RegisterJP2Image method is:
688
%
689
%      size_t RegisterJP2Image(void)
690
%
691
*/
692
ModuleExport size_t RegisterJP2Image(void)
693
17
{
694
17
  char
695
17
    version[MagickPathExtent];
696
697
17
  MagickInfo
698
17
    *entry;
699
700
17
  *version='\0';
701
17
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
702
17
  (void) FormatLocaleString(version,MagickPathExtent,"%s",opj_version());
703
17
#endif
704
17
  entry=AcquireMagickInfo("JP2","JP2","JPEG-2000 File Format Syntax");
705
17
  if (*version != '\0')
706
17
    entry->version=ConstantString(version);
707
17
  entry->mime_type=ConstantString("image/jp2");
708
17
  entry->magick=(IsImageFormatHandler *) IsJP2;
709
17
  entry->flags^=CoderAdjoinFlag;
710
17
  entry->flags|=CoderDecoderSeekableStreamFlag;
711
17
  entry->flags|=CoderEncoderSeekableStreamFlag;
712
17
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
713
17
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
714
17
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
715
17
#endif
716
17
  (void) RegisterMagickInfo(entry);
717
17
  entry=AcquireMagickInfo("JP2","J2C","JPEG-2000 Code Stream Syntax");
718
17
  if (*version != '\0')
719
17
    entry->version=ConstantString(version);
720
17
  entry->mime_type=ConstantString("image/jp2");
721
17
  entry->magick=(IsImageFormatHandler *) IsJ2K;
722
17
  entry->flags^=CoderAdjoinFlag;
723
17
  entry->flags|=CoderDecoderSeekableStreamFlag;
724
17
  entry->flags|=CoderEncoderSeekableStreamFlag;
725
17
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
726
17
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
727
17
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
728
17
#endif
729
17
  (void) RegisterMagickInfo(entry);
730
17
  entry=AcquireMagickInfo("JP2","J2K","JPEG-2000 Code Stream Syntax");
731
17
  if (*version != '\0')
732
17
    entry->version=ConstantString(version);
733
17
  entry->mime_type=ConstantString("image/jp2");
734
17
  entry->magick=(IsImageFormatHandler *) IsJ2K;
735
17
  entry->flags^=CoderAdjoinFlag;
736
17
  entry->flags|=CoderDecoderSeekableStreamFlag;
737
17
  entry->flags|=CoderEncoderSeekableStreamFlag;
738
17
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
739
17
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
740
17
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
741
17
#endif
742
17
  (void) RegisterMagickInfo(entry);
743
17
  entry=AcquireMagickInfo("JP2","JPM","JPEG-2000 File Format Syntax");
744
17
  if (*version != '\0')
745
17
    entry->version=ConstantString(version);
746
17
  entry->mime_type=ConstantString("image/jp2");
747
17
  entry->magick=(IsImageFormatHandler *) IsJP2;
748
17
  entry->flags^=CoderAdjoinFlag;
749
17
  entry->flags|=CoderDecoderSeekableStreamFlag;
750
17
  entry->flags|=CoderEncoderSeekableStreamFlag;
751
17
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
752
17
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
753
17
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
754
17
#endif
755
17
  (void) RegisterMagickInfo(entry);
756
17
  entry=AcquireMagickInfo("JP2","JPT","JPEG-2000 File Format Syntax");
757
17
  if (*version != '\0')
758
17
    entry->version=ConstantString(version);
759
17
  entry->mime_type=ConstantString("image/jp2");
760
17
  entry->magick=(IsImageFormatHandler *) IsJP2;
761
17
  entry->flags^=CoderAdjoinFlag;
762
17
  entry->flags|=CoderDecoderSeekableStreamFlag;
763
17
  entry->flags|=CoderEncoderSeekableStreamFlag;
764
17
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
765
17
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
766
17
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
767
17
#endif
768
17
  (void) RegisterMagickInfo(entry);
769
17
  entry=AcquireMagickInfo("JP2","JPC","JPEG-2000 Code Stream Syntax");
770
17
  if (*version != '\0')
771
17
    entry->version=ConstantString(version);
772
17
  entry->mime_type=ConstantString("image/jp2");
773
17
  entry->magick=(IsImageFormatHandler *) IsJP2;
774
17
  entry->flags^=CoderAdjoinFlag;
775
17
  entry->flags|=CoderDecoderSeekableStreamFlag;
776
17
  entry->flags|=CoderEncoderSeekableStreamFlag;
777
17
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
778
17
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
779
17
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
780
17
#endif
781
17
  (void) RegisterMagickInfo(entry);
782
17
  return(MagickImageCoderSignature);
783
17
}
784

785
/*
786
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787
%                                                                             %
788
%                                                                             %
789
%                                                                             %
790
%   U n r e g i s t e r J P 2 I m a g e                                       %
791
%                                                                             %
792
%                                                                             %
793
%                                                                             %
794
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795
%
796
%  UnregisterJP2Image() removes format registrations made by the JP2 module
797
%  from the list of supported formats.
798
%
799
%  The format of the UnregisterJP2Image method is:
800
%
801
%      UnregisterJP2Image(void)
802
%
803
*/
804
ModuleExport void UnregisterJP2Image(void)
805
0
{
806
0
  (void) UnregisterMagickInfo("JPC");
807
0
  (void) UnregisterMagickInfo("JPT");
808
0
  (void) UnregisterMagickInfo("JPM");
809
0
  (void) UnregisterMagickInfo("JP2");
810
0
  (void) UnregisterMagickInfo("J2K");
811
0
}
812

813
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
814
/*
815
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816
%                                                                             %
817
%                                                                             %
818
%                                                                             %
819
%   W r i t e J P 2 I m a g e                                                 %
820
%                                                                             %
821
%                                                                             %
822
%                                                                             %
823
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824
%
825
%  WriteJP2Image() writes an image in the JPEG 2000 image format.
826
%
827
%  JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
828
%
829
%  The format of the WriteJP2Image method is:
830
%
831
%      MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
832
%        ExceptionInfo *exception)
833
%
834
%  A description of each parameter follows.
835
%
836
%    o image_info: the image info.
837
%
838
%    o image:  The image.
839
%
840
*/
841
842
static void CinemaProfileCompliance(const opj_image_t *jp2_image,
843
  opj_cparameters_t *parameters)
844
500
{
845
  /*
846
    Digital Cinema 4K profile compliant codestream.
847
  */
848
500
  parameters->tile_size_on=OPJ_FALSE;
849
500
  parameters->cp_tdx=1;
850
500
  parameters->cp_tdy=1;
851
500
  parameters->tp_flag='C';
852
500
  parameters->tp_on=1;
853
500
  parameters->cp_tx0=0;
854
500
  parameters->cp_ty0=0;
855
500
  parameters->image_offset_x0=0;
856
500
  parameters->image_offset_y0=0;
857
500
  parameters->cblockw_init=32;
858
500
  parameters->cblockh_init=32;
859
500
  parameters->csty|=0x01;
860
500
  parameters->prog_order=OPJ_CPRL;
861
500
  parameters->roi_compno=(-1);
862
500
  parameters->subsampling_dx=1;
863
500
  parameters->subsampling_dy=1;
864
500
  parameters->irreversible=1;
865
500
  if ((jp2_image->comps[0].w == 2048) || (jp2_image->comps[0].h == 1080))
866
500
    {
867
      /*
868
        Digital Cinema 2K.
869
      */
870
500
#if OPJ_NUMERIC_VERSION >= OPJ_COMPUTE_NUMERIC_VERSION(2,1,0)
871
500
      parameters->rsiz=OPJ_PROFILE_CINEMA_2K;
872
500
      parameters->max_cs_size=OPJ_CINEMA_24_CS;
873
500
      parameters->max_comp_size=OPJ_CINEMA_24_COMP;
874
#else
875
      parameters->cp_cinema=OPJ_CINEMA2K_24;
876
      parameters->cp_rsiz=OPJ_CINEMA2K;
877
      parameters->max_comp_size=1041666;
878
#endif
879
500
      if (parameters->numresolution > 6)
880
0
        parameters->numresolution=6;
881
882
500
    }
883
500
  if ((jp2_image->comps[0].w == 4096) || (jp2_image->comps[0].h == 2160))
884
0
    {
885
      /*
886
        Digital Cinema 4K.
887
      */
888
0
#if OPJ_NUMERIC_VERSION >= OPJ_COMPUTE_NUMERIC_VERSION(2,1,0)
889
0
      parameters->rsiz=OPJ_PROFILE_CINEMA_4K;
890
0
      parameters->max_cs_size=OPJ_CINEMA_24_CS;
891
0
      parameters->max_comp_size=OPJ_CINEMA_24_COMP;
892
#else
893
      parameters->cp_cinema=OPJ_CINEMA4K_24;
894
      parameters->cp_rsiz=OPJ_CINEMA4K;
895
      parameters->max_comp_size=1041666;
896
#endif
897
0
      if (parameters->numresolution < 1)
898
0
        parameters->numresolution=1;
899
0
      if (parameters->numresolution > 7)
900
0
        parameters->numresolution=7;
901
0
      parameters->numpocs=2;
902
0
      parameters->POC[0].tile=1;
903
0
      parameters->POC[0].resno0=0;
904
0
      parameters->POC[0].compno0=0;
905
0
      parameters->POC[0].layno1=1;
906
0
      parameters->POC[0].resno1=(unsigned int) parameters->numresolution-1;
907
0
      parameters->POC[0].compno1=3;
908
0
      parameters->POC[0].prg1=OPJ_CPRL;
909
0
      parameters->POC[1].tile=1;
910
0
      parameters->POC[1].resno0=(unsigned int) parameters->numresolution-1;
911
0
      parameters->POC[1].compno0=0;
912
0
      parameters->POC[1].layno1=1;
913
0
      parameters->POC[1].resno1=(unsigned int) parameters->numresolution;
914
0
      parameters->POC[1].compno1=3;
915
0
      parameters->POC[1].prg1=OPJ_CPRL;
916
0
    }
917
500
  parameters->tcp_numlayers=1;
918
500
  parameters->tcp_rates[0]=(((float) jp2_image->numcomps*jp2_image->comps[0].w*
919
500
    jp2_image->comps[0].h*jp2_image->comps[0].prec))/((float)
920
500
    parameters->max_comp_size*8*jp2_image->comps[0].dx*jp2_image->comps[0].dy);
921
500
  parameters->cp_disto_alloc=OPJ_TRUE;
922
500
}
923
924
static inline int CalculateNumResolutions(size_t width,size_t height)
925
6.17k
{
926
6.17k
  int
927
6.17k
    i;
928
929
29.8k
  for (i=1; i < 6; i++)
930
25.7k
    if ((width < ((size_t) MagickULLConstant(1) << i)) ||
931
24.5k
        (height < ((size_t) MagickULLConstant(1) << i)))
932
2.09k
      break;
933
6.17k
  return(i);
934
6.17k
}
935
936
static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
937
  ExceptionInfo *exception)
938
6.17k
{
939
6.17k
  const char
940
6.17k
    *option,
941
6.17k
    *property;
942
943
6.17k
  int
944
6.17k
    jp2_status;
945
946
6.17k
  MagickBooleanType
947
6.17k
    status;
948
949
6.17k
  opj_codec_t
950
6.17k
    *jp2_codec;
951
952
6.17k
  OPJ_COLOR_SPACE
953
6.17k
    jp2_colorspace;
954
955
6.17k
  opj_cparameters_t
956
6.17k
    *parameters;
957
958
6.17k
  opj_image_cmptparm_t
959
6.17k
    jp2_info[5];
960
961
6.17k
  opj_image_t
962
6.17k
    *jp2_image;
963
964
6.17k
  opj_stream_t
965
6.17k
    *jp2_stream;
966
967
6.17k
  ssize_t
968
6.17k
    i,
969
6.17k
    y;
970
971
6.17k
  unsigned int
972
6.17k
    channels;
973
974
  /*
975
    Open image file.
976
  */
977
6.17k
  assert(image_info != (const ImageInfo *) NULL);
978
6.17k
  assert(image_info->signature == MagickCoreSignature);
979
6.17k
  assert(image != (Image *) NULL);
980
6.17k
  assert(image->signature == MagickCoreSignature);
981
6.17k
  assert(exception != (ExceptionInfo *) NULL);
982
6.17k
  assert(exception->signature == MagickCoreSignature);
983
6.17k
  if (IsEventLogging() != MagickFalse)
984
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
985
6.17k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
986
6.17k
  if (status == MagickFalse)
987
0
    return(status);
988
  /*
989
    Initialize JPEG 2000 API.
990
  */
991
6.17k
  parameters=(opj_cparameters_t *) AcquireMagickMemory(sizeof(*parameters));
992
6.17k
  if (parameters == (opj_cparameters_t *) NULL)
993
6.17k
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
994
6.17k
  opj_set_default_encoder_parameters(parameters);
995
6.17k
  option=GetImageOption(image_info,"jp2:number-resolutions");
996
6.17k
  if (option != (const char *) NULL)
997
0
    parameters->numresolution=StringToInteger(option);
998
6.17k
  else
999
6.17k
    parameters->numresolution=CalculateNumResolutions(image->columns,
1000
6.17k
      image->rows);
1001
6.17k
  parameters->tcp_numlayers=1;
1002
6.17k
  parameters->tcp_rates[0]=0;  /* lossless */
1003
6.17k
  parameters->cp_disto_alloc=OPJ_TRUE;
1004
6.17k
  if ((image_info->quality != 0) && (image_info->quality != 100))
1005
0
    {
1006
0
      parameters->tcp_distoratio[0]=(float) image_info->quality;
1007
0
      parameters->cp_fixed_quality=OPJ_TRUE;
1008
0
      parameters->cp_disto_alloc=OPJ_FALSE;
1009
0
    }
1010
6.17k
  if (image_info->extract != (char *) NULL)
1011
0
    {
1012
0
      int
1013
0
        flags;
1014
1015
0
      RectangleInfo
1016
0
        geometry;
1017
1018
      /*
1019
        Set tile size.
1020
      */
1021
0
      (void) memset(&geometry,0,sizeof(geometry));
1022
0
      flags=(int) ParseAbsoluteGeometry(image_info->extract,&geometry);
1023
0
      parameters->cp_tdx=(int) geometry.width;
1024
0
      parameters->cp_tdy=(int) geometry.width;
1025
0
      if ((flags & HeightValue) != 0)
1026
0
        parameters->cp_tdy=(int) geometry.height;
1027
0
      if ((flags & XValue) != 0)
1028
0
        parameters->cp_tx0=(int) geometry.x;
1029
0
      if ((flags & YValue) != 0)
1030
0
        parameters->cp_ty0=(int) geometry.y;
1031
0
      parameters->tile_size_on=OPJ_TRUE;
1032
0
      parameters->numresolution=CalculateNumResolutions((size_t)
1033
0
        parameters->cp_tdx,(size_t) parameters->cp_tdy);
1034
0
    }
1035
6.17k
  option=GetImageOption(image_info,"jp2:quality");
1036
6.17k
  if (option != (const char *) NULL)
1037
0
    {
1038
0
      const char
1039
0
        *p;
1040
1041
0
      size_t
1042
0
        extent = sizeof(parameters->tcp_distoratio)/
1043
0
          sizeof(*parameters->tcp_distoratio);
1044
1045
      /*
1046
        Set quality PSNR.
1047
      */
1048
0
      p=option;
1049
0
      for (i=0; (i < (ssize_t) (extent-1)) &&
1050
0
                (MagickSscanf(p,"%f",&parameters->tcp_distoratio[i]) == 1); i++)
1051
0
      {
1052
0
        while ((*p != '\0') && (*p != ','))
1053
0
          p++;
1054
0
        if (*p == '\0')
1055
0
          break;
1056
0
        p++;
1057
0
      }
1058
0
      parameters->tcp_numlayers=(int) (i+1);
1059
0
      parameters->cp_fixed_quality=OPJ_TRUE;
1060
0
      parameters->cp_disto_alloc=OPJ_FALSE;
1061
0
    }
1062
6.17k
  option=GetImageOption(image_info,"jp2:progression-order");
1063
6.17k
  if (option != (const char *) NULL)
1064
0
    {
1065
0
      if (LocaleCompare(option,"LRCP") == 0)
1066
0
        parameters->prog_order=OPJ_LRCP;
1067
0
      if (LocaleCompare(option,"RLCP") == 0)
1068
0
        parameters->prog_order=OPJ_RLCP;
1069
0
      if (LocaleCompare(option,"RPCL") == 0)
1070
0
        parameters->prog_order=OPJ_RPCL;
1071
0
      if (LocaleCompare(option,"PCRL") == 0)
1072
0
        parameters->prog_order=OPJ_PCRL;
1073
0
      if (LocaleCompare(option,"CPRL") == 0)
1074
0
        parameters->prog_order=OPJ_CPRL;
1075
0
    }
1076
6.17k
  option=GetImageOption(image_info,"jp2:rate");
1077
6.17k
  if (option != (const char *) NULL)
1078
0
    {
1079
0
      const char
1080
0
        *p;
1081
1082
0
      size_t
1083
0
        extent = sizeof(parameters->tcp_rates)/sizeof(*parameters->tcp_rates);
1084
1085
      /*
1086
        Set compression rate.
1087
      */
1088
0
      p=option;
1089
0
      for (i=0; (i < (ssize_t) (extent-1)) &&
1090
0
                (MagickSscanf(p,"%f",&parameters->tcp_rates[i]) == 1); i++)
1091
0
      {
1092
0
        while ((*p != '\0') && (*p != ','))
1093
0
          p++;
1094
0
        if (*p == '\0')
1095
0
          break;
1096
0
        p++;
1097
0
      }
1098
0
      parameters->tcp_numlayers=(int) (i+1);
1099
0
      parameters->cp_disto_alloc=OPJ_TRUE;
1100
0
    }
1101
6.17k
  if (image_info->sampling_factor != (char *) NULL)
1102
0
    {
1103
0
      GeometryInfo
1104
0
        geometry_info;
1105
1106
0
      MagickStatusType
1107
0
        flags;
1108
1109
0
      flags=ParseGeometry(image_info->sampling_factor,&geometry_info);
1110
0
      if ((flags & RhoValue) != 0)
1111
0
        parameters->subsampling_dx=(int) MagickMax(
1112
0
          geometry_info.rho,1.0);
1113
0
      parameters->subsampling_dy=parameters->subsampling_dx;
1114
0
      if ((flags & SigmaValue) != 0)
1115
0
        parameters->subsampling_dy=(int) MagickMax(
1116
0
          geometry_info.sigma,1.0);
1117
0
    }   
1118
6.17k
  property=GetImageProperty(image,"comment",exception);
1119
6.17k
  if (property != (const char *) NULL)
1120
0
    parameters->cp_comment=(char *) property;
1121
6.17k
  channels=3;
1122
6.17k
  jp2_colorspace=OPJ_CLRSPC_SRGB;
1123
6.17k
  if (image->colorspace == YUVColorspace)
1124
0
    jp2_colorspace=OPJ_CLRSPC_SYCC;
1125
6.17k
  else
1126
6.17k
    {
1127
6.17k
      if (IsGrayColorspace(image->colorspace) != MagickFalse)
1128
5.67k
        {
1129
5.67k
          channels=1;
1130
5.67k
          jp2_colorspace=OPJ_CLRSPC_GRAY;
1131
5.67k
        }
1132
497
      else
1133
497
        if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1134
115
          (void) TransformImageColorspace(image,sRGBColorspace,exception);
1135
6.17k
      if (image->alpha_trait != UndefinedPixelTrait)
1136
58
        channels++;
1137
6.17k
    }
1138
6.17k
  parameters->tcp_mct=channels == 3 ? 1 : 0;
1139
6.17k
  memset(jp2_info,0,sizeof(jp2_info));
1140
13.3k
  for (i=0; i < (ssize_t) channels; i++)
1141
7.22k
  {
1142
7.22k
    jp2_info[i].prec=(OPJ_UINT32) image->depth;
1143
7.22k
    if ((image->depth == 1) &&
1144
380
        ((LocaleCompare(image_info->magick,"JPT") == 0) ||
1145
380
         (LocaleCompare(image_info->magick,"JP2") == 0)))
1146
72
      jp2_info[i].prec++;  /* OpenJPEG returns exception for depth @ 1 */
1147
7.22k
    jp2_info[i].sgnd=0;
1148
7.22k
    jp2_info[i].dx=(unsigned int) parameters->subsampling_dx;
1149
7.22k
    jp2_info[i].dy=(unsigned int) parameters->subsampling_dy;
1150
7.22k
    jp2_info[i].w=(OPJ_UINT32) image->columns;
1151
7.22k
    jp2_info[i].h=(OPJ_UINT32) image->rows;
1152
7.22k
  }
1153
6.17k
  jp2_image=opj_image_create((OPJ_UINT32) channels,jp2_info,jp2_colorspace);
1154
6.17k
  if (jp2_image == (opj_image_t *) NULL)
1155
0
    {
1156
0
      parameters=(opj_cparameters_t *) RelinquishMagickMemory(parameters);
1157
0
      ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1158
0
    }
1159
6.17k
  jp2_image->x0=(unsigned int) parameters->image_offset_x0;
1160
6.17k
  jp2_image->y0=(unsigned int) parameters->image_offset_y0;
1161
6.17k
  jp2_image->x1=(unsigned int) (2*parameters->image_offset_x0+
1162
6.17k
    ((ssize_t) image->columns-1)*parameters->subsampling_dx+1);
1163
6.17k
  jp2_image->y1=(unsigned int) (2*parameters->image_offset_y0+
1164
6.17k
    ((ssize_t) image->rows-1)*parameters->subsampling_dy+1);
1165
6.17k
  if ((image->depth == 12) &&
1166
1.87k
      ((image->columns == 2048) || (image->rows == 1080) ||
1167
1.37k
       (image->columns == 4096) || (image->rows == 2160)))
1168
500
    CinemaProfileCompliance(jp2_image,parameters);
1169
6.17k
  if (channels == 4)
1170
35
    jp2_image->comps[3].alpha=1;
1171
6.13k
  else
1172
6.13k
    if ((channels == 2) && (jp2_colorspace == OPJ_CLRSPC_GRAY))
1173
23
      jp2_image->comps[1].alpha=1;
1174
  /*
1175
    Convert to JP2 pixels.
1176
  */
1177
2.29M
  for (y=0; y < (ssize_t) image->rows; y++)
1178
2.28M
  {
1179
2.28M
    const Quantum
1180
2.28M
      *p;
1181
1182
2.28M
    ssize_t
1183
2.28M
      x;
1184
1185
2.28M
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1186
2.28M
    if (p == (const Quantum *) NULL)
1187
0
      break;
1188
2.13G
    for (x=0; x < (ssize_t) image->columns; x++)
1189
2.13G
    {
1190
4.29G
      for (i=0; i < (ssize_t) channels; i++)
1191
2.16G
      {
1192
2.16G
        double
1193
2.16G
          scale;
1194
1195
2.16G
        int
1196
2.16G
          *q;
1197
1198
2.16G
        scale=(double) (((size_t) MagickULLConstant(1) <<
1199
2.16G
          jp2_image->comps[i].prec)-1)/(double) QuantumRange;
1200
2.16G
        q=jp2_image->comps[i].data+(ssize_t) (y*MagickSafeReciprocal(
1201
2.16G
          jp2_image->comps[i].dy)*image->columns*MagickSafeReciprocal(
1202
2.16G
          jp2_image->comps[i].dx)+x*MagickSafeReciprocal(
1203
2.16G
          jp2_image->comps[i].dx));
1204
2.16G
        switch (i)
1205
2.16G
        {
1206
2.13G
          case 0:
1207
2.13G
          {
1208
2.13G
            if (jp2_colorspace == OPJ_CLRSPC_GRAY)
1209
2.12G
              {
1210
2.12G
                *q=(int) (scale*(double) GetPixelGray(image,p));
1211
2.12G
                break;
1212
2.12G
              }
1213
14.0M
            *q=(int) (scale*(double) GetPixelRed(image,p));
1214
14.0M
            break;
1215
2.13G
          }
1216
14.0M
          case 1:
1217
14.0M
          {
1218
14.0M
            if (jp2_colorspace == OPJ_CLRSPC_GRAY)
1219
2.84k
              {
1220
2.84k
                *q=(int) (scale*(double) GetPixelAlpha(image,p));
1221
2.84k
                break;
1222
2.84k
              }
1223
14.0M
            *q=(int) (scale*(double) GetPixelGreen(image,p));
1224
14.0M
            break;
1225
14.0M
          }
1226
14.0M
          case 2:
1227
14.0M
          {
1228
14.0M
            *q=(int) (scale*(double) GetPixelBlue(image,p));
1229
14.0M
            break;
1230
14.0M
          }
1231
4.61k
          case 3:
1232
4.61k
          {
1233
4.61k
            *q=(int) (scale*(double) GetPixelAlpha(image,p));
1234
4.61k
            break;
1235
14.0M
          }
1236
2.16G
        }
1237
2.16G
      }
1238
2.13G
      p+=(ptrdiff_t) GetPixelChannels(image);
1239
2.13G
    }
1240
2.28M
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1241
2.28M
      image->rows);
1242
2.28M
    if (status == MagickFalse)
1243
0
      break;
1244
2.28M
  }
1245
6.17k
  if (LocaleCompare(image_info->magick,"JPT") == 0)
1246
0
    jp2_codec=opj_create_compress(OPJ_CODEC_JPT);
1247
6.17k
  else
1248
6.17k
    if (LocaleCompare(image_info->magick,"J2K") == 0)
1249
2.89k
      jp2_codec=opj_create_compress(OPJ_CODEC_J2K);
1250
3.27k
    else
1251
3.27k
      jp2_codec=opj_create_compress(OPJ_CODEC_JP2);
1252
6.17k
  opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
1253
6.17k
  opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
1254
6.17k
  opj_setup_encoder(jp2_codec,parameters,jp2_image);
1255
6.17k
  jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,OPJ_FALSE);
1256
6.17k
  if (jp2_stream == (opj_stream_t *) NULL)
1257
0
    {
1258
0
      opj_destroy_codec(jp2_codec);
1259
0
      opj_image_destroy(jp2_image);
1260
0
      parameters=(opj_cparameters_t *) RelinquishMagickMemory(parameters);
1261
0
      ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1262
0
    }
1263
6.17k
  opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
1264
6.17k
  opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
1265
6.17k
  opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
1266
6.17k
  opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
1267
6.17k
  opj_stream_set_user_data(jp2_stream,image,NULL);
1268
6.17k
  jp2_status=opj_start_compress(jp2_codec,jp2_image,jp2_stream);
1269
6.17k
  if ((jp2_status == 0) || (opj_encode(jp2_codec,jp2_stream) == 0) ||
1270
6.10k
      (opj_end_compress(jp2_codec,jp2_stream) == 0))
1271
62
    {
1272
62
      opj_stream_destroy(jp2_stream);
1273
62
      opj_destroy_codec(jp2_codec);
1274
62
      opj_image_destroy(jp2_image);
1275
62
      parameters=(opj_cparameters_t *) RelinquishMagickMemory(parameters);
1276
62
      ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1277
0
    }
1278
  /*
1279
    Free resources.
1280
  */
1281
6.10k
  opj_stream_destroy(jp2_stream);
1282
6.10k
  opj_destroy_codec(jp2_codec);
1283
6.10k
  opj_image_destroy(jp2_image);
1284
6.10k
  parameters=(opj_cparameters_t *) RelinquishMagickMemory(parameters);
1285
6.10k
  if (CloseBlob(image) == MagickFalse)
1286
0
    status=MagickFalse;
1287
6.10k
  return(status);
1288
6.17k
}
1289
#endif