Coverage Report

Created: 2026-06-30 07:12

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
35.4k
{
131
35.4k
  if (length < 4)
132
0
    return(MagickFalse);
133
35.4k
  if (memcmp(magick,"\xff\x4f\xff\x51",4) == 0)
134
30.5k
    return(MagickTrue);
135
4.89k
  return(MagickFalse);
136
35.4k
}
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
4.89k
{
165
4.89k
  if (length < 4)
166
0
    return(MagickFalse);
167
4.89k
  if (memcmp(magick,"\x0d\x0a\x87\x0a",4) == 0)
168
440
    return(MagickTrue);
169
4.45k
  if (length < 12)
170
0
    return(MagickFalse);
171
4.45k
  if (memcmp(magick,"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a",12) == 0)
172
4.21k
    return(MagickTrue);
173
236
  return(MagickFalse);
174
4.45k
}
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
39.5k
{
209
39.5k
  ExceptionInfo
210
39.5k
    *exception;
211
212
39.5k
  exception=(ExceptionInfo *) client_data;
213
39.5k
  (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
214
39.5k
    message,"`%s'","OpenJP2");
215
39.5k
}
216
217
static OPJ_SIZE_T JP2ReadHandler(void *buffer,OPJ_SIZE_T length,void *context)
218
41.1k
{
219
41.1k
  Image
220
41.1k
    *image;
221
222
41.1k
  ssize_t
223
41.1k
    count;
224
225
41.1k
  image=(Image *) context;
226
41.1k
  count=ReadBlob(image,(size_t) length,(unsigned char *) buffer);
227
41.1k
  if (count == 0)
228
5.30k
    return((OPJ_SIZE_T) -1);
229
35.8k
  return((OPJ_SIZE_T) count);
230
41.1k
}
231
232
static OPJ_BOOL JP2SeekHandler(OPJ_OFF_T offset,void *context)
233
14.2k
{
234
14.2k
  Image
235
14.2k
    *image;
236
237
14.2k
  image=(Image *) context;
238
14.2k
  return(SeekBlob(image,offset,SEEK_SET) < 0 ? OPJ_FALSE : OPJ_TRUE);
239
14.2k
}
240
241
static OPJ_OFF_T JP2SkipHandler(OPJ_OFF_T offset,void *context)
242
5.65k
{
243
5.65k
  Image
244
5.65k
    *image;
245
246
5.65k
  image=(Image *) context;
247
5.65k
  return(SeekBlob(image,offset,SEEK_CUR) < 0 ? -1 : offset);
248
5.65k
}
249
250
static void JP2WarningHandler(const char *message,void *client_data)
251
4.62M
{
252
4.62M
  ExceptionInfo
253
4.62M
    *exception;
254
255
4.62M
  exception=(ExceptionInfo *) client_data;
256
4.62M
  (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
257
4.62M
    message,"`%s'","OpenJP2");
258
4.62M
}
259
260
static OPJ_SIZE_T JP2WriteHandler(void *buffer,OPJ_SIZE_T length,void *context)
261
20.6k
{
262
20.6k
  Image
263
20.6k
    *image;
264
265
20.6k
  ssize_t
266
20.6k
    count;
267
268
20.6k
  image=(Image *) context;
269
20.6k
  count=WriteBlob(image,(size_t) length,(unsigned char *) buffer);
270
20.6k
  return((OPJ_SIZE_T) count);
271
20.6k
}
272
273
static MagickBooleanType JP2ComponentHasAlpha(const ImageInfo* image_info,
274
  opj_image_comp_t comp)
275
649
{
276
649
  const char
277
649
    *option;
278
279
649
  if (comp.alpha != 0)
280
114
    return(MagickTrue);
281
535
  option=GetImageOption(image_info,"jp2:assume-alpha");
282
535
  return(IsStringTrue(option));
283
649
}
284
285
static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
286
35.5k
{
287
35.5k
  const char
288
35.5k
    *option;
289
290
35.5k
  Image
291
35.5k
    *image;
292
293
35.5k
  int
294
35.5k
    jp2_status;
295
296
35.5k
  JP2CompsInfo
297
35.5k
    comps_info[MaxPixelChannels];
298
299
35.5k
  MagickBooleanType
300
35.5k
    status;
301
302
35.5k
  opj_codec_t
303
35.5k
    *jp2_codec;
304
305
35.5k
  opj_codestream_info_v2_t
306
35.5k
    *jp2_codestream_info;
307
308
35.5k
  opj_dparameters_t
309
35.5k
    parameters;
310
311
35.5k
  opj_image_t
312
35.5k
    *jp2_image;
313
314
35.5k
  opj_stream_t
315
35.5k
    *jp2_stream;
316
317
35.5k
  ssize_t
318
35.5k
    i,
319
35.5k
    y;
320
321
35.5k
  unsigned char
322
35.5k
    magick[16];
323
324
  /*
325
    Open image file.
326
  */
327
35.5k
  assert(image_info != (const ImageInfo *) NULL);
328
35.5k
  assert(image_info->signature == MagickCoreSignature);
329
35.5k
  assert(exception != (ExceptionInfo *) NULL);
330
35.5k
  assert(exception->signature == MagickCoreSignature);
331
35.5k
  if (IsEventLogging() != MagickFalse)
332
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
333
0
      image_info->filename);
