Coverage Report

Created: 2026-09-14 07:37

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
10
#  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
430k
{
193
430k
  if (length < 9)
194
0
    return(False);
195
430k
  if (memcmp(magick+4,"\152\120\040\040\015",5) == 0)
196
19.7k
    return(True);
197
410k
  return(False);
198
430k
}
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
430k
{
231
430k
  if (length < 2)
232
0
    return(False);
233
430k
  if (memcmp(magick,"\377\117",2) == 0)
234
196k
    return(True);
235
233k
  return(False);
236
430k
}
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
430k
{
271
430k
  if (length < 5)
272
0
    return(False);
273
430k
  if ((memcmp(magick,"PG ML",5) == 0) || (memcmp(magick,"PG LM",5) == 0))
274
216k
    return(True);
275
213k
  return(False);
276
430k
}
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
61.6M
{
353
61.6M
  size_t
354
61.6M
    count;
355
356
61.6M
  StreamManager
357
61.6M
    *source = (StreamManager *) obj;
358
359
61.6M
  count=ReadBlob(source->image,(size_t) cnt,(void *) buf);
360
61.6M
#if defined(HAVE_JAS_STREAM_IO_V3)
361
61.6M
  return (count);
362
#else
363
  if ((size_t)((int) count) != count)
364
    count = 0;
365
  return ((int) count);
366
#endif
367
61.6M
}
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.35M
{
377
4.35M
  size_t
378
4.35M
    count;
379
380
4.35M
  StreamManager
381
4.35M
    *source = (StreamManager *) obj;
382
383
4.35M
  count=WriteBlob(source->image,(size_t) cnt,(void *) buf);
384
4.35M
#if defined(HAVE_JAS_STREAM_IO_V3)
385
4.35M
  return(count);
386
#else
387
  if ((size_t)((int) count) != count)
388
    count = 0;
389
  return ((int) count);
390
#endif
391
4.35M
}
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
432k
{
407
432k
  int status;
408
432k
  StreamManager
409
432k
    *source = (StreamManager *) obj;
410
411
432k
  status = CloseBlob(source->image);
412
432k
  jas_free(source);
413
432k
  return (status == 0 ? EOF : 0);
414
432k
}
415
416
417
static jas_stream_t *JP2StreamManager(jas_stream_ops_t *stream_ops, Image *image)
418
432k
{
419
432k
  jas_stream_t
420
432k
    *stream;
421
422
432k
  StreamManager
423
432k
    *source;
424
425
432k
  stream=(jas_stream_t *) jas_malloc(sizeof(jas_stream_t));
426
432k
  if (stream == (jas_stream_t *) NULL)
427
0
    return((jas_stream_t *) NULL);
428
432k
  (void) memset(stream,0,sizeof(jas_stream_t));
429
432k
  stream->rwlimit_=(-1);
430
432k
  stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
431
432k
  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
432k
  stream->ops_=stream_ops;
439
432k
  stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
440
432k
  stream->bufbase_=stream->tinybuf_;
441
432k
  stream->bufsize_=1;
442
432k
  stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
443
432k
  stream->ptr_=stream->bufstart_;
444
432k
  stream->bufmode_|=JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK;
445
432k
  source=(StreamManager *) stream->obj_;
446
432k
  source->image=image;
447
432k
  return(stream);
448
432k
}
449
450
#if defined(HAVE_JAS_INIT_LIBRARY)
451
438k
#  define JAS_CLEANUP_THREAD() jas_cleanup_thread()
452
#else
453
#  define JAS_CLEANUP_THREAD()
454
#endif
455
456
#define ThrowJP2ReaderException(code_,reason_,image_)                   \
457
399k
  {                                                                     \
458
410k
    for (component=0; component < (long) number_components; component++) \
459
399k
      MagickFreeResourceLimitedMemory(Quantum *,channel_lut[component]); \
460
399k
    if (pixels)                                                         \
461
399k
      jas_matrix_destroy(pixels);                                       \
462
399k
    if (jp2_stream)                                                     \
463
399k
      (void) jas_stream_close(jp2_stream);                              \
464
399k
    if (jp2_image)                                                      \
465
399k
      jas_image_destroy(jp2_image);                                     \
466
399k
    MagickFreeMemory(options);                                          \
467
399k
    JAS_CLEANUP_THREAD();                                               \
468
399k
    ThrowReaderException(code_,reason_,image_);                         \
469
0
  }
470
471
#define ThrowJP2WriterException(code_,reason_,image_)   \
472
19
  {                                                     \
473
19
    JAS_CLEANUP_THREAD();                               \
474
19
    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
426M
{
483
426M
  char *p;
484
426M
  (void) allocator;
485
  /* JasPer expects its allocator to return non-null for zero size */
486
426M
  p=(char *) _MagickAllocateResourceLimitedMemoryLoc((size == 0 ? 1 : size),GetMagickModule());
487
  /* fprintf(stderr,"alloc_rlm(%p, %zu) -> %p\n", allocator, size, p); */
488
426M
  return p;
489
426M
}
490
static void free_rlm(struct jas_allocator_s *allocator, void *pointer)
491
426M
{
492
426M
  (void) allocator;
493
  /* fprintf(stderr,"free_rlm(%p, %p\n", allocator, pointer); */
494
426M
  _MagickFreeResourceLimitedMemoryLoc(pointer,GetMagickModule());
495
426M
}
496
static void *realloc_rlm(struct jas_allocator_s *allocator, void *pointer,
497
                         size_t new_size)
498
124k
{
499
124k
  char *p;
500
124k
  (void) allocator;
501
124k
  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
124k
  return p;
504
124k
}
505
#endif /* if HAVE_JAS_INIT_LIBRARY */
506
static MagickPassFail initialize_jasper(ExceptionInfo *exception)
507
438k
{
508
438k
  (void) exception;
509
438k
  if (!jasper_initialized)
510
10
    {
511
10
#if HAVE_JAS_INIT_LIBRARY
512
10
      {
513
        /* static jas_std_allocator_t allocator; */
514
10
        static jas_allocator_t allocator;
515
516
10
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
517
10
                              "Initializing JasPer...");
518
        /*
519
          Configure the library using the default configuration settings.
520
        */
521
10
        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
10
        allocator.cleanup = 0;
537
538
        /*
539
          Function to allocate memory.
540
          This function should have behavior similar to malloc.
541
        */
542
10
        allocator.alloc = alloc_rlm;
543
544
        /*
545
          Function to deallocate memory.
546
          This function should have behavior similar to free.
547
        */
548
10
        allocator.free = free_rlm;
549
550
        /*
551
          Function to reallocate memory.
552
          This function should have behavior similar to realloc.
553
        */
554
10
        allocator.realloc = realloc_rlm;
555
        /* jas_std_allocator_init(&allocator); */ /* Uses JasPer allocators */
556
10
        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
10
        {
563
10
          size_t max_mem_gm = (size_t) GetMagickResourceLimit(MemoryResource);
564
10
          size_t max_mem_jas = jas_get_total_mem_size();
565
10
          if (max_mem_jas == 0)
566
0
            max_mem_jas=max_mem_gm;
567
10
          jas_conf_set_max_mem_usage(Min(max_mem_jas,max_mem_gm));
568
10
        }
569
570
        /*
571
          Inform JasPer that app may be multi-threaded
572
        */
573
10
        jas_conf_set_multithread(JP2_HAVE_THREADS);
574
575
        /* Perform global initialization for the JasPer library. */
576
10
        if (jas_init_library() == 0)
577
10
          {
578
10
            jasper_initialized=MagickTrue;
579
            /* jas_set_debug_level(110); */
580
10
          }
581
0
        else
582
0
          {
583
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
584
0
                                  "jas_init_library() failed!");
585
0
          }
586
10
      }
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
10
      if (!jasper_initialized)
606
0
        {
607
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
608
0
                                "Failed to initialize JasPer!");
609
0
        }
