Coverage Report

Created: 2026-07-25 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/jp2.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
%
5
% This program is covered by multiple licenses, which are described in
6
% Copyright.txt. You should have received a copy of Copyright.txt with this
7
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8
%
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10
%                                                                             %
11
%                                                                             %
12
%                                                                             %
13
%                              JJJ  PPPP    222                               %
14
%                               J   P   P  2   2                              %
15
%                               J   PPPP     22                               %
16
%                            J  J   P       2                                 %
17
%                             JJ    P      22222                              %
18
%                                                                             %
19
%                                                                             %
20
%                    Read/Write JPEG-2000 Image Format.                       %
21
%                                                                             %
22
%                                                                             %
23
%                                John Cristy                                  %
24
%                                Nathan Brown                                 %
25
%                                 June 2001                                   %
26
%                              Bob Friesenhahn                                %
27
%                               February 2003                                 %
28
%                                                                             %
29
%                                                                             %
30
%                                                                             %
31
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32
%
33
%
34
*/
35

36
/*
37
  Include declarations.
38
*/
39
#include "magick/studio.h"
40
#include "magick/analyze.h"
41
#include "magick/blob.h"
42
#include "magick/pixel_cache.h"
43
#include "magick/log.h"
44
#include "magick/magick.h"
45
#include "magick/monitor.h"
46
#include "magick/profile.h"
47
#include "magick/resource.h"
48
#include "magick/utility.h"
49
#include "magick/static.h"
50
#if defined(HasJP2)
51
#  if !defined(uchar)
52
#    define uchar  unsigned char
53
#  endif
54
#  if !defined(ushort)
55
#    define ushort  unsigned short
56
#  endif
57
#  if !defined(uint)
58
#    define uint  unsigned int
59
#  endif
60
#  if !defined(longlong)
61
#    define longlong  long long
62
#  endif
63
#  if !defined(ulonglong)
64
#    define ulonglong  unsigned long long
65
#  endif
66
67
#  ifdef __VMS
68
#    define JAS_VERSION 1.700.0
69
#    define PACKAGE jasper
70
#    define VERSION 1.700.0
71
#  endif /* ifdef __VMS */
72
#  undef PACKAGE_NAME
73
#  undef PACKAGE_STRING
74
#  undef PACKAGE_TARNAME
75
#  undef PACKAGE_VERSION
76
#  include "jasper/jasper.h"
77
#  undef PACKAGE_NAME
78
#  undef PACKAGE_STRING
79
#  undef PACKAGE_TARNAME
80
#  undef PACKAGE_VERSION
81
/*
82
  Old JasPer uses non-persistent '!defined(EXCLUDE_FOO_SUPPORT)' and
83
  modern JasPer uses persistent 'if defined(JAS_INCLUDE_FOO_CODEC)'
84
  in jas_image.h
85
*/
86
#  if defined(EXCLUDE_JP2_SUPPORT)
87
#    undef HAVE_JP2_DECODE
88
#  endif
89
#  if defined(EXCLUDE_JPC_SUPPORT)
90
#    undef HAVE_JPC_DECODE
91
#  endif
92
#  if defined(EXCLUDE_PGX_SUPPORT)
93
#    undef HAVE_PGX_DECODE
94
#  endif
95
96
#if defined(HAVE_JAS_INIT_LIBRARY)
97
# define HAVE_JAS_STREAM_IO_V3
98
#endif
99
100
#if 0
101
/* Development JasPer 3.0.0 jas_init_library() is not yet ready for our purposes */
102
#if !(defined(MAGICK_ENABLE_JAS_INIT_LIBRARY) && MAGICK_ENABLE_JAS_INIT_LIBRARY)
103
#undef HAVE_JAS_INIT_LIBRARY
104
#endif /* if !(defined(MAGICK_ENABLE_JAS_INIT_LIBRARY) && MAGICK_ENABLE_JAS_INIT_LIBRARY) */
105
#endif
106
107
#if defined(HAVE_PTHREAD) || defined(MSWINDOWS) || defined(HAVE_OPENMP)
108
9
#  define JP2_HAVE_THREADS 1
109
#else
110
#  define JP2_HAVE_THREADS 0
111
#endif
112
113

114
/*
115
  Forward declarations.
116
*/
117
static unsigned int
118
  WriteJP2Image(const ImageInfo *,Image *);
119
120
static MagickBool jasper_initialized=MagickFalse;
121
static const char jasper_enc_options[][11] =
122
  {
123
    "cblkheight",
124
    "cblkwidth",
125
    "debug",
126
    "eph",
127
    "ilyrrates",
128
    "imgareatlx",
129
    "imgareatly",
130
    "lazy",
131
    "mode",
132
    "nomct",
133
    "numgbits",
134
    "numrlvls",
135
    "prcheight",
136
    "prcwidth",
137
    "prg",
138
    "pterm",
139
    "rate",
140
    "resetprob",
141
    "segsym",
142
    "sop",
143
    "termall",
144
    "tilegrdtlx",
145
    "tilegrdtly",
146
    "tileheight",
147
    "tilewidth",
148
    "vcausal"
149
  };
150
151
static const char jasper_dec_options[][12] =
152
  {
153
    "allow_trunc",
154
    "debug",
155
    "max_samples",
156
    "maxlyrs",
157
    "maxpkts",
158
    "version"
159
  };
160
161

162
/*
163
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164
%                                                                             %
165
%                                                                             %
166
%                                                                             %
167
%   I s J P 2                                                                 %
168
%                                                                             %
169
%                                                                             %
170
%                                                                             %
171
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172
%
173
%  Method IsJP2 returns True if the image format type, identified by the
174
%  magick string, is JP2.
175
%
176
%  The format of the IsJP2 method is:
177
%
178
%      unsigned int IsJP2(const unsigned char *magick,const size_t length)
179
%
180
%  A description of each parameter follows:
181
%
182
%    o status:  Method IsJP2 returns True if the image format type is JP2.
183
%
184
%    o magick: This string is generally the first few bytes of an image file
185
%      or blob.
186
%
187
%    o length: Specifies the length of the magick string.
188
%
189
%
190
*/
191
static unsigned int IsJP2(const unsigned char *magick,const size_t length)
192
417k
{
193
417k
  if (length < 9)
194
0
    return(False);
195
417k
  if (memcmp(magick+4,"\152\120\040\040\015",5) == 0)
196
13.2k
    return(True);
197
403k
  return(False);
198
417k
}
199

200
/*
201
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202
%                                                                             %
203
%                                                                             %
204
%                                                                             %
205
%   I s J P C                                                                 %
206
%                                                                             %
207
%                                                                             %
208
%                                                                             %
209
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210
%
211
%  Method IsJPC returns True if the image format type, identified by the
212
%  magick string, is JPC.
213
%
214
%  The format of the IsJPC method is:
215
%
216
%      unsigned int IsJPC(const unsigned char *magick,const size_t length)
217
%
218
%  A description of each parameter follows:
219
%
220
%    o status:  Method IsJPC returns True if the image format type is JPC.
221
%
222
%    o magick: This string is generally the first few bytes of an image file
223
%      or blob.
224
%
225
%    o length: Specifies the length of the magick string.
226
%
227
%
228
*/
229
static unsigned int IsJPC(const unsigned char *magick,const size_t length)
230
417k
{
231
417k
  if (length < 2)
232
0
    return(False);
233
417k
  if (memcmp(magick,"\377\117",2) == 0)
234
201k
    return(True);
235
215k
  return(False);
236
417k
}
237

238
/*
239
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240
%                                                                             %
241
%                                                                             %
242
%                                                                             %
243
%   I s P G X                                                                 %
244
%                                                                             %
245
%                                                                             %
246
%                                                                             %
247
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248
%
249
%  Method IsPGX returns True if the image format type, identified by the
250
%  magick string, is PGX. PGX is an uncompressed raster image file format
251
%  used in JPEG 2000 conformance testing. PGX file stores only a single
252
%  component, so it is limited to grayscale.
253
%
254
%  The format of the IsPGX method is:
255
%
256
%      unsigned int IsPGX(const unsigned char *magick,const size_t length)
257
%
258
%  A description of each parameter follows:
259
%
260
%    o status:  Method IsPGX returns True if the image format type is PGX.
261
%
262
%    o magick: This string is generally the first few bytes of an image file
263
%      or blob.
264
%
265
%    o length: Specifies the length of the magick string.
266
%
267
%
268
*/
269
static unsigned int IsPGX(const unsigned char *magick,const size_t length)
270
417k
{
271
417k
  if (length < 5)
272
0
    return(False);
273
417k
  if ((memcmp(magick,"PG ML",5) == 0) || (memcmp(magick,"PG LM",5) == 0))
274
204k
    return(True);
275
212k
  return(False);
276
417k
}
277