334
35.5k
  image=AcquireImage(image_info,exception);
335
35.5k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
336
35.5k
  if (status == MagickFalse)
337
0
    {
338
0
      image=DestroyImageList(image);
339
0
      return((Image *) NULL);
340
0
    }
341
  /*
342
    Initialize JP2 codec.
343
  */
344
35.5k
  if (ReadBlob(image,sizeof(magick),magick) != sizeof(magick))
345
34
    {
346
34
      image=DestroyImageList(image);
347
34
      return((Image *) NULL);
348
34
    }
349
35.5k
  (void) SeekBlob(image,SEEK_SET,0);
350
35.5k
  if (LocaleCompare(image_info->magick,"JPT") == 0)
351
34
    jp2_codec=opj_create_decompress(OPJ_CODEC_JPT);
352
35.4k
  else
353
35.4k
    if (IsJ2K(magick,sizeof(magick)) != MagickFalse)
354
30.5k
      jp2_codec=opj_create_decompress(OPJ_CODEC_J2K);
355
4.89k
    else
356
4.89k
      if (IsJP2(magick,sizeof(magick)) != MagickFalse)
357
4.65k
        jp2_codec=opj_create_decompress(OPJ_CODEC_JP2);
358
236
      else
359
35.2k
        ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
360
35.2k
  opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
361
35.2k
  opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
362
35.2k
  opj_set_default_decoder_parameters(&parameters);
363
35.2k
  option=GetImageOption(image_info,"jp2:reduce-factor");
364
35.2k
  if (option != (const char *) NULL)
365
0
    parameters.cp_reduce=(unsigned int) StringToInteger(option);
366
35.2k
  option=GetImageOption(image_info,"jp2:quality-layers");
367
35.2k
  if (option != (const char *) NULL)
368
0
    parameters.cp_layer=(unsigned int) StringToInteger(option);
369
35.2k
  if (opj_setup_decoder(jp2_codec,&parameters) == 0)
370
34
    {
371
34
      opj_destroy_codec(jp2_codec);
372
34
      ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
373
0
    }
374
35.2k
  jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,1);
375
35.2k
  opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
376
35.2k
  opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
377
35.2k
  opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
378
35.2k
  opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
379
35.2k
  opj_stream_set_user_data(jp2_stream,image,NULL);
380
35.2k
  opj_stream_set_user_data_length(jp2_stream,GetBlobSize(image));
381
35.2k
  jp2_image=(opj_image_t *) NULL;
382
35.2k
  if (opj_read_header(jp2_stream,jp2_codec,&jp2_image) == 0)
383
8.43k
    {
384
8.43k
      opj_stream_destroy(jp2_stream);
385
8.43k
      opj_destroy_codec(jp2_codec);
386
8.43k
      ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
387
0
    }
388
26.7k
  jp2_codestream_info=opj_get_cstr_info(jp2_codec);
389
26.7k
  if (AcquireMagickResource(ListLengthResource,(MagickSizeType)
390
26.7k
       jp2_codestream_info->m_default_tile_info.numlayers) == MagickFalse)
391
240
    {
392
240
      opj_destroy_cstr_info(&jp2_codestream_info);
393
240
      opj_stream_destroy(jp2_stream);
394
240
      opj_destroy_codec(jp2_codec);
395
240
      opj_image_destroy(jp2_image);
396
240
      ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
397
0
    }
398
26.5k
  opj_destroy_cstr_info(&jp2_codestream_info);
399
26.5k
  jp2_status=OPJ_TRUE;
400
26.5k
  if ((AcquireMagickResource(WidthResource,(size_t) jp2_image->comps[0].w) == MagickFalse) ||
401
26.2k
      (AcquireMagickResource(WidthResource,(size_t) jp2_image->x1) == MagickFalse) ||
402
26.2k
      (AcquireMagickResource(HeightResource,(size_t) jp2_image->comps[0].h) == MagickFalse) ||
403
26.1k
      (AcquireMagickResource(HeightResource,(size_t) jp2_image->y1) == MagickFalse))
404
380
    {
405
380
      opj_stream_destroy(jp2_stream);
406
380
      opj_destroy_codec(jp2_codec);
407
380
      opj_image_destroy(jp2_image);
408
380
      ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
409
0
    }
410
26.1k
  if (image->ping == MagickFalse)
411
26.1k
    {
412
26.1k
      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
26.1k
      else
421
26.1k
        jp2_status=opj_set_decode_area(jp2_codec,jp2_image,0,0,
422
26.1k
          (int) jp2_image->comps[0].w,(int) jp2_image->comps[0].h);
423
26.1k
      if (jp2_status == OPJ_FALSE)
424
17
        {
425
17
          opj_stream_destroy(jp2_stream);
426
17
          opj_destroy_codec(jp2_codec);
427
17
          opj_image_destroy(jp2_image);
428
17
          ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
429
0
        }
430
26.1k
    }