610
10
    }
611
612
438k
  return jasper_initialized ? MagickPass : MagickFail;
613
438k
}
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
436k
{
638
436k
  Image
639
436k
    *image;
640
641
436k
  long
642
436k
    y;
643
644
436k
  jas_image_t
645
436k
    *jp2_image = (jas_image_t *) NULL;
646
647
436k
  jas_matrix_t
648
436k
    *pixels = (jas_matrix_t *) NULL;
649
650
436k
  jas_stream_ops_t
651
436k
    StreamOperators =
652
436k
    {
653
436k
      BlobRead,
654
436k
      BlobWrite,
655
436k
      BlobSeek,
656
436k
      BlobClose
657
436k
    };
658
659
436k
  jas_stream_t
660
436k
    *jp2_stream = (jas_stream_t *) NULL;
661
662
436k
  register long
663
436k
    x;
664
665
436k
  register PixelPacket
666
436k
    *q;
667
668
436k
  magick_off_t
669
436k
    pos;
670
671
436k
  int
672
436k
    component,
673
436k
    components[4],
674
436k
    number_components=0;
675
676
436k
  Quantum
677
436k
    *channel_lut[4];
678
679
436k
  char
680
436k
    option_keyval[MaxTextExtent],
681
436k
    *options = NULL;
682
683
436k
  unsigned int
684
436k
    status;
685
686
436k
  MagickBool
687
436k
    jp2_hdr,
688
436k
    jpc_hdr,
689
436k
    pgx_hdr;
690
691
  /*
692
    Initialize Jasper
693
  */
694
436k
  if (initialize_jasper(exception) != MagickPass)
695
0
    {
696
0
      return (Image *) NULL;
697
0
    }
698
699
436k
#if HAVE_JAS_INIT_LIBRARY
700
  /*
701
    Perform any per-thread initialization for the JasPer library.
702
  */
703
436k
  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
436k
#endif /* if HAVE_JAS_INIT_LIBRARY */
711
712
  /*
713
    Open image file.
714
  */
715
436k
  assert(image_info != (const ImageInfo *) NULL);
716
436k
  assert(image_info->signature == MagickSignature);
717
436k
  assert(exception != (ExceptionInfo *) NULL);
718
436k
  assert(exception->signature == MagickSignature);
719
436k
  (void) memset(channel_lut,0,sizeof(channel_lut));
720
436k
  image=AllocateImage(image_info);
721
436k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
722
436k
  if (status == False)
723
436k
    ThrowJP2ReaderException(FileOpenError,UnableToOpenFile,image);
724
725
436k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
726
436k
                        "Requested format is \"%s\"",
727
436k
                        image_info->magick);
728
729
  /*
730
    Get the header and auto-detect apparent format.
731
  */
732
436k
  {
733
436k
    size_t
734
436k
      magick_length;
735
736
436k
    unsigned char
737
436k
      magick[16];
738
739
436k
    const MagickInfo
740
436k
      *magick_info;
741
742
    /* Get current seek position (normally 0) */
743
436k
    pos=TellBlob(image);
744
436k
    if (pos < 0)
745
0
      {
746
0
        ThrowJP2ReaderException(BlobError,UnableToObtainOffset,image);
747
0
      }
748
749
    /* Read header */
750
436k
    if ((magick_length=ReadBlob(image,sizeof(magick),magick)) != sizeof(magick))
751
5.72k
      {
752
5.72k
        ThrowJP2ReaderException(CorruptImageError,UnexpectedEndOfFile,image);
753
0
      }
754
755
    /* Restore seek position */
756
430k
    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
430k
    jp2_hdr=IsJP2(magick,sizeof(magick));
763
430k
    jpc_hdr=IsJPC(magick,sizeof(magick));
764
430k
    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
430k
    if (((LocaleCompare(image_info->magick,"JP2") == 0) && !jp2_hdr) ||
771
430k
        (((LocaleCompare(image_info->magick,"JPC") == 0) ||
772
238k
          (LocaleCompare(image_info->magick,"J2C") == 0)) && !jpc_hdr) ||
773
430k
        ((LocaleCompare(image_info->magick,"PGX") == 0) && !pgx_hdr))
774
213
      {
775
213
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
776
213
                              "Not a \"%s\" file!", image_info->magick);
777
213
        ThrowJP2ReaderException(CorruptImageError,ImproperImageHeader,image);
778
0
      }
779
780
    /*
781
      Throw exception if header is not one we expect.
782
    */
783
430k
    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
