ref: f7e5af47f117be34669dc1e532d525dcbbff73f0
dir: /jp2_enc.c/
/* * Copyright (c) 1999-2000 Image Power, Inc. and the University of * British Columbia. * Copyright (c) 2001-2003 Michael David Adams. * All rights reserved. */ /* __START_OF_JASPER_LICENSE__ * * JasPer License Version 2.0 * * Copyright (c) 2001-2006 Michael David Adams * Copyright (c) 1999-2000 Image Power, Inc. * Copyright (c) 1999-2000 The University of British Columbia * * All rights reserved. * * Permission is hereby granted, free of charge, to any person (the * "User") obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * 1. The above copyright notices and this permission notice (which * includes the disclaimer below) shall be included in all copies or * substantial portions of the Software. * * 2. The name of a copyright holder shall not be used to endorse or * promote products derived from the Software without specific prior * written permission. * * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. * * __END_OF_JASPER_LICENSE__ */ /* * JP2 Library * * $Id$ */ /******************************************************************************\ * Includes. \******************************************************************************/ #include "jasper/jas_image.h" #include "jasper/jas_malloc.h" #include "jasper/jas_stream.h" #include "jasper/jas_cm.h" #include "jasper/jas_icc.h" #include "jasper/jas_debug.h" #include "jp2_cod.h" /******************************************************************************\ * Function prototypes. \******************************************************************************/ static uint_fast32_t jp2_gettypeasoc(int colorspace, int ctype); static int clrspctojp2(jas_clrspc_t clrspc); /******************************************************************************\ * Functions. \******************************************************************************/ int jp2_encode(jas_image_t *image, jas_stream_t *out, const char *optstr) { jp2_box_t *box; jp2_ftyp_t *ftyp; jp2_ihdr_t *ihdr; jas_stream_t *tmpstream; int allcmptssame; jp2_bpcc_t *bpcc; long len; uint_fast16_t cmptno; jp2_colr_t *colr; char buf[4096]; uint_fast32_t overhead; jp2_cdefchan_t *cdefchanent; jp2_cdef_t *cdef; uint_fast32_t typeasoc; jas_iccprof_t *iccprof; jas_stream_t *iccstream; int pos; int needcdef; box = 0; tmpstream = 0; iccstream = 0; iccprof = 0; if (jas_image_numcmpts(image) < 1) { jas_logerrorf("image must have at least one component\n"); goto error; } allcmptssame = 1; const bool sgnd = jas_image_cmptsgnd(image, 0); const unsigned prec = jas_image_cmptprec(image, 0); for (unsigned i = 1; i < jas_image_numcmpts(image); ++i) { if (jas_image_cmptsgnd(image, i) != sgnd || jas_image_cmptprec(image, i) != prec) { allcmptssame = 0; break; } } /* Output the signature box. */ if (!(box = jp2_box_create(JP2_BOX_JP))) { jas_logerrorf("cannot create JP box\n"); goto error; } box->data.jp.magic = JP2_JP_MAGIC; if (jp2_box_put(box, out)) { jas_logerrorf("cannot write JP box\n"); goto error; } jp2_box_destroy(box); /* Output the file type box. */ if (!(box = jp2_box_create(JP2_BOX_FTYP))) { jas_logerrorf("cannot create FTYP box\n"); goto error; } ftyp = &box->data.ftyp; ftyp->majver = JP2_FTYP_MAJVER; ftyp->minver = JP2_FTYP_MINVER; ftyp->numcompatcodes = 1; ftyp->compatcodes[0] = JP2_FTYP_COMPATCODE; if (jp2_box_put(box, out)) { jas_logerrorf("cannot write FTYP box\n"); goto error; } jp2_box_destroy(box); box = 0; /* * Generate the data portion of the JP2 header box. * We cannot simply output the header for this box * since we do not yet know the correct value for the length * field. */ if (!(tmpstream = jas_stream_memopen(0, 0))) { jas_logerrorf("cannot create temporary stream\n"); goto error; } /* Generate image header box. */ if (!(box = jp2_box_create(JP2_BOX_IHDR))) { jas_logerrorf("cannot create IHDR box\n"); goto error; } ihdr = &box->data.ihdr; ihdr->width = jas_image_width(image); ihdr->height = jas_image_height(image); ihdr->numcmpts = jas_image_numcmpts(image); ihdr->bpc = allcmptssame ? JP2_SPTOBPC(jas_image_cmptsgnd(image, 0), jas_image_cmptprec(image, 0)) : JP2_IHDR_BPCNULL; ihdr->comptype = JP2_IHDR_COMPTYPE; ihdr->csunk = 0; ihdr->ipr = 0; if (jp2_box_put(box, tmpstream)) { jas_logerrorf("cannot write IHDR box\n"); goto error; } jp2_box_destroy(box); /* Generate bits per component box. */ if (!allcmptssame) { if (!(box = jp2_box_create(JP2_BOX_BPCC))) { jas_logerrorf("cannot create BPCC box\n"); goto error; } bpcc = &box->data.bpcc; bpcc->numcmpts = jas_image_numcmpts(image); if (!(bpcc->bpcs = jas_alloc2(bpcc->numcmpts, sizeof(uint_fast8_t)))) { jas_logerrorf("memory allocation failed\n"); goto error; } for (cmptno = 0; cmptno < bpcc->numcmpts; ++cmptno) { bpcc->bpcs[cmptno] = JP2_SPTOBPC(jas_image_cmptsgnd(image, cmptno), jas_image_cmptprec(image, cmptno)); } if (jp2_box_put(box, tmpstream)) { jas_logerrorf("cannot write BPCC box\n"); goto error; } jp2_box_destroy(box); } /* Generate color specification box. */ if (!(box = jp2_box_create(JP2_BOX_COLR))) { jas_logerrorf("cannot create COLR box\n"); goto error; } colr = &box->data.colr; switch (jas_image_clrspc(image)) { case JAS_CLRSPC_SRGB: case JAS_CLRSPC_SYCBCR: case JAS_CLRSPC_SGRAY: colr->method = JP2_COLR_ENUM; colr->csid = clrspctojp2(jas_image_clrspc(image)); colr->pri = JP2_COLR_PRI; colr->approx = 0; break; default: colr->method = JP2_COLR_ICC; colr->pri = JP2_COLR_PRI; colr->approx = 0; /* Ensure that cmprof_ is not null. */ if (!jas_image_cmprof(image)) { jas_logerrorf("CM profile is null\n"); goto error; } if (!(iccprof = jas_iccprof_createfromcmprof( jas_image_cmprof(image)))) { jas_logerrorf("cannot create ICC profile\n"); goto error; } if (!(iccstream = jas_stream_memopen(0, 0))) { jas_logerrorf("cannot create temporary stream\n"); goto error; } if (jas_iccprof_save(iccprof, iccstream)) { jas_logerrorf("cannot write ICC profile\n"); goto error; } if ((pos = jas_stream_tell(iccstream)) < 0) { jas_logerrorf("cannot get stream position\n"); goto error; } colr->iccplen = pos; if (!(colr->iccp = jas_malloc(pos))) { jas_logerrorf("memory allocation failed\n"); goto error; } jas_stream_rewind(iccstream); if (jas_stream_read(iccstream, colr->iccp, colr->iccplen) != colr->iccplen) { jas_logerrorf("cannot read temporary stream\n"); goto error; } jas_stream_close(iccstream); iccstream = 0; jas_iccprof_destroy(iccprof); iccprof = 0; break; } if (jp2_box_put(box, tmpstream)) { jas_logerrorf("cannot write box\n"); goto error; } jp2_box_destroy(box); needcdef = 1; switch (jas_clrspc_fam(jas_image_clrspc(image))) { case JAS_CLRSPC_FAM_RGB: if (jas_image_numcmpts(image) >= 3 && jas_image_cmpttype(image, 0) == JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R) && jas_image_cmpttype(image, 1) == JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G) && jas_image_cmpttype(image, 2) == JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)) needcdef = 0; break; case JAS_CLRSPC_FAM_YCBCR: if (jas_image_numcmpts(image) >= 3 && jas_image_cmpttype(image, 0) == JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_Y) && jas_image_cmpttype(image, 1) == JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CB) && jas_image_cmpttype(image, 2) == JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CR)) needcdef = 0; break; case JAS_CLRSPC_FAM_GRAY: if (jas_image_numcmpts(image) >= 1 && jas_image_cmpttype(image, 0) == JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y)) needcdef = 0; break; default: assert(false); JAS_UNREACHABLE(); } if (needcdef) { if (!(box = jp2_box_create(JP2_BOX_CDEF))) { jas_logerrorf("cannot create CDEF box\n"); goto error; } cdef = &box->data.cdef; cdef->numchans = jas_image_numcmpts(image); cdef->ents = jas_alloc2(cdef->numchans, sizeof(jp2_cdefchan_t)); if (!cdef->ents) { goto error; } for (unsigned i = 0; i < jas_image_numcmpts(image); ++i) { cdefchanent = &cdef->ents[i]; cdefchanent->channo = i; typeasoc = jp2_gettypeasoc(jas_image_clrspc(image), jas_image_cmpttype(image, i)); cdefchanent->type = typeasoc >> 16; cdefchanent->assoc = typeasoc & 0x7fff; } if (jp2_box_put(box, tmpstream)) { jas_logerrorf("cannot write CDEF box\n"); goto error; } jp2_box_destroy(box); } /* Determine the total length of the JP2 header box. */ len = jas_stream_tell(tmpstream); jas_stream_rewind(tmpstream); /* * Output the JP2 header box and all of the boxes which it contains. */ if (!(box = jp2_box_create(JP2_BOX_JP2H))) { jas_logerrorf("cannot create JP2H box\n"); goto error; } box->len = len + JP2_BOX_HDRLEN(false); if (jp2_box_put(box, out)) { jas_logerrorf("cannot write JP2H box\n"); goto error; } jp2_box_destroy(box); box = 0; if (jas_stream_copy(out, tmpstream, len)) { jas_logerrorf("cannot copy stream\n"); goto error; } jas_stream_close(tmpstream); tmpstream = 0; /* * Output the contiguous code stream box. */ if (!(box = jp2_box_create(JP2_BOX_JP2C))) { jas_logerrorf("cannot create JP2C box\n"); goto error; } box->len = 0; if (jp2_box_put(box, out)) { jas_logerrorf("cannot write JP2C box\n"); goto error; } jp2_box_destroy(box); box = 0; /* Output the JPEG-2000 code stream. */ overhead = jas_stream_getrwcount(out); sprintf(buf, "%s\n_jp2overhead=%lu\n", (optstr ? optstr : ""), (unsigned long) overhead); if (jpc_encode(image, out, buf)) { jas_logerrorf("jpc_encode failed\n"); goto error; } return 0; error: if (iccprof) { jas_iccprof_destroy(iccprof); } if (iccstream) { jas_stream_close(iccstream); } if (box) { jp2_box_destroy(box); } if (tmpstream) { jas_stream_close(tmpstream); } return -1; } static uint_fast32_t jp2_gettypeasoc(int colorspace, int ctype) { int type; int asoc; if (ctype & JAS_IMAGE_CT_OPACITY) { type = JP2_CDEF_TYPE_OPACITY; asoc = JP2_CDEF_ASOC_ALL; goto done; } type = JP2_CDEF_TYPE_UNSPEC; asoc = JP2_CDEF_ASOC_NONE; switch (jas_clrspc_fam(colorspace)) { case JAS_CLRSPC_FAM_RGB: switch (JAS_IMAGE_CT_COLOR(ctype)) { case JAS_IMAGE_CT_RGB_R: type = JP2_CDEF_TYPE_COLOR; asoc = JP2_CDEF_RGB_R; break; case JAS_IMAGE_CT_RGB_G: type = JP2_CDEF_TYPE_COLOR; asoc = JP2_CDEF_RGB_G; break; case JAS_IMAGE_CT_RGB_B: type = JP2_CDEF_TYPE_COLOR; asoc = JP2_CDEF_RGB_B; break; } break; case JAS_CLRSPC_FAM_YCBCR: switch (JAS_IMAGE_CT_COLOR(ctype)) { case JAS_IMAGE_CT_YCBCR_Y: type = JP2_CDEF_TYPE_COLOR; asoc = JP2_CDEF_YCBCR_Y; break; case JAS_IMAGE_CT_YCBCR_CB: type = JP2_CDEF_TYPE_COLOR; asoc = JP2_CDEF_YCBCR_CB; break; case JAS_IMAGE_CT_YCBCR_CR: type = JP2_CDEF_TYPE_COLOR; asoc = JP2_CDEF_YCBCR_CR; break; } break; case JAS_CLRSPC_FAM_GRAY: type = JP2_CDEF_TYPE_COLOR; asoc = JP2_CDEF_GRAY_Y; break; } done: return (type << 16) | asoc; } static int clrspctojp2(jas_clrspc_t clrspc) { switch (clrspc) { case JAS_CLRSPC_SRGB: return JP2_COLR_SRGB; case JAS_CLRSPC_SYCBCR: return JP2_COLR_SYCC; case JAS_CLRSPC_SGRAY: return JP2_COLR_SGRAY; default: assert(false); JAS_UNREACHABLE(); } JAS_UNREACHABLE(); return -1; }