278
/*
279
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280
%                                                                             %
281
%                                                                             %
282
%                                                                             %
283
%   R e a d J P 2 I m a g e                                                   %
284
%                                                                             %
285
%                                                                             %
286
%                                                                             %
287
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288
%
289
%  Method ReadJP2Image reads a JPEG 2000 Image file (JP2) or JPEG 2000
290
%  codestream (JPC) image file and returns it.  It allocates the memory
291
%  necessary for the new Image structure and returns a pointer to the new
292
%  image or set of images.
293
%
294
%  JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
295
%
296
%  The format of the ReadJP2Image method is:
297
%
298
%      Image *ReadJP2Image(const ImageInfo *image_info,
299
%                          ExceptionInfo *exception)
300
%
301
%  A description of each parameter follows:
302
%
303
%    o image:  Method ReadJP2Image returns a pointer to the image after
304
%      reading.  A null image is returned if there is a memory shortage or
305
%      if the image cannot be read.
306
%
307
%    o image_info: Specifies a pointer to a ImageInfo structure.
308
%
309
%    o exception: return any errors or warnings in this structure.
310
%
311
*/
312
313
typedef struct _StreamManager
314
{
315
  jas_stream_t
316
    *stream;
317
318
  Image
319
    *image;
320
} StreamManager;
321
322
/*
323
  I/O read/write callbacks changed
324
325
  Cnt argument changed from 'int' to 'unsigned' on 6/29/20 (2.0.19).
326
327
  Write write buf pointer changed from 'char *' to 'const char *' on 8/14/20
328
329
  Old interface:
330
  int (*read_)(jas_stream_obj_t *obj, char *buf, int cnt);
331
  int (*write_)(jas_stream_obj_t *obj, char *buf, int cnt);
332
333
  New interface:
334
  int (*read_)(jas_stream_obj_t *obj, char *buf, unsigned cnt);
335
  int (*write_)(jas_stream_obj_t *obj, const char *buf, unsigned cnt);
336
337
  In Jasper 3.0.0 the interface changed again:
338
  ssize_t (*read_)(jas_stream_obj_t *obj, char *buf, size_t cnt);
339
  ssize_t (*write_)(jas_stream_obj_t *obj, const char *buf, size_t cnt);
340
341
  We have yet to find a useful way to determine the version of the
342
  JasPer library using the C pre-processor.
343
 */
344
345
/* Read characters from a file object. */
346
/* ssize_t (*read_)(jas_stream_obj_t *obj, char *buf, size_t cnt); */
347
#if defined(HAVE_JAS_STREAM_IO_V3)
348
static ssize_t BlobRead(jas_stream_obj_t *obj, char *buf, size_t cnt)
349
#else
350
static int BlobRead(jas_stream_obj_t *obj, char *buf, unsigned cnt)
351
#endif
352
49.8M
{
353
49.8M
  size_t
354
49.8M
    count;
355
356
49.8M
  StreamManager
357
49.8M
    *source = (StreamManager *) obj;
358
359
49.8M
  count=ReadBlob(source->image,(size_t) cnt,(void *) buf);
360
49.8M
#if defined(HAVE_JAS_STREAM_IO_V3)
361
49.8M
  return (count);
362
#else
363
  if ((size_t)((int) count) != count)
364
    count = 0;
365
  return ((int) count);
366
#endif
367
49.8M
}
368
369
/* Write characters to a file object. */
370
/* ssize_t (*write_)(jas_stream_obj_t *obj, const char *buf, size_t cnt); */
371
#if defined(HAVE_JAS_STREAM_IO_V3)
372
static ssize_t  BlobWrite(jas_stream_obj_t *obj, const char *buf, size_t cnt)
373
#else
374
static int BlobWrite(jas_stream_obj_t *obj, const char *buf, unsigned cnt)
375
#endif
376
4.40M
{
377
4.40M
  size_t
378
4.40M
    count;
379
380
4.40M
  StreamManager
381
4.40M
    *source = (StreamManager *) obj;
382
383
4.40M
  count=WriteBlob(source->image,(size_t) cnt,(void *) buf);
384
4.40M
#if defined(HAVE_JAS_STREAM_IO_V3)
385
4.40M
  return(count);
386
#else
387
  if ((size_t)((int) count) != count)
388
    count = 0;
389
  return ((int) count);
390
#endif
391
4.40M
}
392
393
/* Set the position for a file object. */
394
/* long (*seek_)(jas_stream_obj_t *obj, long offset, int origin); */
395
static long BlobSeek(jas_stream_obj_t *obj,long offset,int origin)
396
0
{
397
0
  StreamManager
398
0
    *source = (StreamManager *) obj;
399
400
0
  return (SeekBlob(source->image,offset,origin));
401
0
}
402
403
/* Close a file object. */
404
/* int (*close_)(jas_stream_obj_t *obj); */
405
static int BlobClose(jas_stream_obj_t *obj)
406
418k
{
407
418k
  int status;
408
418k
  StreamManager
409
418k
    *source = (StreamManager *) obj;
410
411
418k
  status = CloseBlob(source->image);
412
418k
  jas_free(source);
413
418k
  return (status == 0 ? EOF : 0);
414
418k
}
415
416
417
static jas_stream_t *JP2StreamManager(jas_stream_ops_t *stream_ops, Image *image)
418
418k
{
419
418k
  jas_stream_t
420
418k
    *stream;
421
422
418k
  StreamManager
423
418k
    *source;
424
425
418k
  stream=(jas_stream_t *) jas_malloc(sizeof(jas_stream_t));
426
418k
  if (stream == (jas_stream_t *) NULL)
427
0
    return((jas_stream_t *) NULL);
428
418k
  (void) memset(stream,0,sizeof(jas_stream_t));
429
418k
  stream->rwlimit_=(-1);
430
418k
  stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
431
418k
  if (stream->obj_ == (jas_stream_obj_t *) NULL)
432
0
    {
433
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
434
0
                            "jas_malloc() failed!");
435
0
      jas_free(stream);
436
0
      return((jas_stream_t *) NULL);
437
0
    }
438
418k
  stream->ops_=stream_ops;
439
418k
  stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
440
418k
  stream->bufbase_=stream->tinybuf_;
441
418k
  stream->bufsize_=1;
442
418k
  stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
443
418k
  stream->ptr_=stream->bufstart_;
444
418k
  stream->bufmode_|=JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK;
445
418k
  source=(StreamManager *) stream->obj_;
446
418k
  source->image=image;
447
418k
  return(stream);
448
418k
}
449
450
#if defined(HAVE_JAS_INIT_LIBRARY)
451
423k
#  define JAS_CLEANUP_THREAD() jas_cleanup_thread()
452
#else
453
#  define JAS_CLEANUP_THREAD()
454
#endif
455
456
#define ThrowJP2ReaderException(code_,reason_,image_)                   \
457
390k
  {                                                                     \
458
403k
    for (component=0; component < (long) number_components; component++) \
459
390k
      MagickFreeResourceLimitedMemory(Quantum *,channel_lut[component]); \
460
390k
    if (pixels)                                                         \
461
390k
      jas_matrix_destroy(pixels);                                       \
462
390k
    if (jp2_stream)                                                     \
463
390k
      (void) jas_stream_close(jp2_stream);                              \
464
390k
    if (jp2_image)                                                      \
465
390k
      jas_image_destroy(jp2_image);                                     \
466
390k
    MagickFreeMemory(options);                                          \
467
390k
    JAS_CLEANUP_THREAD();                                               \
468
390k
    ThrowReaderException(code_,reason_,image_);                         \
469
0
  }
470
471
#define ThrowJP2WriterException(code_,reason_,image_)   \
472
2
  {                                                     \
473
2
    JAS_CLEANUP_THREAD();                               \
474
2
    ThrowWriterException(code_,reason_,image_);         \
475
0
  }
476
477
/*
478
  Initialize Jasper
479
*/
480
#if HAVE_JAS_INIT_LIBRARY
481
static void *alloc_rlm(struct jas_allocator_s *allocator, size_t size)
482
331M
{
483
331M
  char *p;
484
331M
  (void) allocator;
485
  /* JasPer expects its allocator to return non-null for zero size */
486
331M
  p=(char *) _MagickAllocateResourceLimitedMemoryLoc((size == 0 ? 1 : size),GetMagickModule());
487
  /* fprintf(stderr,"alloc_rlm(%p, %zu) -> %p\n", allocator, size, p); */
488
331M
  return p;
489
331M
}
490
static void free_rlm(struct jas_allocator_s *allocator, void *pointer)
491
331M
{
492
331M
  (void) allocator;
493
  /* fprintf(stderr,"free_rlm(%p, %p\n", allocator, pointer); */
494
331M
  _MagickFreeResourceLimitedMemoryLoc(pointer,GetMagickModule());
495
331M
}
496
static void *realloc_rlm(struct jas_allocator_s *allocator, void *pointer,
497
                         size_t new_size)