430k
    if (((magick_info = GetMagickInfo(image_info->magick,exception)) ==
794
430k
         (const MagickInfo *) NULL) ||
795
430k
        (magick_info->decoder == (DecoderHandler) NULL))
796
0
      {
797
0
        ThrowJP2ReaderException(DelegateError,UnableToDecodeImageFile,image);
798
0
      }
799
430k
  }
800
801
  /*
802
    Obtain a JP2 Stream.
803
  */
804
430k
  jp2_stream=JP2StreamManager(&StreamOperators, image);
805
430k
  if (jp2_stream == (jas_stream_t *) NULL)
806
430k
    ThrowJP2ReaderException(DelegateError,UnableToManageJP2Stream,image);
807
808
  /*
809
    Support passing Jasper options.
810
  */
811
430k
  {
812
430k
    unsigned int
813
430k
      i;
814
815
430k
    MagickBool
816
430k
      max_samples_specified = MagickFalse;
817
818
3.01M
    for (i=0; i < ArraySize(jasper_dec_options); i++)
819
2.58M
      {
820
2.58M
        const char
821
2.58M
          *option = jasper_dec_options[i];
822
823
2.58M
        const char
824
2.58M
          *value;
825
826
2.58M
        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.58M
      }
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
430k
    if (!max_samples_specified)
845
430k
      {
846
430k
        const magick_uintmax_t width_limit = (magick_uintmax_t) GetMagickResourceLimit(WidthResource);
847
430k
        const magick_uintmax_t height_limit = (magick_uintmax_t) GetMagickResourceLimit(HeightResource);
848
430k
        const magick_uintmax_t max_samples_rectangle = width_limit*height_limit;
849
430k
        const magick_uintmax_t max_samples_pixels = (magick_uintmax_t) GetMagickResourceLimit(PixelsResource);
850
430k
        const magick_uintmax_t max_samples = Min(max_samples_rectangle,max_samples_pixels);
851
852
430k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
853
430k
                              "max_samples limits: max_samples_rectangle = "
854
430k
                              "%" MAGICK_UINTMAX_F "u, max_samples_pixels = %" MAGICK_UINTMAX_F "u",
855
430k
                              max_samples_rectangle, max_samples_pixels);
856
857
430k
        MagickFormatString(option_keyval,sizeof(option_keyval),"max_samples=%" MAGICK_UINTMAX_F "u ", max_samples*3);
858
430k
        ConcatenateString(&options,option_keyval);
859
430k
      }
860
861
430k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
862
430k
                          "JP2 options = \"%s\"", options);
863
430k
  }
864
865
  /*
866
    Decode
867
  */
868
430k
  {
869
430k
    int
870
430k
      jas_fmt = -1;
871
872
430k
    const char *
873
430k
      jas_fmt_str = NULL;
874
875
430k
    if (jp2_hdr)
876
19.7k
      jas_fmt_str = "jp2";
877
410k
    else if (jpc_hdr)
878
193k
      jas_fmt_str = "jpc";
879
216k
    else if (pgx_hdr)
880
216k
      jas_fmt_str = "pgx";
881
882
430k
    if (jas_fmt_str != (const char *) NULL)
883
430k
      {
884
430k
        jas_fmt = jas_image_strtofmt(jas_fmt_str);
885
430k
        if (-1 != jas_fmt)
886
430k
          {
887
430k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
888
430k
                                  "Decoding %s...", jas_fmt_str);
889
430k
            jp2_image=jas_image_decode(jp2_stream,jas_fmt,options);
890
430k
          }
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
430k
      }
898
430k
  }
899
900
430k
  MagickFreeMemory(options);
901
902
430k
  if (jp2_image == (jas_image_t *) NULL)
903
381k
    ThrowJP2ReaderException(DelegateError,UnableToDecodeImageFile,image);
904
905
  /*
906
    Validate that we can handle the image and obtain component
907
    indexes.
908
  */
909
48.5k
  switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
910
48.5k
    {
911
496
    case JAS_CLRSPC_FAM_RGB:
912
496
      {
913
496
        if (((components[0]=
914
496
              jas_image_getcmptbytype(jp2_image,
915
496
                                      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0) ||
916
489
            ((components[1]=
917
489
              jas_image_getcmptbytype(jp2_image,
918
489
                                      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0) ||
919
483
            ((components[2]=
920
483
              jas_image_getcmptbytype(jp2_image,
921
483
                                      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0))
922
15
          {
923
15
            ThrowJP2ReaderException(CorruptImageError,MissingImageChannel,image);
924
0
          }
925
481
        number_components=3;
926
481
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
927
481
                              "Image is in RGB colorspace family");
928
481
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
929
481
                              "RED is in channel %d, GREEN is in channel %d, BLUE is in channel %d",
930
481
                              components[0],components[1],components[2]);
931
932
481
        if((components[3]=jas_image_getcmptbytype(jp2_image,
933
481
                                                  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY))) > 0)
934
26
          {
935
26
            image->matte=MagickTrue;
936
26
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
937
26
                                  "OPACITY is in channel %d",components[3]);
938
26
            number_components++;
939
26
          }
940
481
        break;
941
496
      }
942
47.8k
    case JAS_CLRSPC_FAM_GRAY:
943
47.8k
      {
944
47.8k
        if ((components[0]=
945
47.8k
             jas_image_getcmptbytype(jp2_image,
946
47.8k
                                     JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y))) < 0)
947
47.8k
          ThrowJP2ReaderException(CorruptImageError,MissingImageChannel,image);
948
47.8k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
949
47.8k
                              "Image is in GRAY colorspace family");
950
47.8k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
951
47.8k
                              "GRAY is in channel %d",components[0]);
952
47.8k
        number_components=1;
953
47.8k
        break;
954
47.8k
      }
955
92
    case JAS_CLRSPC_FAM_YCBCR:
956
92
      {
957
92
        components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
958
92
        components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
959
92
        components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
960
92
        if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
961
89
          ThrowJP2ReaderException(CorruptImageError,MissingImageChannel,image);
962
89
        number_components=3;
963
89
        components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_OPACITY);
964
89
        if (components[3] > 0)
965
0
          {
966
0
            image->matte=True;
967
0
            number_components++;
968
0
          }
