Coverage Report

Created: 2026-09-14 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jasper/src/libjasper/jp2/jp2_enc.c
Line
Count
Source
1
/*
2
 * Copyright (c) 1999-2000 Image Power, Inc. and the University of
3
 *   British Columbia.
4
 * Copyright (c) 2001-2003 Michael David Adams.
5
 * All rights reserved.
6
 */
7
8
/* __START_OF_JASPER_LICENSE__
9
 * 
10
 * JasPer License Version 2.0
11
 * 
12
 * Copyright (c) 2001-2006 Michael David Adams
13
 * Copyright (c) 1999-2000 Image Power, Inc.
14
 * Copyright (c) 1999-2000 The University of British Columbia
15
 * 
16
 * All rights reserved.
17
 * 
18
 * Permission is hereby granted, free of charge, to any person (the
19
 * "User") obtaining a copy of this software and associated documentation
20
 * files (the "Software"), to deal in the Software without restriction,
21
 * including without limitation the rights to use, copy, modify, merge,
22
 * publish, distribute, and/or sell copies of the Software, and to permit
23
 * persons to whom the Software is furnished to do so, subject to the
24
 * following conditions:
25
 * 
26
 * 1.  The above copyright notices and this permission notice (which
27
 * includes the disclaimer below) shall be included in all copies or
28
 * substantial portions of the Software.
29
 * 
30
 * 2.  The name of a copyright holder shall not be used to endorse or
31
 * promote products derived from the Software without specific prior
32
 * written permission.
33
 * 
34
 * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
35
 * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
36
 * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
37
 * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
38
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
39
 * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
40
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
41
 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
42
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
43
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
44
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
45
 * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
46
 * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
47
 * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
48
 * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
49
 * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
50
 * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
51
 * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
52
 * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
53
 * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
54
 * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
55
 * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
56
 * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
57
 * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
58
 * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
59
 * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
60
 * 
61
 * __END_OF_JASPER_LICENSE__
62
 */
63
64
/*
65
 * JP2 Library
66
 *
67
 * $Id$
68
 */