431
26.1k
  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
26.1k
  else
435
26.1k
    if (image->ping == MagickFalse)
436
26.1k
      {
437
26.1k
        jp2_status=opj_decode(jp2_codec,jp2_stream,jp2_image);
438
26.1k
        if (jp2_status != OPJ_FALSE)
439
19.4k
          jp2_status=opj_end_decompress(jp2_codec,jp2_stream);
440
26.1k
      }
441
26.1k
  if (jp2_status == OPJ_FALSE)
442
6.70k
    {
443
6.70k
      opj_stream_destroy(jp2_stream);
444
6.70k
      opj_destroy_codec(jp2_codec);
445
6.70k
      opj_image_destroy(jp2_image);
446
6.70k
      ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
447
0
    }
448
19.4k
  if (jp2_image->numcomps >= MaxPixelChannels)
449
23
    {
450
23
      opj_stream_destroy(jp2_stream);
451
23
      opj_destroy_codec(jp2_codec);
452
23
      opj_image_destroy(jp2_image);
453
23
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
454
0
    }
455
42.2k
  for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
456
22.9k
  {
457
22.9k
    if ((jp2_image->comps[i].dx == 0) || (jp2_image->comps[i].dy == 0) ||
458
22.9k
        (jp2_image->comps[0].prec != jp2_image->comps[i].prec) ||
459
22.8k
        (jp2_image->comps[0].prec > 64) ||
460
22.8k
        (jp2_image->comps[0].sgnd != jp2_image->comps[i].sgnd))
461
154
      {
462
154
        opj_stream_destroy(jp2_stream);
463
154
        opj_destroy_codec(jp2_codec);
464
154
        opj_image_destroy(jp2_image);
465
154
        ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported")
466
154
      }
467
22.9k
  }
468
19.2k
  opj_stream_destroy(jp2_stream);
469
19.2k
  if (image->ping == MagickFalse)
470
19.2k
    {
471
41.8k
      for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
472
22.5k
        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
19.2k
    }
480
  /*
481
    Convert JP2 image.
482
  */
483
19.2k
  image->columns=(size_t) jp2_image->comps[0].w;
484
19.2k
  image->rows=(size_t) jp2_image->comps[0].h;
485
19.2k
  image->depth=jp2_image->comps[0].prec;
486
19.2k
  image->compression=JPEG2000Compression;
487
19.2k
  if (jp2_image->numcomps == 1)
488
18.0k
    SetImageColorspace(image,GRAYColorspace,exception);
489
1.18k
  else
490
1.18k
    if (jp2_image->color_space == 2)
491
53
      SetImageColorspace(image,GRAYColorspace,exception);
492
1.13k
    else
493
1.13k
      if (jp2_image->color_space == 3)
494
166
        SetImageColorspace(image,Rec601YCbCrColorspace,exception);
495
19.2k
  if (jp2_image->numcomps > 3)
496
517
    {
497
517
      size_t
498
517
        number_meta_channels;
499
500
517
      number_meta_channels=jp2_image->numcomps-3;
501
517
      if (JP2ComponentHasAlpha(image_info,jp2_image->comps[3]) != MagickFalse)
502
60
        {
503
60
          image->alpha_trait=BlendPixelTrait;
504
60
          number_meta_channels-=1;
505
60
        }
506
517
      if (number_meta_channels > 0)
507
493
        {
508
493
          status=SetPixelMetaChannels(image,(size_t) number_meta_channels,
509
493
            exception);
510
493
          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
493
        }
517
517
    }
518
18.7k
  else if (jp2_image->numcomps == 2)
519
132
    {
520
132
      if (JP2ComponentHasAlpha(image_info,jp2_image->comps[1]) != MagickFalse)
521
54
        image->alpha_trait=BlendPixelTrait;
522
132
    }
523
18.6k
  else if ((jp2_image->numcomps == 1) && (jp2_image->comps[0].alpha != 0))
524
18
    image->alpha_trait=BlendPixelTrait;
525
19.2k
  if (jp2_image->icc_profile_buf != (unsigned char *) NULL)
526
347
    {
527
347
      StringInfo
528
347
        *profile;
529
530
347
      profile=BlobToProfileStringInfo("icc",jp2_image->icc_profile_buf,
531
347
        jp2_image->icc_profile_len,exception);
532
347
      (void) SetImageProfilePrivate(image,profile,exception);
533
347
    }
534
19.2k
  if (image->ping != MagickFalse)
535
7
    {
536
7
      opj_destroy_codec(jp2_codec);
537
7
      opj_image_destroy(jp2_image);
538
7
      return(GetFirstImageInList(image));
539
7
    }
540
19.2k
  status=SetImageExtent(image,image->columns,image->rows,exception);
541
19.2k
  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
19.2k
  memset(comps_info,0,MaxPixelChannels*sizeof(JP2CompsInfo));