969
89
        image->colorspace=YCbCrColorspace;
970
89
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
971
89
                              "Image is in YCBCR colorspace family");
972
89
        break;
973
92
      }
974
87
    default:
975
87
      {
976
87
        ThrowJP2ReaderException(CoderError,ColorspaceModelIsNotSupported,image);
977
0
      }
978
48.5k
    }
979
48.3k
  image->columns=jas_image_width(jp2_image);
980
48.3k
  image->rows=jas_image_height(jp2_image);
981
48.3k
  if (image->logging)
982
48.3k
    {
983
48.3k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
984
48.3k
                            "columns=%lu rows=%lu components=%d",image->columns,image->rows,
985
48.3k
                            number_components);
986
97.9k
      for (component=0; component < number_components; component++)
987
49.5k
        {
988
49.5k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
989
49.5k
                                "Component %u:\n"
990
49.5k
                                "    width                         = %ld\n" /* width */
991
49.5k
                                "    height                        = %ld\n" /* height */
992
49.5k
                                "    tl x,y coordinate             = %ld,%ld\n" /* x,y-coordinates of the top-left corner */
993
49.5k
                                "    br x,y coordinate             = %ld,%ld\n" /* x,y-coordinates of the bottom-right corner */
994
49.5k
                                "    horizontal subsampling factor = %ld\n" /* horizontal subsampling factor */
995
49.5k
                                "    vertical subsampling factor   = %ld\n" /* vertical subsampling factor */
996
49.5k
                                "    depth                         = %u\n"  /* depth */
997
49.5k
                                "    signed sample data            = %d",   /* signedness of the sample data (true == signed) */
998
49.5k
                                component,
999
49.5k
                                (long) jas_image_cmptwidth(jp2_image,components[component]),
1000
49.5k
                                (long) jas_image_cmptheight(jp2_image,components[component]),
1001
49.5k
                                (long) jas_image_cmpttlx(jp2_image, components[component]),
1002
49.5k
                                (long) jas_image_cmpttly(jp2_image, components[component]),
1003
49.5k
                                (long) jas_image_cmptbrx(jp2_image, components[component]),
1004
49.5k
                                (long) jas_image_cmptbry(jp2_image, components[component]),
1005
49.5k
                                (long) jas_image_cmpthstep(jp2_image, components[component]),
1006
49.5k
                                (long) jas_image_cmptvstep(jp2_image, components[component]),
1007
49.5k
                                (unsigned int) jas_image_cmptprec(jp2_image,components[component]),
1008
49.5k
                                (int) jas_image_cmptsgnd(jp2_image, components[component]));
1009
49.5k
        }
1010
48.3k
    }
1011
97.1k
  for (component=0; component < number_components; component++)
1012
49.4k
    {
1013
49.4k
      if (((unsigned long) jas_image_cmptwidth(jp2_image,components[component]) != image->columns) ||
1014
49.0k
          ((unsigned long) jas_image_cmptheight(jp2_image,components[component]) != image->rows) ||
1015
48.7k
          (jas_image_cmpttlx(jp2_image, components[component]) != 0) ||
1016
48.7k
          (jas_image_cmpttly(jp2_image, components[component]) != 0) ||
1017
48.7k
          (jas_image_cmpthstep(jp2_image, components[component]) != 1) ||
1018
48.7k
          (jas_image_cmptvstep(jp2_image, components[component]) != 1))
1019
48.7k
        ThrowJP2ReaderException(CoderError,IrregularChannelGeometryNotSupported,image);
1020
48.7k
    }
1021
  /* FIXME: It would be good to support signed data! */
1022
89.9k
  for (component=0; component < number_components; component++)
1023
48.6k
    {
1024
48.6k
      if ((jas_image_cmptsgnd(jp2_image, components[component]) != false))
1025
42.3k
        ThrowJP2ReaderException(CoderError,DataStorageTypeIsNotSupported,image);
1026
42.3k
    }
1027
1028
41.3k
  image->matte=number_components > 3;
1029
83.5k
  for (component=0; component < number_components; component++)
1030
42.2k
    {
1031
42.2k
      unsigned int
1032
42.2k
        component_depth;
1033
1034
42.2k
      component_depth=jas_image_cmptprec(jp2_image,components[component]);
1035
42.2k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1036
42.2k
                            "Component[%d] depth is %u",component,component_depth);
1037
42.2k
      if (0 == component)
1038
41.3k
        image->depth=component_depth;
1039
970
      else
1040
970
        image->depth=Max(image->depth,component_depth);
1041
42.2k
    }
1042
41.3k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1043
41.3k
                        "Image depth is %u",image->depth);
1044
41.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
41.3k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
1056
38.0k
    ThrowJP2ReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1057
1058
  /*
1059
    Allocate Jasper pixels.
1060
  */
1061
38.0k
  pixels=jas_matrix_create(1,(unsigned int) image->columns);
1062
38.0k
  if (pixels == (jas_matrix_t *) NULL)
1063
38.0k
    ThrowJP2ReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1064
1065
  /*
1066
    Allocate and populate channel LUTs
1067
  */
1068
76.0k
  for (component=0; component < (long) number_components; component++)
1069
38.8k
    {
1070
38.8k
      double
1071
38.8k
        scale_to_quantum;
1072
1073
38.8k
      unsigned int
1074
38.8k
        component_depth,
1075
38.8k
        i,
1076
38.8k
        max_value;
1077
1078
38.8k
      component_depth=jas_image_cmptprec(jp2_image,components[component]);
1079
38.8k
      if ((0 == component_depth) || (component_depth > 16))
1080
881
        {
1081
881
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1082
881
                                "Component %u depth is %u!",
1083
881
                                component, component_depth);
1084
881
          ThrowJP2ReaderException(CorruptImageError,ImproperImageHeader,image);
1085
0
        }
1086
38.0k
      max_value=(unsigned int) MaxValueGivenBits(component_depth);
1087
38.0k
      if ((0 == max_value) || (max_value > 65535))
1088
38.0k
        ThrowJP2ReaderException(CorruptImageError,ImproperImageHeader,image);
1089
38.0k
      scale_to_quantum=MaxRGBDouble/max_value;
1090
38.0k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1091
38.0k
                            "Channel %d scale is %g", component, scale_to_quantum);