498
65.5k
{
499
65.5k
  char *p;
500
65.5k
  (void) allocator;
501
65.5k
  p =(char *) _MagickReallocateResourceLimitedMemoryLoc(pointer, 1,new_size,0,GetMagickModule());
502
  /* fprintf(stderr,"realloc_rlm(%p, %p, %zu) -> %p\n", allocator, pointer, new_size, p); */
503
65.5k
  return p;
504
65.5k
}
505
#endif /* if HAVE_JAS_INIT_LIBRARY */
506
static MagickPassFail initialize_jasper(ExceptionInfo *exception)
507
423k
{
508
423k
  (void) exception;
509
423k
  if (!jasper_initialized)
510
9
    {
511
9
#if HAVE_JAS_INIT_LIBRARY
512
9
      {
513
        /* static jas_std_allocator_t allocator; */
514
9
        static jas_allocator_t allocator;
515
516
9
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
517
9
                              "Initializing JasPer...");
518
        /*
519
          Configure the library using the default configuration settings.
520
        */
521
9
        jas_conf_clear();
522
523
        /*
524
          Provide our own resource-limited memory allocation
525
          functions.
526
527
          See src/libjasper/include/jasper/jas_malloc.h
528
        */
529
530
        /*
531
          Function to clean up the allocator when no longer needed.
532
          The allocator cannot be used after the clean-up operation is performed.
533
          This function pointer may be null, in which case the clean-up operation
534
          is treated as a no-op.
535
        */
536
9
        allocator.cleanup = 0;
537
538
        /*
539
          Function to allocate memory.
540
          This function should have behavior similar to malloc.
541
        */
542
9
        allocator.alloc = alloc_rlm;
543
544
        /*
545
          Function to deallocate memory.
546
          This function should have behavior similar to free.
547
        */
548
9
        allocator.free = free_rlm;
549
550
        /*
551
          Function to reallocate memory.
552
          This function should have behavior similar to realloc.
553
        */
554
9
        allocator.realloc = realloc_rlm;
555
        /* jas_std_allocator_init(&allocator); */ /* Uses JasPer allocators */
556
9
        jas_conf_set_allocator(&allocator); /* Assigns jas_allocator_t to jas_conf.allocator in library */
557
        /* jas_conf_set_debug_level(cmdopts->debug); */
558
559
        /*
560
          Tell JasPer how much memory it could ever be allowed to use.
561
        */
562
9
        {
563
9
          size_t max_mem_gm = (size_t) GetMagickResourceLimit(MemoryResource);
564
9
          size_t max_mem_jas = jas_get_total_mem_size();
565
9
          if (max_mem_jas == 0)
566
0
            max_mem_jas=max_mem_gm;
567
9
          jas_conf_set_max_mem_usage(Min(max_mem_jas,max_mem_gm));
568
9
        }
569
570
        /*
571
          Inform JasPer that app may be multi-threaded
572
        */
573
9
        jas_conf_set_multithread(JP2_HAVE_THREADS);
574
575
        /* Perform global initialization for the JasPer library. */
576
9
        if (jas_init_library() == 0)
577
9
          {
578
9
            jasper_initialized=MagickTrue;
579
            /* jas_set_debug_level(110); */
580
9
          }
581
0
        else
582
0
          {
583
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
584
0
                                  "jas_init_library() failed!");
585
0
          }
586
9
      }
587
#else
588
      {
589
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
590
                              "Initializing JasPer...");
591
        if (jas_init() == 0)
592
          {
593
            jasper_initialized=MagickTrue;
594
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
595
                                "Initialized JasPer");
596
          }
597
        else
598
          {
599
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
600
                                  "jas_init() failed!");
601
          }
602
      }
603
#endif  /* HAVE_JAS_INIT_LIBRARY */
604
605
9
      if (!jasper_initialized)
606
0
        {
607
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
608
0
                                "Failed to initialize JasPer!");
609
0
        }
610
9
    }
611
612
423k
  return jasper_initialized ? MagickPass : MagickFail;
613
423k
}
614
615
616
/*
617
  Cleanup Jasper
618
*/
619
static void cleanup_jasper(void)
620
0
{
621
0
  if (jasper_initialized)
622
0
    {
623
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
624
0
                            "Destroying JasPer...");
625
0
#if HAVE_JAS_INIT_LIBRARY
626
      /* Perform global cleanup for the JasPer library. */
627
0
      jas_cleanup_library();
628
#else
629
      jas_cleanup();
630
#endif /* if HAVE_JAS_INIT_LIBRARY */
631
0
      jasper_initialized=MagickFalse;
632
0
    }
633
0
}
634
635
static Image *ReadJP2Image(const ImageInfo *image_info,
636
                           ExceptionInfo *exception)
637
422k
{
638
422k
  Image
639
422k
    *image;
640
641
422k
  long
642
422k
    y;
643
644
422k
  jas_image_t
645
422k
    *jp2_image = (jas_image_t *) NULL;
646
647
422k
  jas_matrix_t
648
422k
    *pixels = (jas_matrix_t *) NULL;
649
650
422k
  jas_stream_ops_t
651
422k
    StreamOperators =
652
422k
    {
653
422k
      BlobRead,
654
422k
      BlobWrite,
655
422k
      BlobSeek,
656
422k
      BlobClose
657
422k
    };
658
659
422k
  jas_stream_t
660
422k
    *jp2_stream = (jas_stream_t *) NULL;
661
662
422k
  register long
663
422k
    x;
664
665
422k
  register PixelPacket
666
422k
    *q;
667
668
422k
  magick_off_t
669
422k
    pos;
670
671
422k
  int
672
422k
    component,
673
422k
    components[4],
674
422k
    number_components=0;
675
676
422k
  Quantum
677
422k
    *channel_lut[4];
678
679
422k
  char
680
422k
    option_keyval[MaxTextExtent],
681
422k
    *options = NULL;
682
683
422k
  unsigned int
684
422k
    status;
685
686
422k
  MagickBool
687
422k
    jp2_hdr,
688
422k
    jpc_hdr,
689
422k
    pgx_hdr;
690
691
  /*
692
    Initialize Jasper
693
  */
694
422k
  if (initialize_jasper(exception) != MagickPass)
695
0
    {
696
0
      return (Image *) NULL;
697
0
    }
698
699
422k
#if HAVE_JAS_INIT_LIBRARY
700
  /*
701
    Perform any per-thread initialization for the JasPer library.
702
  */
703
422k
  if (jas_init_thread())
704
0
    {
705
      /* Handle the initialization error. */
706
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
707
0
                            "jas_init_thread() failed!");
708
0
      return (Image *) NULL;
709
0
    }
710
422k
#endif /* if HAVE_JAS_INIT_LIBRARY */
711
712
  /*
713
    Open image file.
714
  */
715
422k
  assert(image_info != (const ImageInfo *) NULL);
716
422k
  assert(image_info->signature == MagickSignature);
717
422k
  assert(exception != (ExceptionInfo *) NULL);
718
422k
  assert(exception->signature == MagickSignature);
719
422k
  (void) memset(channel_lut,0,sizeof(channel_lut));
720
422k
  image=AllocateImage(image_info);
721
422k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
722
422k
  if (status == False)
723
422k
    ThrowJP2ReaderException(FileOpenError,UnableToOpenFile,image);
724
725
422k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
726
422k
                        "Requested format is \"%s\"",
727
422k
                        image_info->magick);
728
729
  /*
730
    Get the header and auto-detect apparent format.
731
  */
732
422k
  {
733
422k
    size_t
734
422k
      magick_length;
735
736
422k
    unsigned char
737
422k
      magick[16];
738
739
422k
    const MagickInfo
740
422k
      *magick_info;
741
742
    /* Get current seek position (normally 0) */
743
422k
    pos=TellBlob(image);
744
422k
    if (pos < 0)
745
0
      {
746
0
        ThrowJP2ReaderException(BlobError,UnableToObtainOffset,image);
747
0
      }
748
749
    /* Read header */
750
422k
    if ((magick_length=ReadBlob(image,sizeof(magick),magick)) != sizeof(magick))
751
4.94k
      {
752
4.94k
        ThrowJP2ReaderException(CorruptImageError,UnexpectedEndOfFile,image);
753
0
      }
754
755
    /* Restore seek position */
756
417k
    if (SeekBlob(image,pos,SEEK_SET) != pos)
757
0
      {
758
0
        ThrowJP2ReaderException(BlobError,UnableToSeekToOffset,image);
759
0
      }
760
761
    /* Inspect header to see what it might actually be */
762
417k
    jp2_hdr=IsJP2(magick,sizeof(magick));
763
417k
    jpc_hdr=IsJPC(magick,sizeof(magick));
764
417k
    pgx_hdr=IsPGX(magick,sizeof(magick));
765
766
    /*
767
      If input format was previously auto-detected or specified, then
768
      assure that header matches what was specified.
769
    */
770
417k
    if (((LocaleCompare(image_info->magick,"JP2") == 0) && !jp2_hdr) ||
771
417k
        (((LocaleCompare(image_info->magick,"JPC") == 0) ||
772
219k
          (LocaleCompare(image_info->magick,"J2C") == 0)) && !jpc_hdr) ||
773
417k
        ((LocaleCompare(image_info->magick,"PGX") == 0) && !pgx_hdr))
774
195
      {
775
195
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
776
195
                              "Not a \"%s\" file!", image_info->magick);
777
195
        ThrowJP2ReaderException(CorruptImageError,ImproperImageHeader,image);
778
0
      }