548
41.8k
  for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
549
22.5k
  {
550
22.5k
    comps_info[i].scale=(double) QuantumRange/(double) 
551
22.5k
      ((MagickULLConstant(1) << jp2_image->comps[i].prec)-1);
552
22.5k
    comps_info[i].addition=(jp2_image->comps[i].sgnd ?
553
20.8k
      MagickULLConstant(1) << (jp2_image->comps[i].prec-1) : 0);
554
22.5k
    comps_info[i].pad=(ssize_t) image->columns % jp2_image->comps[i].dx;
555
22.5k
  }
556
7.64M
  for (y=0; y < (ssize_t) image->rows; y++)
557
7.62M
  {
558
7.62M
    Quantum
559
7.62M
      *magick_restrict q;
560
561
7.62M
    ssize_t
562
7.62M
      x;
563
564
15.6M
    for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
565
8.01M
    {
566
8.01M
      comps_info[i].y_index=y/jp2_image->comps[i].dy*((ssize_t) image->columns+
567
8.01M
        comps_info[i].pad);
568
8.01M
    }
569
7.62M
    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
570
7.62M
    if (q == (Quantum *) NULL)
571
0
      break;
572
7.57G
    for (x=0; x < (ssize_t) image->columns; x++)
573
7.56G
    {
574
15.3G
      for (i=0; i < (ssize_t) jp2_image->numcomps; i++)
575
7.75G
      {
576
7.75G
        double
577
7.75G
          pixel;
578
579
7.75G
        ssize_t
580
7.75G
          index;
581
582
7.75G
        index=comps_info[i].y_index/jp2_image->comps[i].dx+x/
583
7.75G
          jp2_image->comps[i].dx;
584
7.75G
        if ((index < 0) ||
585
7.75G
            (index >= (ssize_t) (jp2_image->comps[i].h*jp2_image->comps[i].w)))
586
140
          {
587
140
            opj_destroy_codec(jp2_codec);
588
140
            opj_image_destroy(jp2_image);
589
140
            ThrowReaderException(CoderError,
590
140
              "IrregularChannelGeometryNotSupported")
591
140
          }
592
7.75G
        pixel=comps_info[i].scale*(jp2_image->comps[i].data[index]+
593
7.75G
          comps_info[i].addition);
594
7.75G
        switch (i)
595
7.75G
        {
596
7.56G
          case 0:
597
7.56G
          {
598
7.56G
            if (jp2_image->numcomps == 1)
599
7.48G
              {
600
7.48G
                SetPixelGray(image,ClampToQuantum(pixel),q);
601
7.48G
                if (jp2_image->comps[i].alpha != 0)
602
654
                  SetPixelAlpha(image,ClampToQuantum(pixel),q);
603
7.48G
                break;
604
7.48G
              }
605
82.9M
            SetPixelRed(image,ClampToQuantum(pixel),q);
606
82.9M
            if (jp2_image->numcomps == 2)
607
206k
              {
608
206k
                SetPixelGreen(image,ClampToQuantum(pixel),q);
609
206k
                SetPixelBlue(image,ClampToQuantum(pixel),q);
610
206k
              }
611
82.9M
            break;
612
7.56G
          }
613
82.9M
          case 1:
614
82.9M
          {
615
82.9M
            if ((jp2_image->numcomps == 2) && (jp2_image->comps[i].alpha != 0))
616
8.44k
              {
617
8.44k
                SetPixelAlpha(image,ClampToQuantum(pixel),q);
618
8.44k
                break;
619
8.44k
              }
620
82.9M
            SetPixelGreen(image,ClampToQuantum(pixel),q);
621
82.9M
            break;
622
82.9M
          }
623
82.7M
          case 2:
624
82.7M
          {
625
82.7M
            SetPixelBlue(image,ClampToQuantum(pixel),q);
626
82.7M
            break;
627
82.9M
          }
628
18.9M
          case 3:
629
18.9M
          {
630
18.9M
            if ((image->alpha_trait & BlendPixelTrait) != 0)
631
83.6k
              SetPixelAlpha(image,ClampToQuantum(pixel),q);
632
18.8M
            else
633
18.8M
              SetPixelChannel(image,MetaPixelChannels,ClampToQuantum(pixel),q);
634
18.9M
            break;
635
82.9M
          }
636
1.64M
          default:
637
1.64M
          {
638
1.64M
            ssize_t
639
1.64M
              offset = MetaPixelChannels+i-3;
640
641
1.64M
            if ((image->alpha_trait & BlendPixelTrait) != 0)
642
79.4k
              offset--;
643
1.64M
            SetPixelChannel(image,(PixelChannel) offset,ClampToQuantum(pixel),
644
1.64M
              q);
645
1.64M
            break;
646
82.9M
          }
647
7.75G
        }
648
7.75G
      }
649
7.56G
      q+=(ptrdiff_t) GetPixelChannels(image);
650
7.56G
    }
651
7.62M
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
652
0
      break;
653
7.62M
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
654
7.62M
      image->rows);