69
70
/******************************************************************************\
71
* Includes.
72
\******************************************************************************/
73
74
#include "jasper/jas_image.h"
75
#include "jasper/jas_malloc.h"
76
#include "jasper/jas_stream.h"
77
#include "jasper/jas_cm.h"
78
#include "jasper/jas_icc.h"
79
#include "jasper/jas_debug.h"
80
81
#include "jp2_cod.h"
82
83
#include <stdio.h>
84
#include <stdlib.h>
85
86
/******************************************************************************\
87
* Function prototypes.
88
\******************************************************************************/
89
90
static uint_fast32_t jp2_gettypeasoc(int colorspace, int ctype);
91
static int clrspctojp2(jas_clrspc_t clrspc);
92
93
/******************************************************************************\
94
* Functions.
95
\******************************************************************************/
96
97
int jp2_encode(jas_image_t *image, jas_stream_t *out, const char *optstr)
98
783
{
99
783
  jp2_box_t *box;
100
783
  jp2_ftyp_t *ftyp;
101
783
  jp2_ihdr_t *ihdr;
102
783
  jas_stream_t *tmpstream;
103
783
  int allcmptssame;
104
783
  jp2_bpcc_t *bpcc;
105
783
  long len;
106
783
  uint_fast16_t cmptno;
107
783
  jp2_colr_t *colr;
108
783
  char buf[4096];
109
783
  uint_fast32_t overhead;
110
783
  jp2_cdefchan_t *cdefchanent;
111
783
  jp2_cdef_t *cdef;
112
783
  uint_fast32_t typeasoc;
113
783
  jas_iccprof_t *iccprof;
114
783
  jas_stream_t *iccstream;
115
783
  int pos;
116
783
  int needcdef;
117
118
783
  box = 0;
119
783
  tmpstream = 0;
120
783
  iccstream = 0;
121
783
  iccprof = 0;
122
123
783
  if (jas_image_numcmpts(image) < 1) {
124
0
    jas_logerrorf("image must have at least one component\n");
125
0
    goto error;
126
0
  }
127
128
783
  allcmptssame = 1;
129
783
  const bool sgnd = jas_image_cmptsgnd(image, 0);
130
783
  const unsigned prec = jas_image_cmptprec(image, 0);
131
1.19k
  for (unsigned i = 1; i < jas_image_numcmpts(image); ++i) {
132
414
    if (jas_image_cmptsgnd(image, i) != sgnd ||
133
414
      jas_image_cmptprec(image, i) != prec) {
134
0
      allcmptssame = 0;
135
0
      break;
136
0
    }
137
414
  }
138
139
  /* Output the signature box. */
140
141
783
  if (!(box = jp2_box_create(JP2_BOX_JP))) {
142
0
    jas_logerrorf("cannot create JP box\n");
143
0
    goto error;
144
0
  }
145
783
  box->data.jp.magic = JP2_JP_MAGIC;
146
783
  if (jp2_box_put(box, out)) {
147
0
    jas_logerrorf("cannot write JP box\n");
148
0
    goto error;
149
0
  }
150
783
  jp2_box_destroy(box);
151
783
  box = 0;
152
153
  /* Output the file type box. */
154
155
783
  if (!(box = jp2_box_create(JP2_BOX_FTYP))) {
156
0
    jas_logerrorf("cannot create FTYP box\n");
157
0
    goto error;
158
0
  }
159
783
  ftyp = &box->data.ftyp;
160
783
  ftyp->majver = JP2_FTYP_MAJVER;
161
783
  ftyp->minver = JP2_FTYP_MINVER;
162
783
  ftyp->numcompatcodes = 1;
163
783
  ftyp->compatcodes[0] = JP2_FTYP_COMPATCODE;
164
783
  if (jp2_box_put(box, out)) {
165
0
    jas_logerrorf("cannot write FTYP box\n");
166
0
    goto error;
167
0
  }
168
783
  jp2_box_destroy(box);
169
783
  box = 0;
170
171
  /*
172
   * Generate the data portion of the JP2 header box.
173
   * We cannot simply output the header for this box
174
   * since we do not yet know the correct value for the length
175
   * field.
176
   */
177
178
783
  if (!(tmpstream = jas_stream_memopen(0, 0))) {
179
0
    jas_logerrorf("cannot create temporary stream\n");
180
0
    goto error;
181
0
  }
182
183
  /* Generate image header box. */
184
185
783
  if (!(box = jp2_box_create(JP2_BOX_IHDR))) {
186
0
    jas_logerrorf("cannot create IHDR box\n");
187
0
    goto error;
188
0
  }
189
783
  ihdr = &box->data.ihdr;
190
783
  ihdr->width = jas_image_width(image);
191
783
  ihdr->height = jas_image_height(image);
192
783
  ihdr->numcmpts = jas_image_numcmpts(image);
193
783
  ihdr->bpc = allcmptssame ? JP2_SPTOBPC(jas_image_cmptsgnd(image, 0),
194
783
    jas_image_cmptprec(image, 0)) : JP2_IHDR_BPCNULL;
195
783
  ihdr->comptype = JP2_IHDR_COMPTYPE;
196
783
  ihdr->csunk = 0;
197
783
  ihdr->ipr = 0;
198
783
  if (jp2_box_put(box, tmpstream)) {
199
0
    jas_logerrorf("cannot write IHDR box\n");
200
0
    goto error;
201
0
  }
202
783
  jp2_box_destroy(box);
203
783
  box = 0;
204
205
  /* Generate bits per component box. */
206
207
783
  if (!allcmptssame) {
208
0
    if (!(box = jp2_box_create(JP2_BOX_BPCC))) {
209
0
      jas_logerrorf("cannot create BPCC box\n");
210
0
      goto error;
211
0
    }
212
0
    bpcc = &box->data.bpcc;
213
0
    bpcc->numcmpts = jas_image_numcmpts(image);
214
0
    if (!(bpcc->bpcs = jas_alloc2(bpcc->numcmpts,
215
0
      sizeof(uint_fast8_t)))) {
216
0
      jas_logerrorf("memory allocation failed\n");
217
0
      goto error;
218
0
    }
219
0
    for (cmptno = 0; cmptno < bpcc->numcmpts; ++cmptno) {
220
0
      bpcc->bpcs[cmptno] = JP2_SPTOBPC(jas_image_cmptsgnd(image,
221
0
        cmptno), jas_image_cmptprec(image, cmptno));
222
0
    }
223
0
    if (jp2_box_put(box, tmpstream)) {
224
0
      jas_logerrorf("cannot write BPCC box\n");
225
0
      goto error;
226
0
    }
227
0
    jp2_box_destroy(box);
228
0
    box = 0;
229
0
  }
230
231
  /* Generate color specification box. */
232
233
783
  if (!(box = jp2_box_create(JP2_BOX_COLR))) {
234
0
    jas_logerrorf("cannot create COLR box\n");
235
0
    goto error;
236
0
  }
237
783
  colr = &box->data.colr;
238
783
  switch (jas_image_clrspc(image)) {
239
198
  case JAS_CLRSPC_SRGB:
240
198
  case JAS_CLRSPC_SYCBCR:
241
783
  case JAS_CLRSPC_SGRAY:
242
783
    colr->method = JP2_COLR_ENUM;
243
783
    colr->csid = clrspctojp2(jas_image_clrspc(image));
244
783
    colr->pri = JP2_COLR_PRI;
245
783
    colr->approx = 0;
246
783
    break;
247
0
  default:
248
0
    colr->method = JP2_COLR_ICC;
249
0
    colr->pri = JP2_COLR_PRI;
250
0
    colr->approx = 0;
251
    /* Ensure that cmprof_ is not null. */
252
0
    if (!jas_image_cmprof(image)) {
253
0
      jas_logerrorf("CM profile is null\n");
254
0
      goto error;
255
0
    }
256
0
    if (!(iccprof = jas_iccprof_createfromcmprof(
257
0
      jas_image_cmprof(image)))) {
258
0
      jas_logerrorf("cannot create ICC profile\n");
259
0
      goto error;
260
0
    }
261
0
    if (!(iccstream = jas_stream_memopen(0, 0))) {
262
0
      jas_logerrorf("cannot create temporary stream\n");
263
0
      goto error;
264
0
    }
265
0
    if (jas_iccprof_save(iccprof, iccstream)) {
266
0
      jas_logerrorf("cannot write ICC profile\n");
267
0
      goto error;
268
0
    }
269
0
    if ((pos = jas_stream_tell(iccstream)) < 0) {
270
0
      jas_logerrorf("cannot get stream position\n");
271
0
      goto error;
272
0
    }
273
0
    colr->iccplen = pos;
274
0
    if (!(colr->iccp = jas_malloc(pos))) {
275
0
      jas_logerrorf("memory allocation failed\n");
276
0
      goto error;
277
0
    }
278
0
    jas_stream_rewind(iccstream);
279
0
    if (jas_stream_read(iccstream, colr->iccp, colr->iccplen) !=
280
0
      colr->iccplen) {
281
0
      jas_logerrorf("cannot read temporary stream\n");
282
0
      goto error;
283
0
    }
284
0
    jas_stream_close(iccstream);
285
0
    iccstream = 0;
286
0
    jas_iccprof_destroy(iccprof);
287
0
    iccprof = 0;
288
0
    break;
289
783
  }
290
783
  if (jp2_box_put(box, tmpstream)) {
291
0
    jas_logerrorf("cannot write box\n");
292
0
    goto error;
293
0
  }
294
783
  jp2_box_destroy(box);
295
783
  box = 0;
296
297
783
  needcdef = 1;
298
783
  switch (jas_clrspc_fam(jas_image_clrspc(image))) {
299
198
  case JAS_CLRSPC_FAM_RGB:
300
198
    if (jas_image_numcmpts(image) == 3 &&
301
180
      jas_image_cmpttype(image, 0) ==
302
180
      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R) &&
303
180
      jas_image_cmpttype(image, 1) ==
304
180
      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G) &&
305
180
      jas_image_cmpttype(image, 2) ==
306
180
      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))