779
780
    /*
781
      Throw exception if header is not one we expect.
782
    */
783
416k
    if (!jp2_hdr && !jpc_hdr && !pgx_hdr)
784
0
      {
785
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
786
0
                              "Header is not a supported type for this coder");
787
0
        ThrowJP2ReaderException(CorruptImageError,ImproperImageHeader,image);
788
0
      }
789
790
    /*
791
      Check if we are allowed to decode this format.
792
    */
793
416k
    if (((magick_info = GetMagickInfo(image_info->magick,exception)) ==
794
416k
         (const MagickInfo *) NULL) ||
795
416k
        (magick_info->decoder == (DecoderHandler) NULL))
796
0
      {
797
0
        ThrowJP2ReaderException(DelegateError,UnableToDecodeImageFile,image);
798
0
      }
799
416k
  }
800
801
  /*
802
    Obtain a JP2 Stream.
803
  */
804
416k
  jp2_stream=JP2StreamManager(&StreamOperators, image);
805
416k
  if (jp2_stream == (jas_stream_t *) NULL)
806
416k
    ThrowJP2ReaderException(DelegateError,UnableToManageJP2Stream,image);
807
808
  /*
809
    Support passing Jasper options.
810
  */
811
416k
  {
812
416k
    unsigned int
813
416k
      i;
814
815
416k
    MagickBool
816
416k
      max_samples_specified = MagickFalse;
817
818
2.91M
    for (i=0; i < ArraySize(jasper_dec_options); i++)
819
2.50M
      {
820
2.50M
        const char
821
2.50M
          *option = jasper_dec_options[i];
822
823
2.50M
        const char
824
2.50M
          *value;
825
826
2.50M
        if ((value=AccessDefinition(image_info,"jp2",option)) != NULL)
827
0
          {
828
0
            MagickFormatString(option_keyval,sizeof(option_keyval),"%s=%.1024s ",option,value);
829
0
            ConcatenateString(&options,option_keyval);
830
831
0
            if (LocaleCompare(option,"max_samples") == 0)
832
0
              max_samples_specified=MagickTrue;
833
834
            /* Setting debug mode seems to require extra assistance */
835
0
            if (LocaleCompare(option,"debug") == 0)
836
0
              jas_setdbglevel(atoi(value));
837
0
          }
838
2.50M
      }
839
840
    /*
841
      If max_samples argument was not specified, then pass options
842
      argument which specifies "max_samples" to cap memory usage.
843
    */
844
416k
    if (!max_samples_specified)
845
416k
      {
846
416k
        const magick_uintmax_t width_limit = (magick_uintmax_t) GetMagickResourceLimit(WidthResource);
847
416k
        const magick_uintmax_t height_limit = (magick_uintmax_t) GetMagickResourceLimit(HeightResource);
848
416k
        const magick_uintmax_t max_samples_rectangle = width_limit*height_limit;
849
416k
        const magick_uintmax_t max_samples_pixels = (magick_uintmax_t) GetMagickResourceLimit(PixelsResource);
850
416k
        const magick_uintmax_t max_samples = Min(max_samples_rectangle,max_samples_pixels);
851
852
416k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
853
416k
                              "max_samples limits: max_samples_rectangle = "
854
416k
                              "%" MAGICK_UINTMAX_F "u, max_samples_pixels = %" MAGICK_UINTMAX_F "u",
855
416k
                              max_samples_rectangle, max_samples_pixels);
856
857
416k
        MagickFormatString(option_keyval,sizeof(option_keyval),"max_samples=%" MAGICK_UINTMAX_F "u ", max_samples*3);
858
416k
        ConcatenateString(&options,option_keyval);
859
416k
      }
860
861
416k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
862
416k
                          "JP2 options = \"%s\"", options);
863
416k
  }
864
865
  /*
866
    Decode
867
  */
868
416k
  {
869
416k
    int
870
416k
      jas_fmt = -1;
871
872
416k
    const char *
873
416k
      jas_fmt_str = NULL;
874
875
416k
    if (jp2_hdr)
876
13.2k
      jas_fmt_str = "jp2";
877
403k
    else if (jpc_hdr)
878
199k
      jas_fmt_str = "jpc";
879
204k
    else if (pgx_hdr)
880
204k
      jas_fmt_str = "pgx";
881
882
416k
    if (jas_fmt_str != (const char *) NULL)
883
416k
      {
884
416k
        jas_fmt = jas_image_strtofmt(jas_fmt_str);
885
416k
        if (-1 != jas_fmt)
886
416k
          {
887
416k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
888
416k
                                  "Decoding %s...", jas_fmt_str);
889
416k
            jp2_image=jas_image_decode(jp2_stream,jas_fmt,options);
890
416k
          }
891
0
        else
892
0
          {
893
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
894
0
                                  "JasPer does not support format %s!",
895
0
                                  jas_fmt_str);
896
0
          }
897
416k
      }
898
416k
  }
899
900
416k
  MagickFreeMemory(options);
901
902
416k
  if (jp2_image == (jas_image_t *) NULL)
903
372k
    ThrowJP2ReaderException(DelegateError,UnableToDecodeImageFile,image);
904
905
  /*
906
    Validate that we can handle the image and obtain component
907
    indexes.
908
  */
909
44.3k
  switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
910
44.3k
    {
911
332
    case JAS_CLRSPC_FAM_RGB:
912
332
      {
913
332
        if (((components[0]=
914
332
              jas_image_getcmptbytype(jp2_image,
915
332
                                      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0) ||
916
332
            ((components[1]=
917
332
              jas_image_getcmptbytype(jp2_image,
918
332
                                      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0) ||
919
332
            ((components[2]=
920
332
              jas_image_getcmptbytype(jp2_image,
921
332
                                      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0))
922
0
          {
923
0
            ThrowJP2ReaderException(CorruptImageError,MissingImageChannel,image);
924
0
          }
925
332
        number_components=3;
926
332
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
927
332
                              "Image is in RGB colorspace family");
928
332
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
929
332
                              "RED is in channel %d, GREEN is in channel %d, BLUE is in channel %d",
930
332
                              components[0],components[1],components[2]);
931
932
332
        if((components[3]=jas_image_getcmptbytype(jp2_image,
933
332
                                                  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY))) > 0)
934
0
          {
935
0
            image->matte=MagickTrue;
936
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
937
0
                                  "OPACITY is in channel %d",components[3]);
938
0
            number_components++;
939
0
          }
940
332
        break;
941
332
      }
942
44.0k
    case JAS_CLRSPC_FAM_GRAY:
943
44.0k
      {
944
44.0k
        if ((components[0]=
945
44.0k
             jas_image_getcmptbytype(jp2_image,
946
44.0k
                                     JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y))) < 0)
947
44.0k
          ThrowJP2ReaderException(CorruptImageError,MissingImageChannel,image);
948
44.0k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
949
44.0k
                              "Image is in GRAY colorspace family");
950
44.0k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
951
44.0k
                              "GRAY is in channel %d",components[0]);
952
44.0k
        number_components=1;
953
44.0k
        break;
954
44.0k
      }
955
0
    case JAS_CLRSPC_FAM_YCBCR:
956
0
      {
957
0
        components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
958
0
        components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
959
0
        components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
960
0
        if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
961
0
          ThrowJP2ReaderException(CorruptImageError,MissingImageChannel,image);
962
0
        number_components=3;
963
0
        components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_OPACITY);
964
0
        if (components[3] > 0)
965
0
          {
966
0
            image->matte=True;
967
0
            number_components++;
968
0
          }
969
0
        image->colorspace=YCbCrColorspace;
970
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
971
0
                              "Image is in YCBCR colorspace family");
972
0
        break;
973
0
      }
974
0
    default:
975
0
      {
976
0
        ThrowJP2ReaderException(CoderError,ColorspaceModelIsNotSupported,image);
977
0
      }
978
44.3k
    }
979
44.3k
  image->columns=jas_image_width(jp2_image);
980
44.3k
  image->rows=jas_image_height(jp2_image);
981
44.3k
  if (image->logging)
982
44.3k
    {
983
44.3k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
984
44.3k
                            "columns=%lu rows=%lu components=%d",image->columns,image->rows,
985
44.3k
                            number_components);
986
89.3k
      for (component=0; component < number_components; component++)