655
7.62M
    if (status == MagickFalse)
656
0
      break;
657
7.62M
  }
658
  /*
659
    Free resources.
660
  */
661
19.1k
  opj_destroy_codec(jp2_codec);
662
19.1k
  opj_image_destroy(jp2_image);
663
19.1k
  (void) CloseBlob(image);
664
19.1k
  if ((image_info->number_scenes != 0) && (image_info->scene != 0))
665
0
    AppendImageToList(&image,CloneImage(image,0,0,MagickTrue,exception));
666
19.1k
  return(GetFirstImageInList(image));
667
19.2k
}
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
15
{
694
15
  char
695
15
    version[MagickPathExtent];
696
697
15
  MagickInfo
698
15
    *entry;
699
700
15
  *version='\0';
701
15
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
702
15
  (void) FormatLocaleString(version,MagickPathExtent,"%s",opj_version());
703
15
#endif
704
15
  entry=AcquireMagickInfo("JP2","JP2","JPEG-2000 File Format Syntax");
705
15
  if (*version != '\0')
706
15
    entry->version=ConstantString(version);
707
15
  entry->mime_type=ConstantString("image/jp2");
708
15
  entry->magick=(IsImageFormatHandler *) IsJP2;
709
15
  entry->flags^=CoderAdjoinFlag;
710
15
  entry->flags|=CoderDecoderSeekableStreamFlag;
711
15
  entry->flags|=CoderEncoderSeekableStreamFlag;
712
15
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
713
15
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
714
15
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
715
15
#endif
716
15
  (void) RegisterMagickInfo(entry);
717
15
  entry=AcquireMagickInfo("JP2","J2C","JPEG-2000 Code Stream Syntax");
718
15
  if (*version != '\0')
719
15
    entry->version=ConstantString(version);
720
15
  entry->mime_type=ConstantString("image/jp2");
721
15
  entry->magick=(IsImageFormatHandler *) IsJ2K;
722
15
  entry->flags^=CoderAdjoinFlag;
723
15
  entry->flags|=CoderDecoderSeekableStreamFlag;
724
15
  entry->flags|=CoderEncoderSeekableStreamFlag;
725
15
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
726
15
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
727
15
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
728
15
#endif
729
15
  (void) RegisterMagickInfo(entry);
730
15
  entry=AcquireMagickInfo("JP2","J2K","JPEG-2000 Code Stream Syntax");
731
15
  if (*version != '\0')
732
15
    entry->version=ConstantString(version);
733
15
  entry->mime_type=ConstantString("image/jp2");
734
15
  entry->magick=(IsImageFormatHandler *) IsJ2K;
735
15
  entry->flags^=CoderAdjoinFlag;
736
15
  entry->flags|=CoderDecoderSeekableStreamFlag;
737
15
  entry->flags|=CoderEncoderSeekableStreamFlag;
738
15
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
739
15
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
740
15
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
741
15
#endif
742
15
  (void) RegisterMagickInfo(entry);
743
15
  entry=AcquireMagickInfo("JP2","JPM","JPEG-2000 File Format Syntax");
744
15
  if (*version != '\0')
745
15
    entry->version=ConstantString(version);
746
15
  entry->mime_type=ConstantString("image/jp2");
747
15
  entry->magick=(IsImageFormatHandler *) IsJP2;
748
15
  entry->flags^=CoderAdjoinFlag;
749
15
  entry->flags|=CoderDecoderSeekableStreamFlag;
750
15
  entry->flags|=CoderEncoderSeekableStreamFlag;
751
15
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
752
15
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
753
15
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
754
15
#endif
755
15
  (void) RegisterMagickInfo(entry);
756
15
  entry=AcquireMagickInfo("JP2","JPT","JPEG-2000 File Format Syntax");
757
15
  if (*version != '\0')
758
15
    entry->version=ConstantString(version);
759
15
  entry->mime_type=ConstantString("image/jp2");
760
15
  entry->magick=(IsImageFormatHandler *) IsJP2;
761
15
  entry->flags^=CoderAdjoinFlag;
762
15
  entry->flags|=CoderDecoderSeekableStreamFlag;
763
15
  entry->flags|=CoderEncoderSeekableStreamFlag;
764
15
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
765
15
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
766
15
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
767
15
#endif
768
15
  (void) RegisterMagickInfo(entry);
769
15
  entry=AcquireMagickInfo("JP2","JPC","JPEG-2000 Code Stream Syntax");
770
15
  if (*version != '\0')
771
15
    entry->version=ConstantString(version);
772
15
  entry->mime_type=ConstantString("image/jp2");
773
15
  entry->magick=(IsImageFormatHandler *) IsJP2;
774
15
  entry->flags^=CoderAdjoinFlag;
775
15
  entry->flags|=CoderDecoderSeekableStreamFlag;
776
15
  entry->flags|=CoderEncoderSeekableStreamFlag;
777
15
#if defined(MAGICKCORE_LIBOPENJP2_DELEGATE)
778
15
  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
779
15
  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
780
15
#endif
781
15
  (void) RegisterMagickInfo(entry);
782
15
  return(MagickImageCoderSignature);
783
15
}
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
814
{
845
  /*
846
    Digital Cinema 4K profile compliant codestream.
847
  */
848
814
  parameters->tile_size_on=OPJ_FALSE;
849
814
  parameters->cp_tdx=1;
850
814
  parameters->cp_tdy=1;
851
814
  parameters->tp_flag='C';
852
814
  parameters->tp_on=1;
853
814
  parameters->cp_tx0=0;
854
814
  parameters->cp_ty0=0;
855
814
  parameters->image_offset_x0=0;
856
814
  parameters->image_offset_y0=0;
857
814
  parameters->cblockw_init=32;
858
814
  parameters->cblockh_init=32;
859
814
  parameters->csty|=0x01;
860
814
  parameters->prog_order=OPJ_CPRL;
861
814
  parameters->roi_compno=(-1);
862
814
  parameters->subsampling_dx=1;
863
814
  parameters->subsampling_dy=1;
864
814
  parameters->irreversible=1;
865
814
  if ((jp2_image->comps[0].w == 2048) || (jp2_image->comps[0].h == 1080))
866
814
    {
867
      /*
868
        Digital Cinema 2K.
869
      */
870
814
#if OPJ_NUMERIC_VERSION >= OPJ_COMPUTE_NUMERIC_VERSION(2,1,0)
871
814
      parameters->rsiz=OPJ_PROFILE_CINEMA_2K;
872
814
      parameters->max_cs_size=OPJ_CINEMA_24_CS;
873
814
      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
814
      if (parameters->numresolution > 6)
880
0
        parameters->numresolution=6;
881
882
814
    }
883
814
  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
814
  parameters->tcp_numlayers=1;
918
814
  parameters->tcp_rates[0]=(((float) jp2_image->numcomps*jp2_image->comps[0].w*
919
814
    jp2_image->comps[0].h*jp2_image->comps[0].prec))/((float)
920
814
    parameters->max_comp_size*8*jp2_image->comps[0].dx*jp2_image->comps[0].dy);
921
814
  parameters->cp_disto_alloc=OPJ_TRUE;
922
814
}
923
924
static inline int CalculateNumResolutions(size_t width,size_t height)
925
8.48k
{
926
8.48k
  int
927
8.48k
    i;
928
929
41.7k
  for (i=1; i < 6; i++)
930
35.8k
    if ((width < ((size_t) MagickULLConstant(1) << i)) ||
931
34.3k
        (height < ((size_t) MagickULLConstant(1) << i)))
932
2.56k
      break;
933
8.48k
  return(i);
934
8.48k
}
935
936
static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image,
937
  ExceptionInfo *exception)