1092
38.0k
      channel_lut[component]=MagickAllocateResourceLimitedArray(Quantum *, (size_t) max_value+1,sizeof(Quantum));
1093
38.0k
      if (channel_lut[component] == (Quantum *) NULL)
1094
38.0k
        ThrowJP2ReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1095
26.7M
      for (i=0; i <= max_value; i++)
1096
26.7M
        (channel_lut[component])[i]=scale_to_quantum*i+0.5;
1097
38.0k
    }
1098
1099
  /*
1100
    Convert JPEG 2000 pixels.
1101
  */
1102
1.65M
  for (y=0; y < (long) image->rows; y++)
1103
1.63M
    {
1104
1.63M
      q=GetImagePixels(image,0,y,image->columns,1);
1105
1.63M
      if (q == (PixelPacket *) NULL)
1106
19.2k
        break;
1107
1108
1.61M
      if (1 == number_components)
1109
1.45M
        {
1110
          /* Grayscale */
1111
1.45M
          (void) jas_image_readcmpt(jp2_image,(short) components[0],0,
1112
1.45M
                                    (unsigned int) y,
1113
1.45M
                                    (unsigned int) image->columns,1,pixels);
1114
1.45G
          for (x=0; x < (long) image->columns; x++)
1115
1.45G
            {
1116
1.45G
              q->red=q->green=q->blue=(channel_lut[0])[jas_matrix_getv(pixels,x)];
1117
1.45G
              q->opacity=OpaqueOpacity;
1118
1.45G
              q++;
1119
1.45G
            }
1120
1.45M
        }
1121
163k
      else
1122
163k
        {
1123
          /* Red */
1124
163k
          (void) jas_image_readcmpt(jp2_image,(short) components[0],0,
1125
163k
                                    (unsigned int) y,
1126
163k
                                    (unsigned int) image->columns,1,pixels);
1127
157M
          for (x=0; x < (long) image->columns; x++)
1128
157M
            q[x].red=(channel_lut[0])[jas_matrix_getv(pixels,x)];
1129
1130
          /* Green */
1131
163k
          (void) jas_image_readcmpt(jp2_image,(short) components[1],0,
1132
163k
                                    (unsigned int) y,
1133
163k
                                    (unsigned int) image->columns,1,pixels);
1134
157M
          for (x=0; x < (long) image->columns; x++)
1135
157M
            q[x].green=(channel_lut[1])[jas_matrix_getv(pixels,x)];
1136
1137
          /* Blue */
1138
163k
          (void) jas_image_readcmpt(jp2_image,(short) components[2],0,
1139
163k
                                    (unsigned int) y,
1140
163k
                                    (unsigned int) image->columns,1,pixels);
1141
157M
          for (x=0; x < (long) image->columns; x++)
1142
157M
            q[x].blue=(channel_lut[2])[jas_matrix_getv(pixels,x)];
1143
1144
          /* Opacity */
1145
163k
          if (number_components > 3)
1146
3.53k
            {
1147
3.53k
              (void) jas_image_readcmpt(jp2_image,(short) components[3],0,
1148
3.53k
                                        (unsigned int) y,
1149
3.53k
                                        (unsigned int) image->columns,1,pixels);
1150
442k
              for (x=0; x < (long) image->columns; x++)
1151
439k
                q[x].opacity=MaxRGB-(channel_lut[3])[jas_matrix_getv(pixels,x)];
1152
3.53k
            }
1153
160k
          else
1154
160k
            {
1155
157M
              for (x=0; x < (long) image->columns; x++)
1156
157M
                q[x].opacity=OpaqueOpacity;
1157
160k
            }
1158
163k
        }
1159
1.61M
      if (!SyncImagePixels(image))
1160
0
        break;
1161
1.61M
      if (image->previous == (Image *) NULL)
1162
1.61M
        if (QuantumTick(y,image->rows))
1163
234k
          if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
1164
234k
                                      image->filename,
1165
234k
                                      image->columns,image->rows))
1166
0
            break;
1167
1.61M
    }
1168
37.1k
  if (number_components == 1)
1169
36.7k
    image->is_grayscale=MagickTrue;
1170
37.1k
  {
1171
    /*
1172
      Obtain ICC ICM color profile
1173
    */
1174
1175
37.1k
    jas_cmprof_t
1176
37.1k
      *cm_profile;
1177
1178
    /* Obtain a pointer to the existing jas_cmprof_t profile handle. */
1179
37.1k
    cm_profile=jas_image_cmprof(jp2_image);
1180
37.1k
    if (cm_profile != (jas_cmprof_t *) NULL)
1181
37.1k
      {
1182
37.1k
        jas_iccprof_t
1183
37.1k
          *icc_profile;
1184
1185
        /* Obtain a copy of the jas_iccprof_t ICC profile handle */
1186
37.1k
        icc_profile=jas_iccprof_createfromcmprof(cm_profile);
1187
        /* or maybe just icc_profile=cm_profile->iccprof */
1188
37.1k
        if (icc_profile != (jas_iccprof_t *) NULL)
1189
37.1k
          {
1190
37.1k
            jas_stream_t
1191
37.1k
              *icc_stream;
1192
1193
37.1k
            icc_stream=jas_stream_memopen(NULL,0);
1194
37.1k
            if ((icc_stream != (jas_stream_t *) NULL) &&
1195
37.1k
                (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
1196
37.1k
                (jas_stream_flush(icc_stream) == 0))
1197
37.1k
              {
1198
37.1k
                jas_stream_memobj_t
1199
37.1k
                  *blob;
1200
1201
37.1k
                blob=(jas_stream_memobj_t *) icc_stream->obj_;
1202
37.1k
                if (image->logging)
1203
37.1k
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1204
37.1k
                                        "ICC profile: %lu bytes",(unsigned long) blob->len_);
1205
37.1k
                SetImageProfile(image,"ICM",blob->buf_,blob->len_);
1206
1207
37.1k
                (void) jas_stream_close(icc_stream);
1208
37.1k
                jas_iccprof_destroy(icc_profile);
1209
37.1k
              }
1210
37.1k
          }
1211
37.1k
      }
1212
37.1k
  }
1213
1214
75.1k
  for (component=0; component < (long) number_components; component++)