987
45.0k
        {
988
45.0k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
989
45.0k
                                "Component %u:\n"
990
45.0k
                                "    width                         = %ld\n" /* width */
991
45.0k
                                "    height                        = %ld\n" /* height */
992
45.0k
                                "    tl x,y coordinate             = %ld,%ld\n" /* x,y-coordinates of the top-left corner */
993
45.0k
                                "    br x,y coordinate             = %ld,%ld\n" /* x,y-coordinates of the bottom-right corner */
994
45.0k
                                "    horizontal subsampling factor = %ld\n" /* horizontal subsampling factor */
995
45.0k
                                "    vertical subsampling factor   = %ld\n" /* vertical subsampling factor */
996
45.0k
                                "    depth                         = %u\n"  /* depth */
997
45.0k
                                "    signed sample data            = %d",   /* signedness of the sample data (true == signed) */
998
45.0k
                                component,
999
45.0k
                                (long) jas_image_cmptwidth(jp2_image,components[component]),
1000
45.0k
                                (long) jas_image_cmptheight(jp2_image,components[component]),
1001
45.0k
                                (long) jas_image_cmpttlx(jp2_image, components[component]),
1002
45.0k
                                (long) jas_image_cmpttly(jp2_image, components[component]),
1003
45.0k
                                (long) jas_image_cmptbrx(jp2_image, components[component]),
1004
45.0k
                                (long) jas_image_cmptbry(jp2_image, components[component]),
1005
45.0k
                                (long) jas_image_cmpthstep(jp2_image, components[component]),
1006
45.0k
                                (long) jas_image_cmptvstep(jp2_image, components[component]),
1007
45.0k
                                (unsigned int) jas_image_cmptprec(jp2_image,components[component]),
1008
45.0k
                                (int) jas_image_cmptsgnd(jp2_image, components[component]));
1009
45.0k
        }
1010
44.3k
    }
1011
88.4k
  for (component=0; component < number_components; component++)
1012
44.9k
    {
1013
44.9k
      if (((unsigned long) jas_image_cmptwidth(jp2_image,components[component]) != image->columns) ||
1014
44.4k
          ((unsigned long) jas_image_cmptheight(jp2_image,components[component]) != image->rows) ||
1015
44.1k
          (jas_image_cmpttlx(jp2_image, components[component]) != 0) ||
1016
44.1k
          (jas_image_cmpttly(jp2_image, components[component]) != 0) ||
1017
44.1k
          (jas_image_cmpthstep(jp2_image, components[component]) != 1) ||
1018
44.1k
          (jas_image_cmptvstep(jp2_image, components[component]) != 1))
1019
44.1k
        ThrowJP2ReaderException(CoderError,IrregularChannelGeometryNotSupported,image);
1020
44.1k
    }
1021
  /* FIXME: It would be good to support signed data! */
1022
80.4k
  for (component=0; component < number_components; component++)
1023
44.0k
    {
1024
44.0k
      if ((jas_image_cmptsgnd(jp2_image, components[component]) != false))
1025
36.9k
        ThrowJP2ReaderException(CoderError,DataStorageTypeIsNotSupported,image);
1026
36.9k
    }
1027
1028
36.3k
  image->matte=number_components > 3;
1029
73.2k
  for (component=0; component < number_components; component++)
1030
36.8k
    {
1031
36.8k
      unsigned int
1032
36.8k
        component_depth;
1033
1034
36.8k
      component_depth=jas_image_cmptprec(jp2_image,components[component]);
1035
36.8k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1036
36.8k
                            "Component[%d] depth is %u",component,component_depth);
1037
36.8k
      if (0 == component)
1038
36.3k
        image->depth=component_depth;
1039
502
      else
1040
502
        image->depth=Max(image->depth,component_depth);
1041
36.8k
    }
1042
36.3k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1043
36.3k
                        "Image depth is %u",image->depth);
1044
36.3k
  if (image_info->ping)
1045
0
    {
1046
0
      (void) jas_stream_close(jp2_stream);
1047
0
      jas_image_destroy(jp2_image);
1048
0
#if HAVE_JAS_INIT_LIBRARY
1049
      /* Perform any per-thread clean-up for the JasPer library. */
1050
0
      JAS_CLEANUP_THREAD();
1051
0
#endif /* if HAVE_JAS_INIT_LIBRARY */
1052
0
      return(image);
1053
0
    }
1054
1055
36.3k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
1056
32.4k
    ThrowJP2ReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1057
1058
  /*
1059
    Allocate Jasper pixels.
1060
  */
1061
32.4k
  pixels=jas_matrix_create(1,(unsigned int) image->columns);
1062
32.4k
  if (pixels == (jas_matrix_t *) NULL)
1063
32.4k
    ThrowJP2ReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1064
1065
  /*
1066
    Allocate and populate channel LUTs
1067
  */
1068
64.5k
  for (component=0; component < (long) number_components; component++)
1069
32.8k
    {
1070
32.8k
      double
1071
32.8k
        scale_to_quantum;
1072
1073
32.8k
      unsigned int
1074
32.8k
        component_depth,
1075
32.8k
        i,
1076
32.8k
        max_value;
1077
1078
32.8k
      component_depth=jas_image_cmptprec(jp2_image,components[component]);
1079
32.8k
      if ((0 == component_depth) || (component_depth > 16))
1080
674
        {
1081
674
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1082
674
                                "Component %u depth is %u!",
1083
674
                                component, component_depth);
1084
674
          ThrowJP2ReaderException(CorruptImageError,ImproperImageHeader,image);
1085
0
        }
1086
32.1k
      max_value=(unsigned int) MaxValueGivenBits(component_depth);
1087
32.1k
      if ((0 == max_value) || (max_value > 65535))
1088
32.1k
        ThrowJP2ReaderException(CorruptImageError,ImproperImageHeader,image);
1089
32.1k
      scale_to_quantum=MaxRGBDouble/max_value;
1090
32.1k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1091
32.1k
                            "Channel %d scale is %g", component, scale_to_quantum);
1092
32.1k
      channel_lut[component]=MagickAllocateResourceLimitedArray(Quantum *, (size_t) max_value+1,sizeof(Quantum));
1093
32.1k
      if (channel_lut[component] == (Quantum *) NULL)
1094
32.1k
        ThrowJP2ReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1095
23.6M
      for (i=0; i <= max_value; i++)
1096
23.6M
        (channel_lut[component])[i]=scale_to_quantum*i+0.5;
1097
32.1k
    }
1098
1099
  /*
1100
    Convert JPEG 2000 pixels.
1101
  */
1102
1.12M
  for (y=0; y < (long) image->rows; y++)
1103
1.10M
    {
1104
1.10M
      q=GetImagePixels(image,0,y,image->columns,1);
1105
1.10M
      if (q == (PixelPacket *) NULL)
1106
13.3k
        break;
1107
1108
1.09M
      if (1 == number_components)
1109
1.01M
        {
1110
          /* Grayscale */
1111
1.01M
          (void) jas_image_readcmpt(jp2_image,(short) components[0],0,
1112
1.01M
                                    (unsigned int) y,
1113
1.01M
                                    (unsigned int) image->columns,1,pixels);
1114
933M
          for (x=0; x < (long) image->columns; x++)
1115
932M
            {
1116
932M
              q->red=q->green=q->blue=(channel_lut[0])[jas_matrix_getv(pixels,x)];
1117
932M
              q->opacity=OpaqueOpacity;
1118
932M
              q++;
1119
932M
            }
1120
1.01M
        }
1121
73.7k
      else
1122
73.7k
        {
1123
          /* Red */
1124
73.7k
          (void) jas_image_readcmpt(jp2_image,(short) components[0],0,
1125
73.7k
                                    (unsigned int) y,
1126
73.7k
                                    (unsigned int) image->columns,1,pixels);
1127
80.4M
          for (x=0; x < (long) image->columns; x++)
1128
80.3M
            q[x].red=(channel_lut[0])[jas_matrix_getv(pixels,x)];
1129
1130
          /* Green */
1131
73.7k
          (void) jas_image_readcmpt(jp2_image,(short) components[1],0,
1132
73.7k
                                    (unsigned int) y,
1133
73.7k
                                    (unsigned int) image->columns,1,pixels);
1134
80.4M
          for (x=0; x < (long) image->columns; x++)
1135
80.3M
            q[x].green=(channel_lut[1])[jas_matrix_getv(pixels,x)];
1136
1137
          /* Blue */
1138
73.7k
          (void) jas_image_readcmpt(jp2_image,(short) components[2],0,
1139
73.7k
                                    (unsigned int) y,
1140
73.7k
                                    (unsigned int) image->columns,1,pixels);
1141
80.4M
          for (x=0; x < (long) image->columns; x++)
1142
80.3M
            q[x].blue=(channel_lut[2])[jas_matrix_getv(pixels,x)];
1143
1144
          /* Opacity */
1145
73.7k
          if (number_components > 3)
1146
0
            {
1147
0
              (void) jas_image_readcmpt(jp2_image,(short) components[3],0,
1148
0
                                        (unsigned int) y,
1149
0
                                        (unsigned int) image->columns,1,pixels);
1150
0
              for (x=0; x < (long) image->columns; x++)
1151
0
                q[x].opacity=MaxRGB-(channel_lut[3])[jas_matrix_getv(pixels,x)];
1152
0
            }
1153
73.7k
          else
1154
73.7k
            {
1155
80.4M
              for (x=0; x < (long) image->columns; x++)
1156
80.3M
                q[x].opacity=OpaqueOpacity;
1157
73.7k
            }
1158
73.7k
        }
1159
1.09M
      if (!SyncImagePixels(image))
1160
0
        break;
1161
1.09M
      if (image->previous == (Image *) NULL)
1162
1.09M
        if (QuantumTick(y,image->rows))
1163
153k
          if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
1164
153k
                                      image->filename,
1165
153k
                                      image->columns,image->rows))