938
8.48k
{
939
8.48k
  const char
940
8.48k
    *option,
941
8.48k
    *property;
942
943
8.48k
  int
944
8.48k
    jp2_status;
945
946
8.48k
  MagickBooleanType
947
8.48k
    status;
948
949
8.48k
  opj_codec_t
950
8.48k
    *jp2_codec;
951
952
8.48k
  OPJ_COLOR_SPACE
953
8.48k
    jp2_colorspace;
954
955
8.48k
  opj_cparameters_t
956
8.48k
    *parameters;
957
958
8.48k
  opj_image_cmptparm_t
959
8.48k
    jp2_info[5];
960
961
8.48k
  opj_image_t
962
8.48k
    *jp2_image;
963
964
8.48k
  opj_stream_t
965
8.48k
    *jp2_stream;
966
967
8.48k
  ssize_t
968
8.48k
    i,
969
8.48k
    y;
970
971
8.48k
  unsigned int
972
8.48k
    channels;
973
974
  /*
975
    Open image file.
976
  */
977
8.48k
  assert(image_info != (const ImageInfo *) NULL);
978
8.48k
  assert(image_info->signature == MagickCoreSignature);
979
8.48k
  assert(image != (Image *) NULL);
980
8.48k
  assert(image->signature == MagickCoreSignature);
981
8.48k
  assert(exception != (ExceptionInfo *) NULL);
982
8.48k
  assert(exception->signature == MagickCoreSignature);
983
8.48k
  if (IsEventLogging() != MagickFalse)
984
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
985
8.48k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
986
8.48k
  if (status == MagickFalse)
987
0
    return(status);
988
  /*
989
    Initialize JPEG 2000 API.
990
  */
991
8.48k
  parameters=(opj_cparameters_t *) AcquireMagickMemory(sizeof(*parameters));
992
8.48k
  if (parameters == (opj_cparameters_t *) NULL)
993
8.48k
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
994
8.48k
  opj_set_default_encoder_parameters(parameters);
995
8.48k
  option=GetImageOption(image_info,"jp2:number-resolutions");
996
8.48k
  if (option != (const char *) NULL)
997
0
    parameters->numresolution=StringToInteger(option);
998
8.48k
  else
999
8.48k
    parameters->numresolution=CalculateNumResolutions(image->columns,
1000
8.48k
      image->rows);
1001
8.48k
  parameters->tcp_numlayers=1;
1002
8.48k
  parameters->tcp_rates[0]=0;  /* lossless */
1003
8.48k
  parameters->cp_disto_alloc=OPJ_TRUE;
1004
8.48k
  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
8.48k
  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
8.48k
  option=GetImageOption(image_info,"jp2:quality");
1036
8.48k
  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
8.48k
  option=GetImageOption(image_info,"jp2:progression-order");
1063
8.48k
  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
8.48k
  option=GetImageOption(image_info,"jp2:rate");
1077
8.48k
  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
8.48k
  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
8.48k
  property=GetImageProperty(image,"comment",exception);
1119
8.48k
  if (property != (const char *) NULL)
1120
0
    parameters->cp_comment=(char *) property;
1121
8.48k
  channels=3;
1122
8.48k
  jp2_colorspace=OPJ_CLRSPC_SRGB;
1123
8.48k
  if (image->colorspace == YUVColorspace)
1124
0
    jp2_colorspace=OPJ_CLRSPC_SYCC;
1125
8.48k
  else
1126
8.48k
    {
1127
8.48k
      if (IsGrayColorspace(image->colorspace) != MagickFalse)
1128
7.93k
        {
1129
7.93k
          channels=1;
1130
7.93k
          jp2_colorspace=OPJ_CLRSPC_GRAY;
1131
7.93k
        }
1132
545
      else
1133
545
        if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1134
160
          (void) TransformImageColorspace(image,sRGBColorspace,exception);
1135
8.48k
      if (image->alpha_trait != UndefinedPixelTrait)
1136
93
        channels++;
1137
8.48k
    }
1138
8.48k
  parameters->tcp_mct=channels == 3 ? 1 : 0;
1139
8.48k
  memset(jp2_info,0,sizeof(jp2_info));
1140
18.1k
  for (i=0; i < (ssize_t) channels; i++)
1141
9.66k
  {
1142
9.66k
    jp2_info[i].prec=(OPJ_UINT32) image->depth;
1143
9.66k
    if ((image->depth == 1) &&
1144
388
        ((LocaleCompare(image_info->magick,"JPT") == 0) ||
1145
388
         (LocaleCompare(image_info->magick,"JP2") == 0)))
1146
82
      jp2_info[i].prec++;  /* OpenJPEG returns exception for depth @ 1 */
1147
9.66k
    jp2_info[i].sgnd=0;
1148
9.66k
    jp2_info[i].dx=(unsigned int) parameters->subsampling_dx;
1149
9.66k
    jp2_info[i].dy=(unsigned int) parameters->subsampling_dy;
1150
9.66k
    jp2_info[i].w=(OPJ_UINT32) image->columns;
1151
9.66k
    jp2_info[i].h=(OPJ_UINT32) image->rows;
1152
9.66k
  }
1153
8.48k
  jp2_image=opj_image_create((OPJ_UINT32) channels,jp2_info,jp2_colorspace);
1154
8.48k
  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
8.48k
  jp2_image->x0=(unsigned int) parameters->image_offset_x0;
1160
8.48k
  jp2_image->y0=(unsigned int) parameters->image_offset_y0;
1161
8.48k
  jp2_image->x1=(unsigned int) (2*parameters->image_offset_x0+
1162
8.48k
    ((ssize_t) image->columns-1)*parameters->subsampling_dx+1);
1163
8.48k
  jp2_image->y1=(unsigned int) (2*parameters->image_offset_y0+
1164
8.48k
    ((ssize_t) image->rows-1)*parameters->subsampling_dy+1);
1165
8.48k
  if ((image->depth == 12) &&
1166
2.87k
      ((image->columns == 2048) || (image->rows == 1080) ||
1167
2.05k
       (image->columns == 4096) || (image->rows == 2160)))
1168
814
    CinemaProfileCompliance(jp2_image,parameters);
1169
8.48k
  if (channels == 4)
1170
57
    jp2_image->comps[3].alpha=1;
1171
8.42k
  else
1172
8.42k
    if ((channels == 2) && (jp2_colorspace == OPJ_CLRSPC_GRAY))
1173
36
      jp2_image->comps[1].alpha=1;
1174
  /*
1175
    Convert to JP2 pixels.
1176
  */
1177
3.55M
  for (y=0; y < (ssize_t) image->rows; y++)
1178
3.54M
  {
1179
3.54M
    const Quantum
1180
3.54M
      *p;
1181
1182
3.54M
    ssize_t
1183
3.54M
      x;
1184
1185
3.54M
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1186
3.54M
    if (p == (const Quantum *) NULL)
1187
0
      break;
1188
3.46G
    for (x=0; x < (ssize_t) image->columns; x++)
1189
3.45G
    {
1190
6.95G
      for (i=0; i < (ssize_t) channels; i++)
1191
3.50G
      {
1192
3.50G
        double
1193
3.50G
          scale;
1194
1195
3.50G
        int
1196
3.50G
          *q;
1197
1198
3.50G
        scale=(double) (((size_t) MagickULLConstant(1) <<
1199
3.50G
          jp2_image->comps[i].prec)-1)/(double) QuantumRange;
1200
3.50G
        q=jp2_image->comps[i].data+(ssize_t) (y*MagickSafeReciprocal(
1201
3.50G
          jp2_image->comps[i].dy)*image->columns*MagickSafeReciprocal(
1202
3.50G
          jp2_image->comps[i].dx)+x*MagickSafeReciprocal(
1203
3.50G
          jp2_image->comps[i].dx));
1204
3.50G
        switch (i)
1205
3.50G
        {
1206
3.45G
          case 0:
1207
3.45G
          {
1208
3.45G
            if (jp2_colorspace == OPJ_CLRSPC_GRAY)
1209
3.43G
              {
1210
3.43G
                *q=(int) (scale*(double) GetPixelGray(image,p));
1211
3.43G
                break;
1212
3.43G
              }
1213
21.2M
            *q=(int) (scale*(double) GetPixelRed(image,p));
1214
21.2M
            break;
1215
3.45G
          }
1216
21.2M
          case 1:
1217
21.2M
          {
1218
21.2M
            if (jp2_colorspace == OPJ_CLRSPC_GRAY)
1219
4.34k
              {
1220
4.34k
                *q=(int) (scale*(double) GetPixelAlpha(image,p));
1221
4.34k
                break;
1222
4.34k
              }
1223
21.2M
            *q=(int) (scale*(double) GetPixelGreen(image,p));
1224
21.2M
            break;
1225
21.2M
          }
1226
21.2M
          case 2:
1227
21.2M
          {
1228
21.2M
            *q=(int) (scale*(double) GetPixelBlue(image,p));
1229
21.2M
            break;
1230
21.2M
          }
1231
24.8k
          case 3:
1232
24.8k
          {
1233
24.8k
            *q=(int) (scale*(double) GetPixelAlpha(image,p));
1234
24.8k
            break;
1235
21.2M
          }
1236
3.50G
        }
1237
3.50G
      }
1238
3.45G
      p+=(ptrdiff_t) GetPixelChannels(image);
1239
3.45G
    }
1240
3.54M
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1241
3.54M
      image->rows);
1242
3.54M
    if (status == MagickFalse)
1243
0
      break;
1244
3.54M
  }