1215
37.9k
    MagickFreeResourceLimitedMemory(Quantum *,channel_lut[component]);
1216
37.1k
  jas_matrix_destroy(pixels);
1217
37.1k
  (void) jas_stream_close(jp2_stream);
1218
37.1k
  MagickFreeMemory(options);
1219
37.1k
  jas_image_destroy(jp2_image);
1220
37.1k
  StopTimer(&image->timer);
1221
37.1k
#if HAVE_JAS_INIT_LIBRARY
1222
  /* Perform any per-thread clean-up for the JasPer library. */
1223
37.1k
  JAS_CLEANUP_THREAD();
1224
37.1k
#endif /* if HAVE_JAS_INIT_LIBRARY */
1225
37.1k
  return(image);
1226
38.0k
}
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
10
{
1254
10
#if defined(HasJP2)
1255
10
  static char
1256
10
    version[16];
1257
1258
10
  MagickInfo
1259
10
    *entry;
1260
1261
10
  (void) strlcpy(version,"JasPer ",sizeof(version));
1262
10
  (void) strlcat(version,jas_getversion(),sizeof(version));
1263
1264
10
#if !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC)
1265
10
  entry=SetMagickInfo("J2C");
1266
10
  entry->description="JPEG-2000 Code Stream Syntax";
1267
10
  entry->version=version;
1268
10
  entry->module="JP2";
1269
10
  entry->magick=(MagickHandler) IsJPC;
1270
10
  entry->adjoin=False;
1271
10
  entry->seekable_stream=True;
1272
10
  entry->thread_support=False;
1273
10
  entry->decoder=(DecoderHandler) ReadJP2Image;
1274
10
  entry->encoder=(EncoderHandler) WriteJP2Image;
1275
10
  entry->coder_class=StableCoderClass;
1276
10
  (void) RegisterMagickInfo(entry);
1277
10
#endif /* !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC) */
1278
1279
10
#if !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC)
1280
10
  entry=SetMagickInfo("JP2");
1281
10
  entry->description="JPEG-2000 JP2 File Format Syntax";
1282
10
  entry->version=version;
1283
10
  entry->module="JP2";
1284
10
  entry->magick=(MagickHandler) IsJP2;
1285
10
  entry->adjoin=False;
1286
10
  entry->seekable_stream=True;
1287
10
  entry->thread_support=False;
1288
10
  entry->decoder=(DecoderHandler) ReadJP2Image;
1289
10
  entry->encoder=(EncoderHandler) WriteJP2Image;
1290
10
  entry->coder_class=StableCoderClass;
1291
10
  (void) RegisterMagickInfo(entry);
1292
10
#endif /* !defined(EXCLUDE_JP2_SUPPORT) || defined(JAS_ENABLE_JP2_CODEC) */
1293
1294
10
#if !defined(EXCLUDE_JPC_SUPPORT) || defined(JAS_ENABLE_JPC_CODEC)
1295
10
  entry=SetMagickInfo("JPC");
1296
10
  entry->description="JPEG-2000 Code Stream Syntax";
1297
10
  entry->version=version;
1298
10
  entry->module="JP2";
1299
10
  entry->magick=(MagickHandler) IsJPC;
1300
10
  entry->adjoin=False;
1301
10
  entry->seekable_stream=True;
1302
10
  entry->thread_support=False;
1303
10
  entry->decoder=(DecoderHandler) ReadJP2Image;
1304
10
  entry->encoder=(EncoderHandler) WriteJP2Image;
1305
10
  entry->coder_class=StableCoderClass;
1306
10
  (void) RegisterMagickInfo(entry);
1307
10
#endif /* !defined(EXCLUDE_JPC_SUPPORT) || defined(JAS_ENABLE_JPC_CODEC) */
1308
1309
10
#if !defined(EXCLUDE_PGX_SUPPORT) || defined(JAS_ENABLE_PGX_CODEC)
1310
10
  entry=SetMagickInfo("PGX");
1311
10
  entry->description="JPEG-2000 VM Format";
1312
10
  entry->version=version;
1313
10
  entry->module="JP2";
1314
10
  entry->magick=(MagickHandler) IsPGX;
1315
10
  entry->adjoin=False;
1316
10
  entry->seekable_stream=True;
1317
10
  entry->thread_support=False;
1318
10
  entry->decoder=(DecoderHandler) ReadJP2Image;
1319
10
  entry->encoder=(EncoderHandler) WriteJP2Image;
1320
10
  entry->coder_class=UnstableCoderClass;
1321
10
  (void) RegisterMagickInfo(entry);
1322
10
#endif /* !defined(EXCLUDE_PGX_SUPPORT) || defined(JAS_ENABLE_PGX_CODEC) */
1323
1324
10
#endif /* if defined(HasJP2) */
1325
10
}
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
2.41k
{
1396
2.41k
  char
1397
2.41k
    magick[MaxTextExtent],
1398
2.41k
    option_keyval[MaxTextExtent],
1399
2.41k
    *options = NULL;
1400
1401
2.41k
  int
1402
2.41k
    format;
1403
1404
2.41k
  long
1405
2.41k
    y;
1406
1407
2.41k
  jas_image_cmptparm_t
1408
2.41k
    component_info;
1409
1410
2.41k
  jas_image_t
1411
2.41k
    *jp2_image;
1412
1413
2.41k
  jas_matrix_t
1414
2.41k
    *jp2_pixels;
1415
1416
2.41k
  jas_stream_ops_t
1417
2.41k
    StreamOperators =
1418
2.41k
    {
1419
2.41k
      BlobRead,
1420
2.41k
      BlobWrite,
1421
2.41k
      BlobSeek,
1422
2.41k
      BlobClose
1423
2.41k
    };
1424
1425
2.41k
  jas_stream_t
1426
2.41k
    *jp2_stream;
1427
1428
2.41k
  register const PixelPacket
1429
2.41k
    *p;
1430
1431
2.41k
  register int
1432
2.41k
    x;
1433
1434
2.41k
  MagickBool
1435
2.41k
    rate_specified=MagickFalse;
1436
1437
2.41k
  MagickPassFail
1438
2.41k
    status;
1439
1440
2.41k
  int
1441
2.41k
    component,
1442
2.41k
    number_components;
1443
1444
2.41k
  unsigned short
1445
2.41k
    *lut;
1446
1447
2.41k
  ImageCharacteristics
1448
2.41k
    characteristics;
1449
1450
  /*
1451
    Initialize Jasper
1452
  */
1453
2.41k
  if (initialize_jasper(&image->exception) != MagickPass)
1454
0
    {
1455
0
      return MagickFail;
1456
0
    }
1457
1458
2.41k
#if HAVE_JAS_INIT_LIBRARY
1459
  /*
1460
    Perform any per-thread initialization for the JasPer library.
1461
  */
1462
2.41k
  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
2.41k
#endif /* if HAVE_JAS_INIT_LIBRARY */
1470
1471
  /*
1472
    Open image file.
1473
  */
1474
2.41k
  assert(image_info != (const ImageInfo *) NULL);
1475
2.41k
  assert(image_info->signature == MagickSignature);
1476
2.41k
  assert(image != (Image *) NULL);
1477
2.41k
  assert(image->signature == MagickSignature);
1478
2.41k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1479
2.41k
  if (status == MagickFail)
1480
2.41k
    ThrowJP2WriterException(FileOpenError,UnableToOpenFile,image);
1481
1482
  /*
1483
    Ensure that image is in RGB space.
1484
  */
1485
2.41k
  if (TransformColorspace(image,RGBColorspace) == MagickFail)
1486
2.41k
      ThrowWriterException(CoderError,UnableToTransformColorspace,image);
1487
1488
  /*
1489
    PGX format requires a grayscale representation
1490
  */
1491
2.41k
  if (strcmp("PGX",image_info->magick) == 0)
1492
275
    {
1493
275
      if (SetImageType(image,GrayscaleType) == MagickFail)
1494
275
        ThrowWriterException(CoderError,UnableToSetImageType,image);
1495
275
    }
1496
1497
  /*
1498
    Analyze image to be written.
1499
  */
1500
2.41k
  if (!GetImageCharacteristics(image,&characteristics,
1501
2.41k
                               (OptimizeType == image_info->type),
1502
2.41k
                               &image->exception))
1503
0
    {
1504
0
      CloseBlob(image);
1505
0
      return MagickFail;
1506
0
    }
1507
1508
  /*
1509
    Support passing Jasper options.
1510
  */
1511
2.41k
  {
1512
2.41k
    unsigned int
1513
2.41k
      i;
1514
1515
65.1k
    for (i=0; i < ArraySize(jasper_enc_options); i++)
1516
62.7k
      {
1517
62.7k
        const char
1518
62.7k
          *option = jasper_enc_options[i];
1519
1520
62.7k
        const char
1521
62.7k
          *value;
1522
1523
62.7k
        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
62.7k
      }
1553
2.41k
  }
1554
1555
  /*
1556
    Obtain a JP2 stream.
1557
  */
1558
2.41k
  jp2_stream=JP2StreamManager(&StreamOperators, image);
1559
2.41k
  if (jp2_stream == (jas_stream_t *) NULL)
1560
2.41k
    ThrowJP2WriterException(DelegateError,UnableToManageJP2Stream,image);
1561
2.41k
  number_components=image->matte ? 4 : 3;
1562
2.41k
  if ((image_info->type != TrueColorType) &&
1563
2.41k
      (characteristics.grayscale))
1564
2.00k
    number_components=1;
1565
1566
2.41k
  jp2_image=jas_image_create0();
1567
2.41k
  if (jp2_image == (jas_image_t *) NULL)
1568
2.41k
    ThrowJP2WriterException(DelegateError,UnableToCreateImage,image);
1569
1570
5.67k
  for (component=0; component < number_components; component++)
1571
3.25k
  {
1572
3.25k
    (void) memset((void *)&component_info,0,sizeof(jas_image_cmptparm_t));
1573
3.25k
    component_info.tlx=0; /* top left x ordinate */
1574
3.25k
    component_info.tly=0; /* top left y ordinate */
1575
3.25k
    component_info.hstep=1; /* horizontal pixels per step */
1576
3.25k
    component_info.vstep=1; /* vertical pixels per step */
1577
3.25k
    component_info.width=(unsigned int) image->columns;
1578
3.25k
    component_info.height=(unsigned int) image->rows;
1579
3.25k
    component_info.prec=(unsigned int) Max(2,Min(image->depth,16)); /* bits in range */
1580
3.25k
    component_info.sgnd = false;  /* range is signed value? */
1581
1582
3.25k
    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
3.25k
  }
1587
1588
  /*
1589
    Allocate and compute LUT.
1590
  */
1591
2.41k
  {
1592
2.41k
    unsigned long
1593
2.41k
      i,
1594
2.41k
      max_value;
1595
1596
2.41k
    double
1597
2.41k
      scale_to_component;
1598
1599
2.41k
    lut=MagickAllocateResourceLimitedArray(unsigned short *,MaxMap+1,sizeof(*lut));
1600
2.41k
    if (lut == (unsigned short *) NULL)
1601
0
      {
1602
0
        jas_image_destroy(jp2_image);
1603
0
        ThrowJP2WriterException(ResourceLimitError,MemoryAllocationFailed,image);
1604
0
      }
1605
1606
2.41k
    max_value=MaxValueGivenBits(component_info.prec);
1607
2.41k
    scale_to_component=max_value/MaxRGBDouble;
1608
158M
    for(i=0; i <= MaxMap; i++)
1609
158M
        lut[i]=scale_to_component*i+0.5;
1610
2.41k
  }
1611
1612
2.41k
  if (number_components == 1)
1613
2.00k
    {
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
2.00k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1619
2.00k
        "Setting SGRAY colorspace");
1620
2.00k
      jas_image_setclrspc(jp2_image, JAS_CLRSPC_SGRAY);
1621
2.00k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1622
2.00k
        "Setting GRAY channel to channel 0");