307
180
      needcdef = 0;
308
198
    break;
309
0
  case JAS_CLRSPC_FAM_YCBCR:
310
0
    if (jas_image_numcmpts(image) == 3 &&
311
0
      jas_image_cmpttype(image, 0) ==
312
0
      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_Y) &&
313
0
      jas_image_cmpttype(image, 1) ==
314
0
      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CB) &&
315
0
      jas_image_cmpttype(image, 2) ==
316
0
      JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CR))
317
0
      needcdef = 0;
318
0
    break;
319
585
  case JAS_CLRSPC_FAM_GRAY:
320
585
    if (jas_image_numcmpts(image) == 1 &&
321
585
      jas_image_cmpttype(image, 0) ==
322
585
      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y))
323
585
      needcdef = 0;
324
585
    break;
325
0
  default:
326
0
    assert(false);
327
0
    JAS_UNREACHABLE();
328
783
  }
329
330
783
  if (needcdef) {
331
18
    if (!(box = jp2_box_create(JP2_BOX_CDEF))) {
332
0
      jas_logerrorf("cannot create CDEF box\n");
333
0
      goto error;
334
0
    }
335
18
    cdef = &box->data.cdef;
336
18
    cdef->numchans = jas_image_numcmpts(image);
337
18
    cdef->ents = jas_alloc2(cdef->numchans, sizeof(jp2_cdefchan_t));
338
18
    if (!cdef->ents) {
339
0
      goto error;
340
0
    }
341
90
    for (unsigned i = 0; i < jas_image_numcmpts(image); ++i) {
342
72
      cdefchanent = &cdef->ents[i];
343
72
      cdefchanent->channo = i;
344
72
      typeasoc = jp2_gettypeasoc(jas_image_clrspc(image),
345
72
        jas_image_cmpttype(image, i));
346
72
      cdefchanent->type = typeasoc >> 16;
347
72
      cdefchanent->assoc = typeasoc & 0x7fff;
348
72
    }
349
18
    if (jp2_box_put(box, tmpstream)) {
350
0
      jas_logerrorf("cannot write CDEF box\n");
351
0
      goto error;
352
0
    }
353
18
    jp2_box_destroy(box);
354
18
    box = 0;
355
18
  }