1245
8.48k
  if (LocaleCompare(image_info->magick,"JPT") == 0)
1246
0
    jp2_codec=opj_create_compress(OPJ_CODEC_JPT);
1247
8.48k
  else
1248
8.48k
    if (LocaleCompare(image_info->magick,"J2K") == 0)
1249
2.82k
      jp2_codec=opj_create_compress(OPJ_CODEC_J2K);
1250
5.66k
    else
1251
5.66k
      jp2_codec=opj_create_compress(OPJ_CODEC_JP2);
1252
8.48k
  opj_set_warning_handler(jp2_codec,JP2WarningHandler,exception);
1253
8.48k
  opj_set_error_handler(jp2_codec,JP2ErrorHandler,exception);
1254
8.48k
  opj_setup_encoder(jp2_codec,parameters,jp2_image);
1255
8.48k
  jp2_stream=opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,OPJ_FALSE);
1256
8.48k
  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
8.48k
  opj_stream_set_read_function(jp2_stream,JP2ReadHandler);
1264
8.48k
  opj_stream_set_write_function(jp2_stream,JP2WriteHandler);
1265
8.48k
  opj_stream_set_seek_function(jp2_stream,JP2SeekHandler);
1266
8.48k
  opj_stream_set_skip_function(jp2_stream,JP2SkipHandler);
