Home | History | Annotate | Download | only in libjasper
      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 (at) 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 
     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 
    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 
    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 
    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 
    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 
    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