356
357
  /* Determine the total length of the JP2 header box. */
358
359
783
  len = jas_stream_tell(tmpstream);
360
783
  jas_stream_rewind(tmpstream);
361
362
  /*
363
   * Output the JP2 header box and all of the boxes which it contains.
364
   */
365
366
783
  if (!(box = jp2_box_create(JP2_BOX_JP2H))) {
367
0
    jas_logerrorf("cannot create JP2H box\n");
368
0
    goto error;
369
0
  }
370
783
  box->len = len + JP2_BOX_HDRLEN(false);
371
783
  if (jp2_box_put(box, out)) {
372
0
    jas_logerrorf("cannot write JP2H box\n");
373
0
    goto error;
374
0
  }
375
783
  jp2_box_destroy(box);
376
783
  box = 0;
377
378
783
  if (jas_stream_copy(out, tmpstream, len)) {
379
0
    jas_logerrorf("cannot copy stream\n");
380
0
    goto error;
381
0
  }
382
383
783
  jas_stream_close(tmpstream);
384
783
  tmpstream = 0;
385
386
  /*
387
   * Output the contiguous code stream box.
388
   */
389
390
783
  if (!(box = jp2_box_create(JP2_BOX_JP2C))) {
391
0
    jas_logerrorf("cannot create JP2C box\n");
392
0
    goto error;
393
0
  }
394
783
  box->len = 0;
395
783
  if (jp2_box_put(box, out)) {
396
0
    jas_logerrorf("cannot write JP2C box\n");
397
0
    goto error;
398
0
  }
399
783
  jp2_box_destroy(box);
400
783
  box = 0;
401
402
  /* Output the JPEG-2000 code stream. */
403
404
783
  overhead = jas_stream_getrwcount(out);
405
783
  sprintf(buf, "%s\n_jp2overhead=%lu\n", (optstr ? optstr : ""),
406
783
    (unsigned long) overhead);