1267
8.48k
  opj_stream_set_user_data(jp2_stream,image,NULL);
1268
8.48k
  jp2_status=opj_start_compress(jp2_codec,jp2_image,jp2_stream);
1269
8.48k
  if ((jp2_status == 0) || (opj_encode(jp2_codec,jp2_stream) == 0) ||
1270
8.42k
      (opj_end_compress(jp2_codec,jp2_stream) == 0))
1271
61
    {
1272
61
      opj_stream_destroy(jp2_stream);
1273
61
      opj_destroy_codec(jp2_codec);
1274
61
      opj_image_destroy(jp2_image);
1275
61
      parameters=(opj_cparameters_t *) RelinquishMagickMemory(parameters);
1276
61
      ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1277
0
    }
1278
  /*
1279
    Free resources.
1280
  */
1281
8.42k
  opj_stream_destroy(jp2_stream);
1282
8.42k
  opj_destroy_codec(jp2_codec);
1283
8.42k
  opj_image_destroy(jp2_image);
1284
8.42k
  parameters=(opj_cparameters_t *) RelinquishMagickMemory(parameters);
1285
8.42k
  if (CloseBlob(image) == MagickFalse)
1286
0
    status=MagickFalse;
1287
8.42k
  return(status);
1288
8.48k
}
1289
#endif