Coverage Report

Created: 2026-06-16 07:20

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