407
408
783
  if (jpc_encode(image, out, buf)) {
409
8
    jas_logerrorf("jpc_encode failed\n");
410
8
    goto error;
411
8
  }
412
413
775
  return 0;
414
415
8
error:
416
417
8
  if (iccprof) {
418
0
    jas_iccprof_destroy(iccprof);
419
0
  }
420
8
  if (iccstream) {
421
0
    jas_stream_close(iccstream);
422
0
  }
423
8
  if (box) {
424
0
    jp2_box_destroy(box);
425
0
  }
426
8
  if (tmpstream) {
427
0
    jas_stream_close(tmpstream);
428
0
  }
429
8
  return -1;
430
783
}
431
432
static uint_fast32_t jp2_gettypeasoc(int colorspace, int ctype)
433
72
{
434
72
  int type;
435
72
  int asoc;
436
437
72
  if (ctype & JAS_IMAGE_CT_OPACITY) {
438
0
    type = JP2_CDEF_TYPE_OPACITY;
439
0
    asoc = JP2_CDEF_ASOC_ALL;
440
0
    goto done;
441
0
  }
442
443
72
  type = JP2_CDEF_TYPE_UNSPEC;
444
72
  asoc = JP2_CDEF_ASOC_NONE;
445
72
  switch (jas_clrspc_fam(colorspace)) {
446
72
  case JAS_CLRSPC_FAM_RGB:
447
72
    switch (JAS_IMAGE_CT_COLOR(ctype)) {
448
36
    case JAS_IMAGE_CT_RGB_R:
449
36
      type = JP2_CDEF_TYPE_COLOR;
450
36
      asoc = JP2_CDEF_RGB_R;
451
36
      break;
452
18
    case JAS_IMAGE_CT_RGB_G:
453
18
      type = JP2_CDEF_TYPE_COLOR;
454
18
      asoc = JP2_CDEF_RGB_G;
455
18
      break;
456
18
    case JAS_IMAGE_CT_RGB_B:
457
18
      type = JP2_CDEF_TYPE_COLOR;
458
18
      asoc = JP2_CDEF_RGB_B;
459
18
      break;
460
72
    }
461
72
    break;
462
72
  case JAS_CLRSPC_FAM_YCBCR:
463
0
    switch (JAS_IMAGE_CT_COLOR(ctype)) {
464
0
    case JAS_IMAGE_CT_YCBCR_Y:
465
0
      type = JP2_CDEF_TYPE_COLOR;
466
0
      asoc = JP2_CDEF_YCBCR_Y;
467
0
      break;
468
0
    case JAS_IMAGE_CT_YCBCR_CB:
469
0
      type = JP2_CDEF_TYPE_COLOR;
470
0
      asoc = JP2_CDEF_YCBCR_CB;
471
0
      break;
472
0
    case JAS_IMAGE_CT_YCBCR_CR:
473
0
      type = JP2_CDEF_TYPE_COLOR;
474
0
      asoc = JP2_CDEF_YCBCR_CR;
475
0
      break;
476
0
    }
477
0
    break;
478
0
  case JAS_CLRSPC_FAM_GRAY:
479
0
    type = JP2_CDEF_TYPE_COLOR;
480
0
    asoc = JP2_CDEF_GRAY_Y;
481
0
    break;
482
72
  }
483
484
72
done:
485
72
  return (type << 16) | asoc;
486
72
}
487
488
static int clrspctojp2(jas_clrspc_t clrspc)
489
783
{
490
783
  switch (clrspc) {
491
198
  case JAS_CLRSPC_SRGB:
492
198
    return JP2_COLR_SRGB;
493
0
  case JAS_CLRSPC_SYCBCR:
494
0
    return JP2_COLR_SYCC;
495
585
  case JAS_CLRSPC_SGRAY:
496
585
    return JP2_COLR_SGRAY;
497
0
  default:
498
0
    assert(false);
499
0
    JAS_UNREACHABLE();
500
783
  }
501
0
  JAS_UNREACHABLE();
502
0
}