1166
0
            break;
1167
1.09M
    }
1168
31.7k
  if (number_components == 1)
1169
31.5k
    image->is_grayscale=MagickTrue;
1170
31.7k
  {
1171
    /*
1172
      Obtain ICC ICM color profile
1173
    */
1174
1175
31.7k
    jas_cmprof_t
1176
31.7k
      *cm_profile;
1177
1178
    /* Obtain a pointer to the existing jas_cmprof_t profile handle. */
1179
31.7k
    cm_profile=jas_image_cmprof(jp2_image);
1180
31.7k
    if (cm_profile != (jas_cmprof_t *) NULL)
1181
31.7k
      {
1182
31.7k
        jas_iccprof_t
1183
31.7k
          *icc_profile;
1184
1185
        /* Obtain a copy of the jas_iccprof_t ICC profile handle */
1186
31.7k
        icc_profile=jas_iccprof_createfromcmprof(cm_profile);
1187
        /* or maybe just icc_profile=cm_profile->iccprof */
1188
31.7k
        if (icc_profile != (jas_iccprof_t *) NULL)
1189
31.7k
          {
1190
31.7k
            jas_stream_t
1191
31.7k
              *icc_stream;
1192
1193
31.7k
            icc_stream=jas_stream_memopen(NULL,0);
1194
31.7k
            if ((icc_stream != (jas_stream_t *) NULL) &&
1195
31.7k
                (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
1196
31.7k
                (jas_stream_flush(icc_stream) == 0))
1197
31.7k
              {
1198
31.7k
                jas_stream_memobj_t
1199
31.7k
                  *blob;
1200
1201
31.7k
                blob=(jas_stream_memobj_t *) icc_stream->obj_;
1202
31.7k
                if (image->logging)
1203
31.7k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1204
31.7k
                                        "ICC profile: %lu bytes",(unsigned long) blob->len_);
1205
31.7k
                SetImageProfile(image,"ICM",blob->buf_,blob->len_);
1206
1207
31.7k
                (void) jas_stream_close(icc_stream);
1208
31.7k
                jas_iccprof_destroy(icc_profile);
1209
31.7k
              }
1210
31.7k
          }
1211
31.7k
      }
1212
31.7k
  }
1213
1214
63.9k
  for (component=0; component < (long) number_components; component++)
1215
32.1k
    MagickFreeResourceLimitedMemory(Quantum *,channel_lut[component]);
1216
31.7k
  jas_matrix_destroy(pixels);
1217
31.7k
  (void) jas_stream_close(jp2_stream);
1218
31.7k
  MagickFreeMemory(options);
1219
31.7k
  jas_image_destroy(jp2_image);
1220
31.7k
  StopTimer(&image->timer);
1221
31.7k
#if HAVE_JAS_INIT_LIBRARY
1222
  /* Perform any per-thread clean-up for the JasPer library. */
1223
31.7k
  JAS_CLEANUP_THREAD();
1224
31.7k
#endif /* if HAVE_JAS_INIT_LIBRARY */
1225
31.7k
  return(image);
1226
32.4k
}
1227
#endif /* if defined(HasJP2) */
1228

1229
/*
1230
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1231
%                                                                             %
1232
%                                                                             %
1233
%                                                                             %
1234
%   R e g i s t e r J P 2 I m a g e                                           %
1235
%                                                                             %
1236
%                                                                             %
1237
%                                                                             %
1238
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1239
%
1240
%  Method RegisterJP2Image adds attributes for the JP2 image format to
1241
%  the list of supported formats.  The attributes include the image format
1242
%  tag, a method to read and/or write the format, whether the format
1243
%  supports the saving of more than one frame to the same file or blob,
1244
%  whether the format supports native in-memory I/O, and a brief
1245
%  description of the format.
1246
%
1247
%  The format of the RegisterJP2Image method is:
1248
%
1249
%      RegisterJP2Image(void)
1250
%
1251
*/
1252
ModuleExport void RegisterJP2Image(void)
1253
9
{
1254
9
#if defined(HasJP2)
1255
9
  static char
1256
9
    version[16];
1257
1258
9
  MagickInfo
1259
9
    *entry;
1260
1261
9
  (void) strlcpy(version,"JasPer ",sizeof(version));
1262
9
  (void) strlcat(version,jas_getversion(),sizeof(version));
1263
1264
9
#if !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC)
1265
9
  entry=SetMagickInfo("J2C");
1266
9
  entry->description="JPEG-2000 Code Stream Syntax";
1267
9
  entry->version=version;
1268
9
  entry->module="JP2";
1269
9
  entry->magick=(MagickHandler) IsJPC;
1270
9
  entry->adjoin=False;
1271
9
  entry->seekable_stream=True;
1272
9
  entry->thread_support=False;
1273
9
  entry->decoder=(DecoderHandler) ReadJP2Image;
1274
9
  entry->encoder=(EncoderHandler) WriteJP2Image;
1275
9
  entry->coder_class=StableCoderClass;
1276
9
  (void) RegisterMagickInfo(entry);
1277
9
#endif /* !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC) */
1278
1279
9
#if !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC)
1280
9
  entry=SetMagickInfo("JP2");
1281
9
  entry->description="JPEG-2000 JP2 File Format Syntax";
1282
9
  entry->version=version;
1283
9
  entry->module="JP2";
1284
9
  entry->magick=(MagickHandler) IsJP2;
1285
9
  entry->adjoin=False;
1286
9
  entry->seekable_stream=True;
1287
9
  entry->thread_support=False;
1288
9
  entry->decoder=(DecoderHandler) ReadJP2Image;
1289
9
  entry->encoder=(EncoderHandler) WriteJP2Image;
1290
9
  entry->coder_class=StableCoderClass;
1291
9
  (void) RegisterMagickInfo(entry);
1292
9
#endif /* !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC) */
1293
1294
9
#if !defined(EXCLUDE_JPC_SUPPORT) || defined(JAS_ENABLE_JPC_CODEC)
1295
9
  entry=SetMagickInfo("JPC");
1296
9
  entry->description="JPEG-2000 Code Stream Syntax";
1297
9
  entry->version=version;
1298
9
  entry->module="JP2";
1299
9
  entry->magick=(MagickHandler) IsJPC;
1300
9
  entry->adjoin=False;
1301
9
  entry->seekable_stream=True;
1302
9
  entry->thread_support=False;
1303
9
  entry->decoder=(DecoderHandler) ReadJP2Image;
1304
9
  entry->encoder=(EncoderHandler) WriteJP2Image;
1305
9
  entry->coder_class=StableCoderClass;
1306
9
  (void) RegisterMagickInfo(entry);
1307
9
#endif /* !defined(EXCLUDE_JPC_SUPPORT) || defined(JAS_ENABLE_JPC_CODEC) */
1308
1309
9
#if !defined(EXCLUDE_PGX_SUPPORT) || defined(JAS_ENABLE_PGX_CODEC)
1310
9
  entry=SetMagickInfo("PGX");
1311
9
  entry->description="JPEG-2000 VM Format";
1312
9
  entry->version=version;
1313
9
  entry->module="JP2";
1314
9
  entry->magick=(MagickHandler) IsPGX;
1315
9
  entry->adjoin=False;
1316
9
  entry->seekable_stream=True;
1317
9
  entry->thread_support=False;
1318
9
  entry->decoder=(DecoderHandler) ReadJP2Image;
1319
9
  entry->encoder=(EncoderHandler) WriteJP2Image;
1320
9
  entry->coder_class=UnstableCoderClass;
1321
9
  (void) RegisterMagickInfo(entry);
1322
9
#endif /* !defined(EXCLUDE_PGX_SUPPORT) || defined(JAS_ENABLE_PGX_CODEC) */
1323
1324
9
#endif /* if defined(HasJP2) */
1325
9
}
1326

1327
/*
1328
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1329
%                                                                             %
1330
%                                                                             %
1331
%                                                                             %
1332
%   U n r e g i s t e r J P 2 I m a g e                                       %
1333
%                                                                             %
1334
%                                                                             %
1335
%                                                                             %
1336
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1337
%
1338
%  Method UnregisterJP2Image removes format registrations made by the
1339
%  JP2 module from the list of supported formats.
1340
%
1341
%  The format of the UnregisterJP2Image method is:
1342
%
1343
%      UnregisterJP2Image(void)
1344
%
1345
*/
1346
ModuleExport void UnregisterJP2Image(void)
1347
0
{
1348
0
#if defined(HasJP2)
1349
0
  (void) UnregisterMagickInfo("PGX");
1350
0
  (void) UnregisterMagickInfo("JPC");
1351
0
  (void) UnregisterMagickInfo("JP2");
1352
0
  (void) UnregisterMagickInfo("J2C");
1353
1354
  /*
1355
    Cleanup Jasper
1356
  */
1357
0
  cleanup_jasper();
1358
0
#endif /* if defined(HasJP2) */
1359
0
}
1360