1623
2.00k
      jas_image_setcmpttype(jp2_image,0,
1624
2.00k
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
1625
2.00k
    }
1626
413
  else
1627
413
    {
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
413
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1634
413
        "Setting SRGB colorspace");
1635
413
      jas_image_setclrspc(jp2_image, JAS_CLRSPC_SRGB);
1636
413
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1637
413
        "Setting RED channel to channel 0");
1638
413
      jas_image_setcmpttype(jp2_image,0,
1639
413
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
1640
413
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1641
413
        "Setting GREEN channel to channel 1");
1642
413
      jas_image_setcmpttype(jp2_image,1,
1643
413
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
1644
413
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1645
413
        "Setting BLUE channel to channel 2");
1646
413
      jas_image_setcmpttype(jp2_image,2,
1647
413
        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
1648
413
      if (number_components == 4 )
1649
18
        {
1650
18
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1651
18
            "Setting OPACITY channel to channel 3");
1652
18
          jas_image_setcmpttype(jp2_image,3,
1653
18
            JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
1654
18
        }
1655
413
    }
1656
  /*
1657
    Convert to JPEG 2000 pixels.
1658
  */
1659
2.41k
  jp2_pixels=jas_matrix_create(1,(unsigned int) image->columns);
1660
2.41k
  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.60M
  for (y=0; y < (long) image->rows; y++)
