opencv/3rdparty/libjasper/jp2_enc.c
2012-10-17 15:57:49 +04:00

482 lines
14 KiB
C

/*
* Copyright (c) 1999-2000 Image Power, Inc. and the University of
* British Columbia.
* Copyright (c) 2001-2003 Michael David Adams.
* All rights reserved.
*/
/*
* Modified by Andrey Kiselev <dron@remotesensing.org> to handle UUID
* box properly.
*/
/* __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: jp2_enc.c,v 1.2 2008-05-26 09:40:52 vp153 Exp $
*/
/******************************************************************************\
* Includes.
\******************************************************************************/
#include <assert.h>
#include "jasper/jas_malloc.h"
#include "jasper/jas_image.h"
#include "jasper/jas_stream.h"
#include "jasper/jas_cm.h"
#include "jasper/jas_icc.h"
#include "jp2_cod.h"
static uint_fast32_t jp2_gettypeasoc(int colorspace, int ctype);
static int clrspctojp2(jas_clrspc_t clrspc);
/******************************************************************************\
* Functions.
\******************************************************************************/
int jp2_write_header(jas_image_t *image, jas_stream_t *out)
{
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;
jp2_cdefchan_t *cdefchanent;
jp2_cdef_t *cdef;
int i;
uint_fast32_t typeasoc;
jas_iccprof_t *iccprof;
jas_stream_t *iccstream;
int pos;
int needcdef;
int prec;
int sgnd;
box = 0;
tmpstream = 0;
allcmptssame = 1;
sgnd = jas_image_cmptsgnd(image, 0);
prec = jas_image_cmptprec(image, 0);
for (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))) {
goto error;
}
box->data.jp.magic = JP2_JP_MAGIC;
if (jp2_box_put(box, out)) {
goto error;
}
jp2_box_destroy(box);
box = 0;
/* Output the file type box. */
if (!(box = jp2_box_create(JP2_BOX_FTYP))) {
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)) {
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))) {
goto error;
}
/* Generate image header box. */
if (!(box = jp2_box_create(JP2_BOX_IHDR))) {
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)) {
goto error;
}
jp2_box_destroy(box);
box = 0;
/* Generate bits per component box. */
if (!allcmptssame) {
if (!(box = jp2_box_create(JP2_BOX_BPCC))) {
goto error;
}
bpcc = &box->data.bpcc;
bpcc->numcmpts = jas_image_numcmpts(image);
if (!(bpcc->bpcs = jas_alloc2(bpcc->numcmpts,
sizeof(uint_fast8_t)))) {
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)) {
goto error;
}
jp2_box_destroy(box);
box = 0;
}
/* Generate color specification box. */
if (!(box = jp2_box_create(JP2_BOX_COLR))) {
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;
iccprof = jas_iccprof_createfromcmprof(jas_image_cmprof(image));
assert(iccprof);
iccstream = jas_stream_memopen(0, 0);
assert(iccstream);
if (jas_iccprof_save(iccprof, iccstream))
abort();
if ((pos = jas_stream_tell(iccstream)) < 0)
abort();
colr->iccplen = pos;
colr->iccp = jas_malloc(pos);
assert(colr->iccp);
jas_stream_rewind(iccstream);
if (jas_stream_read(iccstream, colr->iccp, colr->iccplen) != colr->iccplen)
abort();
jas_stream_close(iccstream);
jas_iccprof_destroy(iccprof);
break;
}
if (jp2_box_put(box, tmpstream)) {
goto error;
}
jp2_box_destroy(box);
box = 0;
needcdef = 1;
switch (jas_clrspc_fam(jas_image_clrspc(image))) {
case JAS_CLRSPC_FAM_RGB:
if (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_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_cmpttype(image, 0) ==
JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y))
needcdef = 0;
break;
default:
abort();
break;
}
if (needcdef) {
if (!(box = jp2_box_create(JP2_BOX_CDEF))) {
goto error;
}
cdef = &box->data.cdef;
cdef->numchans = jas_image_numcmpts(image);
cdef->ents = jas_alloc2(cdef->numchans, sizeof(jp2_cdefchan_t));
for (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)) {
goto error;
}
jp2_box_destroy(box);
box = 0;
}
/* 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))) {
goto error;
}
box->len = len + JP2_BOX_HDRLEN(false);
if (jp2_box_put(box, out)) {
goto error;
}
jp2_box_destroy(box);
box = 0;
if (jas_stream_copy(out, tmpstream, len)) {
goto error;
}
jas_stream_close(tmpstream);
tmpstream = 0;
return 0;
abort();
error:
if (box) {
jp2_box_destroy(box);
}
if (tmpstream) {
jas_stream_close(tmpstream);
}
return -1;
}
int jp2_write_codestream(jas_image_t *image, jas_stream_t *out, char *optstr)
{
jp2_box_t *box;
char buf[4096];
uint_fast32_t overhead;
/*
* Output the contiguous code stream box.
*/
if (!(box = jp2_box_create(JP2_BOX_JP2C))) {
goto error;
}
box->len = 0;
if (jp2_box_put(box, out)) {
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)) {
goto error;
}
return 0;
abort();
error:
if (box) {
jp2_box_destroy(box);
}
return -1;
}
int jp2_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
{
if (jp2_write_header(image, out) < 0)
return -1;
if (jp2_write_codestream(image, out, optstr) < 0)
return -1;
return 0;
}
int jp2_encode_uuid(jas_image_t *image, jas_stream_t *out,
char *optstr, jp2_box_t *uuid)
{
if (jp2_write_header(image, out) < 0)
return -1;
if (uuid) {
if (jp2_box_put(uuid, out))
return -1;
}
if (jp2_write_codestream(image, out, optstr) < 0)
return -1;
return 0;
}
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:
abort();
break;
}
}