1361
#if defined(HasJP2)
1362
/*
1363
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364
%                                                                             %
1365
%                                                                             %
1366
%                                                                             %
1367
%   W r i t e J P 2 I m a g e                                                 %
1368
%                                                                             %
1369
%                                                                             %
1370
%                                                                             %
1371
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372
%
1373
%  Method WriteJP2Image writes an image in the JPEG 2000 image format.
1374
%
1375
%  JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
1376
%
1377
%  The format of the WriteJP2Image method is:
1378
%
1379
%      MagickPassFail WriteJP2Image(const ImageInfo *image_info,Image *image)
1380
%
1381
%  A description of each parameter follows.
1382
%
1383
%    o status: Method WriteJP2Image return MagickTrue if the image is written.
1384
%      MagickFalse is returned is there is a memory shortage or if the image file
1385
%      fails to write.
1386
%
1387
%    o image_info: Specifies a pointer to a ImageInfo structure.
1388
%
1389
%    o image:  A pointer to an Image structure.
1390
%
1391
%
1392
*/
1393
static MagickPassFail
1394
WriteJP2Image(const ImageInfo *image_info,Image *image)
1395
1.60k
{
1396
1.60k
  char
1397
1.60k
    magick[MaxTextExtent],
1398
1.60k
    option_keyval[MaxTextExtent],
1399
1.60k
    *options = NULL;
1400
1401
1.60k
  int
1402
1.60k
    format;
1403
1404
1.60k
  long
1405
1.60k
    y;
1406
1407
1.60k
  jas_image_cmptparm_t
1408
1.60k
    component_info;
1409
1410
1.60k
  jas_image_t
1411
1.60k
    *jp2_image;
1412
1413
1.60k
  jas_matrix_t
1414
1.60k
    *jp2_pixels;
1415
1416
1.60k
  jas_stream_ops_t
1417
1.60k
    StreamOperators =
1418
1.60k
    {
1419
1.60k
      BlobRead,
1420
1.60k
      BlobWrite,
1421
1.60k
      BlobSeek,
1422
1.60k
      BlobClose
1423
1.60k
    };
1424
1425
1.60k
  jas_stream_t
1426
1.60k
    *jp2_stream;
1427
1428
1.60k
  register const PixelPacket
1429
1.60k
    *p;
1430
1431
1.60k
  register int
1432
1.60k
    x;
1433
1434
1.60k
  MagickBool
1435
1.60k
    rate_specified=MagickFalse;
1436
1437
1.60k
  MagickPassFail
1438
1.60k
    status;
1439
1440
1.60k
  int
1441
1.60k
    component,
1442
1.60k
    number_components;
1443
1444
1.60k
  unsigned short
1445
1.60k
    *lut;
1446
1447
1.60k
  ImageCharacteristics
1448
1.60k
    characteristics;
1449
1450
  /*
1451
    Initialize Jasper
1452
  */
1453
1.60k
  if (initialize_jasper(&image->exception) != MagickPass)
1454
0
    {
1455
0
      return MagickFail;
1456
0
    }
1457
1458
1.60k
#if HAVE_JAS_INIT_LIBRARY
1459
  /*
1460
    Perform any per-thread initialization for the JasPer library.
1461
  */
1462
1.60k
  if (jas_init_thread())
1463
0
    {
1464
      /* Handle the initialization error. */
1465
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1466
0
                            "jas_init_thread() failed!");
1467
0
      return MagickFail;
1468
0
    }
1469
1.60k
#endif /* if HAVE_JAS_INIT_LIBRARY */
1470
1471
  /*
1472
    Open image file.
1473
  */
1474
1.60k
  assert(image_info != (const ImageInfo *) NULL);
1475
1.60k
  assert(image_info->signature == MagickSignature);
1476
1.60k
  assert(image != (Image *) NULL);
1477
1.60k
  assert(image->signature == MagickSignature);
1478
1.60k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1479
1.60k
  if (status == MagickFail)
1480
1.60k
    ThrowJP2WriterException(FileOpenError,UnableToOpenFile,image);
1481
1482
  /*
1483
    Ensure that image is in RGB space.
1484
  */
1485
1.60k
  if (TransformColorspace(image,RGBColorspace) == MagickFail)
1486
1.60k
      ThrowWriterException(CoderError,UnableToTransformColorspace,image);
1487
1488
  /*
1489
    PGX format requires a grayscale representation
1490
  */
1491
1.60k
  if (strcmp("PGX",image_info->magick) == 0)
1492
264
    {
1493
264
      if (SetImageType(image,GrayscaleType) == MagickFail)
1494
264
        ThrowWriterException(CoderError,UnableToSetImageType,image);
1495
264
    }
1496
1497
  /*
1498
    Analyze image to be written.
1499
  */
1500
1.60k
  if (!GetImageCharacteristics(image,&characteristics,
1501
1.60k
                               (OptimizeType == image_info->type),
1502
1.60k
                               &image->exception))
1503
0
    {
1504
0
      CloseBlob(image);
1505
0
      return MagickFail;
1506
0
    }
1507
1508
  /*
1509
    Support passing Jasper options.
1510
  */
1511
1.60k
  {
1512
1.60k
    unsigned int
1513
1.60k
      i;
1514
1515
43.2k
    for (i=0; i < ArraySize(jasper_enc_options); i++)
1516
41.6k
      {
1517
41.6k
        const char
1518
41.6k
          *option = jasper_enc_options[i];
1519
1520
41.6k
        const char
1521
41.6k
          *value;
1522
1523
41.6k
        if ((value=AccessDefinition(image_info,"jp2",option)) != NULL)
1524
0
          {
1525
0
            if (LocaleCompare(option,"rate") == 0)
1526
0
              {
1527
                /*
1528
                  It is documented that a rate specification of 1.0 should
1529
                  result in lossless compression.  However, Jasper only
1530
                  provides lossless compression if rate was not specified
1531
                  at all.  Support lossless compression as documented.
1532
                */
1533
0
                const double rate=atof(value);
1534
1535
0
                rate_specified=MagickTrue;
1536
0
                if (rate < 1.0-MagickEpsilon)
1537
0
                  {
1538
0
                    MagickFormatString(option_keyval,sizeof(option_keyval),"%s=%.1024s ",option,value);
1539
0
                    ConcatenateString(&options,option_keyval);
1540
0
                  }
1541
0
              }
1542
0
            else
1543
0
              {
1544
0
                MagickFormatString(option_keyval,sizeof(option_keyval),"%s=%.1024s ",option,value);
1545
0
                ConcatenateString(&options,option_keyval);
1546
1547
                /* Setting debug mode seems to require extra assistance */
1548
0
                if (LocaleCompare(option,"debug") == 0)
1549
0
                  jas_setdbglevel(atoi(value));
1550
0
              }
1551
0
          }
1552
41.6k
      }
1553
1.60k
  }
1554
1555
  /*
1556
    Obtain a JP2 stream.
1557
  */
1558
1.60k
  jp2_stream=JP2StreamManager(&StreamOperators, image);
1559
1.60k
  if (jp2_stream == (jas_stream_t *) NULL)
1560
1.60k
    ThrowJP2WriterException(DelegateError,UnableToManageJP2Stream,image);
1561
1.60k
  number_components=image->matte ? 4 : 3;
1562
1.60k
  if ((image_info->type != TrueColorType) &&
1563
1.60k
      (characteristics.grayscale))
1564
1.39k
    number_components=1;
1565
1566
1.60k
  jp2_image=jas_image_create0();
1567
1.60k
  if (jp2_image == (jas_image_t *) NULL)
1568
1.60k
    ThrowJP2WriterException(DelegateError,UnableToCreateImage,image);
1569
1570
3.62k
  for (component=0; component < number_components; component++)
1571
2.01k
  {
1572
2.01k
    (void) memset((void *)&component_info,0,sizeof(jas_image_cmptparm_t));
1573
2.01k
    component_info.tlx=0; /* top left x ordinate */
1574
2.01k
    component_info.tly=0; /* top left y ordinate */
1575
2.01k
    component_info.hstep=1; /* horizontal pixels per step */
1576
2.01k
    component_info.vstep=1; /* vertical pixels per step */
1577
2.01k
    component_info.width=(unsigned int) image->columns;
1578
2.01k
    component_info.height=(unsigned int) image->rows;
1579
2.01k
    component_info.prec=(unsigned int) Max(2,Min(image->depth,16)); /* bits in range */
1580
2.01k
    component_info.sgnd = false;  /* range is signed value? */
1581
1582
2.01k
    if (jas_image_addcmpt(jp2_image, component,&component_info)) {
1583
0
      jas_image_destroy(jp2_image);
1584
0
      ThrowJP2WriterException(DelegateError,UnableToCreateImageComponent,image);
1585
0
    }
1586
2.01k
  }
1587
1588
  /*
1589
    Allocate and compute LUT.
1590
  */