1668
1.60M
  {
1669
1.60M
    p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1670
1.60M
    if (p == (const PixelPacket *) NULL)
1671
0
      break;
1672
1.60M
    if (number_components == 1)
1673
1.43M
      {
1674
1.45G
        for (x=0; x < (long) image->columns; x++)
1675
1.45G
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(PixelIntensityToQuantum(&p[x]))]);
1676
1.43M
        (void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y,
1677
1.43M
                                   (unsigned int) image->columns,1,jp2_pixels);
1678
1.43M
      }
1679
163k
    else
1680
163k
      {
1681
157M
        for (x=0; x < (long) image->columns; x++)
1682
157M
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].red)]);
1683
163k
        (void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y,
1684
163k
                                   (unsigned int) image->columns,1,jp2_pixels);
1685
1686
157M
        for (x=0; x < (long) image->columns; x++)
1687
157M
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].green)]);
1688
163k
        (void) jas_image_writecmpt(jp2_image,1,0,(unsigned int) y,
1689
163k
                                   (unsigned int) image->columns,1,jp2_pixels);
1690
1691
157M
        for (x=0; x < (long) image->columns; x++)
1692
157M
          jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].blue)]);
1693
163k
        (void) jas_image_writecmpt(jp2_image,2,0,(unsigned int) y,
1694
163k
                                   (unsigned int) image->columns,1,jp2_pixels);
1695
1696
163k
        if (number_components > 3)
1697
442k
          for (x=0; x < (long) image->columns; x++)
1698
439k
            jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(MaxRGB-p[x].opacity)]);
1699
163k
        (void) jas_image_writecmpt(jp2_image,3,0,(unsigned int) y,
1700
163k
                                   (unsigned int) image->columns,1,jp2_pixels);
1701
163k
      }
1702
1.60M
    if (image->previous == (Image *) NULL)
1703
1.60M
      if (QuantumTick(y,image->rows))
1704
218k
        if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1705
218k
                                    SaveImageText,image->filename,
1706
218k
                                    image->columns,image->rows))
1707
0
          break;
1708
1.60M
  }
1709
2.41k
  (void) strlcpy(magick,image_info->magick,MaxTextExtent);
1710
  /*
1711
    J2C is an alias for JPC but Jasper only supports "JPC".
1712
  */
1713
2.41k
  if (LocaleCompare(magick,"j2c") == 0)
1714
771
    (void) strlcpy(magick,"jpc",sizeof(magick));
1715
2.41k
  LocaleLower(magick);
1716
2.41k
  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
2.41k
  if (rate_specified == MagickFalse)
1723
2.41k
    {
1724
2.41k
      double
1725
2.41k
        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
2.41k
      if ((image_info->quality < 100.0-MagickEpsilon) &&
1733
2.41k
          (MagickArraySize(image->rows,image->columns) > 2500U))
1734
1.98k
        {
1735
1.98k
          double
1736
1.98k
            header_size,
1737
1.98k
            current_size,
1738
1.98k
            target_size,
1739
1.98k
            d;
1740
1741
1.98k
          d=115-image_info->quality;  /* Best number is 110-115 */
1742
1.98k
          rate=100.0/(d*d);
1743
1.98k
          header_size=550.0; /* Base file size. */
1744
1.98k
          header_size+=((size_t) number_components-1)*142; /* Additional components */
1745
          /* FIXME: Need to account for any ICC profiles here */
1746
1747
1.98k
          current_size=(double)((image->rows*image->columns*image->depth)/8)*
1748
1.98k
            number_components;
1749
1.98k
          target_size=(current_size*rate)+header_size;
1750
1.98k
          rate=target_size/current_size;
1751
1.98k
          MagickFormatString(option_keyval,sizeof(option_keyval),"%s=%g ","rate",rate);
1752
1.98k
          ConcatenateString(&options,option_keyval);
1753
1.98k
        }
1754
2.41k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1755
2.41k
        "Compression rate: %g (%3.2f:1)",rate,1.0/rate);
1756
2.41k
    }
1757
1758
1759
2.41k
  if (options)
1760
1.98k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1761
1.98k
       "Jasper options: \"%s\"", options);
1762
1763
2.41k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Encoding image");
1764
2.41k
  status=jas_image_encode(jp2_image,jp2_stream,format,options);
1765
2.41k
  (void) jas_stream_close(jp2_stream);
1766
2.41k
  MagickFreeMemory(options);
1767
2.41k
  MagickFreeResourceLimitedMemory(unsigned short *,lut);
1768
2.41k
  jas_matrix_destroy(jp2_pixels);
1769
2.41k
  jas_image_destroy(jp2_image);
1770
2.41k
  if (status)
1771
2.39k
    ThrowJP2WriterException(DelegateError,UnableToEncodeImageFile,image);
1772
1773
2.39k
#if HAVE_JAS_INIT_LIBRARY
1774
  /* Perform any per-thread clean-up for the JasPer library. */
1775
2.39k
  JAS_CLEANUP_THREAD();
1776
2.39k
#endif /* if HAVE_JAS_INIT_LIBRARY */
1777
2.39k
  return(True);
1778
2.41k
}
1779
#endif /* if defined(HasJP2) */