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