1591
1.60k
  {
1592
1.60k
    unsigned long
1593
1.60k
      i,
1594
1.60k
      max_value;
1595
1596
1.60k
    double
1597
1.60k
      scale_to_component;
1598
1599
1.60k
    lut=MagickAllocateResourceLimitedArray(unsigned short *,MaxMap+1,sizeof(*lut));
1600
1.60k
    if (lut == (unsigned short *) NULL)
1601
0
      {
1602
0
        jas_image_destroy(jp2_image);
1603
0
        ThrowJP2WriterException(ResourceLimitError,MemoryAllocationFailed,image);
1604
0
      }
1605
1606
1.60k
    max_value=MaxValueGivenBits(component_info.prec);
1607
1.60k
    scale_to_component=max_value/MaxRGBDouble;
1608
104M
    for(i=0; i <= MaxMap; i++)
1609
104M
        lut[i]=scale_to_component*i+0.5;
1610
1.60k
  }
1611
1612
1.60k
  if (number_components == 1)
1613
1.39k
    {
1614
      /* FIXME: If image has an attached ICC profile, then the profile
1615
         should be transferred and the image colorspace set to
1616
         JAS_CLRSPC_GENGRAY */
1617
      /* sRGB Grayscale */
1618
1.39k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1619
1.39k
        "Setting SGRAY colorspace");
1620
1.39k
      jas_image_setclrspc(jp2_image, JAS_CLRSPC_SGRAY);
1621
1.39k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1622
1.39k
        "Setting GRAY channel to channel 0");
1623
1.39k
      jas_image_setcmpttype(jp2_image,0,
1624
1.39k
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
1625
1.39k
    }
1626
208
  else
1627
208
    {
1628
      /* FIXME: If image has an attached ICC profile, then the profile
1629
         should be transferred and the image colorspace set to
1630
         JAS_CLRSPC_GENRGB */
1631
1632
      /* sRGB */
1633
208
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1634
208
        "Setting SRGB colorspace");
1635
208
      jas_image_setclrspc(jp2_image, JAS_CLRSPC_SRGB);
1636
208
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1637
208
        "Setting RED channel to channel 0");
1638
208
      jas_image_setcmpttype(jp2_image,0,
1639
208
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
1640
208
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1641
208
        "Setting GREEN channel to channel 1");
1642
208
      jas_image_setcmpttype(jp2_image,1,
1643
208
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
1644
208
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1645
208
        "Setting BLUE channel to channel 2");
1646
208
      jas_image_setcmpttype(jp2_image,2,
1647
208
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
1648
208
      if (number_components == 4 )
1649
0
        {
1650
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1651
0
            "Setting OPACITY channel to channel 3");
1652
0
          jas_image_setcmpttype(jp2_image,3,
1653
0
            JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
1654
0
        }
1655
208
    }
1656
  /*
1657
    Convert to JPEG 2000 pixels.
1658
  */
1659
1.60k
  jp2_pixels=jas_matrix_create(1,(unsigned int) image->columns);
1660
1.60k
  if (jp2_pixels == (jas_matrix_t *) NULL)
1661
0
    {
1662
0
      MagickFreeResourceLimitedMemory(unsigned short *,lut);
1663
0
      jas_image_destroy(jp2_image);
1664
0
      ThrowJP2WriterException(ResourceLimitError,MemoryAllocationFailed,image);
1665
0
    }
1666
1667
1.07M
  for (y=0; y < (long) image->rows; y++)
1668
1.07M
  {
1669
1.07M
    p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1670
1.07M
    if (p == (const PixelPacket *) NULL)
1671
0
      break;
1672
1.07M
    if (number_components == 1)
1673
1.00M
      {
1674
933M
        for (x=0; x < (long) image->columns; x++)
1675
932M
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(PixelIntensityToQuantum(&p[x]))]);
1676
1.00M
        (void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y,
1677
1.00M
                                   (unsigned int) image->columns,1,jp2_pixels);
1678
1.00M
      }
1679
73.7k
    else
1680
73.7k
      {
1681
80.4M
        for (x=0; x < (long) image->columns; x++)
1682
80.3M
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].red)]);
1683
73.7k
        (void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y,
1684
73.7k
                                   (unsigned int) image->columns,1,jp2_pixels);
1685
1686
80.4M
        for (x=0; x < (long) image->columns; x++)
1687
80.3M
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].green)]);
1688
73.7k
        (void) jas_image_writecmpt(jp2_image,1,0,(unsigned int) y,
1689
73.7k
                                   (unsigned int) image->columns,1,jp2_pixels);
1690
1691
80.4M
        for (x=0; x < (long) image->columns; x++)
1692
80.3M
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].blue)]);
1693
73.7k
        (void) jas_image_writecmpt(jp2_image,2,0,(unsigned int) y,
1694
73.7k
                                   (unsigned int) image->columns,1,jp2_pixels);
1695
1696
73.7k
        if (number_components > 3)
1697
0
          for (x=0; x < (long) image->columns; x++)
1698
0
            jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(MaxRGB-p[x].opacity)]);
1699
73.7k
        (void) jas_image_writecmpt(jp2_image,3,0,(unsigned int) y,
1700
73.7k
                                   (unsigned int) image->columns,1,jp2_pixels);
1701
73.7k
      }
1702
1.07M
    if (image->previous == (Image *) NULL)
1703
1.07M
      if (QuantumTick(y,image->rows))
1704
136k
        if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1705
136k
                                    SaveImageText,image->filename,
1706
136k
                                    image->columns,image->rows))
1707
0
          break;
1708
1.07M
  }
1709
1.60k
  (void) strlcpy(magick,image_info->magick,MaxTextExtent);
1710
  /*
1711
    J2C is an alias for JPC but Jasper only supports "JPC".
1712
  */
1713
1.60k
  if (LocaleCompare(magick,"j2c") == 0)
1714
690
    (void) strlcpy(magick,"jpc",sizeof(magick));
1715
1.60k
  LocaleLower(magick);
1716
1.60k
  format=jas_image_strtofmt(magick);
1717
1718
  /*
1719
    Provide an emulation of IJG JPEG "quality" by default if rate was
1720
    not specified.
1721
  */
1722
1.60k
  if (rate_specified == MagickFalse)
1723
1.60k
    {
1724
1.60k
      double
1725
1.60k
        rate=INFINITY;
1726
1727
      /*
1728
        A rough approximation to JPEG v1 quality using JPEG-2000.
1729
        Default "quality" 75 results in a request for 16:1 compression, which
1730
        results in image sizes approximating that of JPEG v1.
1731
      */
1732
1.60k
      if ((image_info->quality < 100.0-MagickEpsilon) &&
1733
1.60k
          (MagickArraySize(image->rows,image->columns) > 2500U))
1734
1.24k
        {
1735
1.24k
          double
1736
1.24k
            header_size,
1737
1.24k
            current_size,
1738
1.24k
            target_size,
1739
1.24k
            d;
1740
1741
1.24k
          d=115-image_info->quality;  /* Best number is 110-115 */
1742
1.24k
          rate=100.0/(d*d);
1743
1.24k
          header_size=550.0; /* Base file size. */
1744
1.24k
          header_size+=((size_t) number_components-1)*142; /* Additional components */
1745
          /* FIXME: Need to account for any ICC profiles here */
1746
1747
1.24k
          current_size=(double)((image->rows*image->columns*image->depth)/8)*
1748
1.24k
            number_components;
1749
1.24k
          target_size=(current_size*rate)+header_size;
1750
1.24k
          rate=target_size/current_size;
1751
1.24k
          MagickFormatString(option_keyval,sizeof(option_keyval),"%s=%g ","rate",rate);
1752
1.24k
          ConcatenateString(&options,option_keyval);
1753
1.24k
        }
1754
1.60k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1755
1.60k
        "Compression rate: %g (%3.2f:1)",rate,1.0/rate);
1756
1.60k
    }
1757
1758
1759
1.60k
  if (options)
1760
1.24k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1761
1.24k
       "Jasper options: \"%s\"", options);
1762
1763
1.60k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Encoding image");
1764
1.60k
  status=jas_image_encode(jp2_image,jp2_stream,format,options);
1765
1.60k
  (void) jas_stream_close(jp2_stream);
1766
1.60k
  MagickFreeMemory(options);
1767
1.60k
  MagickFreeResourceLimitedMemory(unsigned short *,lut);
1768
1.60k
  jas_matrix_destroy(jp2_pixels);
1769
1.60k
  jas_image_destroy(jp2_image);
1770
1.60k
  if (status)
1771
1.60k
    ThrowJP2WriterException(DelegateError,UnableToEncodeImageFile,image);
1772
1773
1.60k
#if HAVE_JAS_INIT_LIBRARY
1774
  /* Perform any per-thread clean-up for the JasPer library. */
1775
1.60k
  JAS_CLEANUP_THREAD();
1776
1.60k
#endif /* if HAVE_JAS_INIT_LIBRARY */
1777
1.60k
  return(True);
1778
1.60k
}
1779
#endif /* if defined(HasJP2) */