diff options
author | scuri <scuri> | 2008-10-17 06:10:15 +0000 |
---|---|---|
committer | scuri <scuri> | 2008-10-17 06:10:15 +0000 |
commit | 5a422aba704c375a307a902bafe658342e209906 (patch) | |
tree | 5005011e086bb863d8fb587ad3319bbec59b2447 /src/libjasper/jp2 |
First commit - moving from LuaForge to SourceForge
Diffstat (limited to 'src/libjasper/jp2')
-rw-r--r-- | src/libjasper/jp2/jp2_cod.c | 980 | ||||
-rw-r--r-- | src/libjasper/jp2/jp2_cod.h | 328 | ||||
-rw-r--r-- | src/libjasper/jp2/jp2_dec.c | 702 | ||||
-rw-r--r-- | src/libjasper/jp2/jp2_dec.h | 85 | ||||
-rw-r--r-- | src/libjasper/jp2/jp2_enc.c | 469 |
5 files changed, 2564 insertions, 0 deletions
diff --git a/src/libjasper/jp2/jp2_cod.c b/src/libjasper/jp2/jp2_cod.c new file mode 100644 index 0000000..81b01ce --- /dev/null +++ b/src/libjasper/jp2/jp2_cod.c @@ -0,0 +1,980 @@ +/* + * Copyright (c) 1999-2000 Image Power, Inc. and the University of + * British Columbia. + * Copyright (c) 2001-2002 Michael David Adams. + * All rights reserved. + + GeoJasper revision: Dima (11/07/2003 17:29 - UUID from j_image_t) + Modifications 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_cod.c,v 1.1 2008/10/17 06:14:59 scuri Exp $ + */ + +/******************************************************************************\ +* Includes. +\******************************************************************************/ + +#include <assert.h> +#include <stdlib.h> + +#include "jasper/jas_stream.h" +#include "jasper/jas_malloc.h" +#include "jasper/jas_debug.h" + +#include "jp2_cod.h" + +/******************************************************************************\ +* Function prototypes. +\******************************************************************************/ + +#define ONES(n) ((1 << (n)) - 1) + +jp2_boxinfo_t *jp2_boxinfolookup(int type); + +static int jp2_getuint8(jas_stream_t *in, uint_fast8_t *val); +static int jp2_getuint16(jas_stream_t *in, uint_fast16_t *val); +static int jp2_getuint32(jas_stream_t *in, uint_fast32_t *val); +static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val); +static int jp2_putuint8(jas_stream_t *out, uint_fast8_t val); +static int jp2_putuint16(jas_stream_t *out, uint_fast16_t val); +static int jp2_putuint32(jas_stream_t *out, uint_fast32_t val); +static int jp2_putuint64(jas_stream_t *out, uint_fast64_t val); + +static int jp2_getint(jas_stream_t *in, int s, int n, int_fast32_t *val); + +jp2_box_t *jp2_box_get(jas_stream_t *in); +void jp2_box_dump(jp2_box_t *box, FILE *out); + +static int jp2_jp_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_jp_putdata(jp2_box_t *box, jas_stream_t *out); +static int jp2_ftyp_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_ftyp_putdata(jp2_box_t *box, jas_stream_t *out); +static int jp2_ihdr_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_ihdr_putdata(jp2_box_t *box, jas_stream_t *out); +static void jp2_bpcc_destroy(jp2_box_t *box); +static int jp2_bpcc_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_bpcc_putdata(jp2_box_t *box, jas_stream_t *out); +static int jp2_colr_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_colr_putdata(jp2_box_t *box, jas_stream_t *out); +static void jp2_colr_dumpdata(jp2_box_t *box, FILE *out); +static void jp2_colr_destroy(jp2_box_t *box); +static void jp2_cdef_destroy(jp2_box_t *box); +static int jp2_cdef_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_cdef_putdata(jp2_box_t *box, jas_stream_t *out); +static void jp2_cdef_dumpdata(jp2_box_t *box, FILE *out); +static void jp2_cmap_destroy(jp2_box_t *box); +static int jp2_cmap_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_cmap_putdata(jp2_box_t *box, jas_stream_t *out); +static void jp2_cmap_dumpdata(jp2_box_t *box, FILE *out); +static void jp2_pclr_destroy(jp2_box_t *box); +static int jp2_pclr_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_pclr_putdata(jp2_box_t *box, jas_stream_t *out); +static void jp2_pclr_dumpdata(jp2_box_t *box, FILE *out); +// GeoJasper: dima - uuid +static void jp2_uuid_destroy(jp2_box_t *box); +static int jp2_uuid_getdata(jp2_box_t *box, jas_stream_t *in); +static int jp2_uuid_putdata(jp2_box_t *box, jas_stream_t *out); + + +/******************************************************************************\ +* Local data. +\******************************************************************************/ + +jp2_boxinfo_t jp2_boxinfos[] = { + {JP2_BOX_JP, "JP", 0, + {0, 0, jp2_jp_getdata, jp2_jp_putdata, 0}}, + {JP2_BOX_FTYP, "FTYP", 0, + {0, 0, jp2_ftyp_getdata, jp2_ftyp_putdata, 0}}, + {JP2_BOX_JP2H, "JP2H", JP2_BOX_SUPER, + {0, 0, 0, 0, 0}}, + {JP2_BOX_IHDR, "IHDR", 0, + {0, 0, jp2_ihdr_getdata, jp2_ihdr_putdata, 0}}, + {JP2_BOX_BPCC, "BPCC", 0, + {0, jp2_bpcc_destroy, jp2_bpcc_getdata, jp2_bpcc_putdata, 0}}, + {JP2_BOX_COLR, "COLR", 0, + {0, jp2_colr_destroy, jp2_colr_getdata, jp2_colr_putdata, jp2_colr_dumpdata}}, + {JP2_BOX_PCLR, "PCLR", 0, + {0, jp2_pclr_destroy, jp2_pclr_getdata, jp2_pclr_putdata, jp2_pclr_dumpdata}}, + {JP2_BOX_CMAP, "CMAP", 0, + {0, jp2_cmap_destroy, jp2_cmap_getdata, jp2_cmap_putdata, jp2_cmap_dumpdata}}, + {JP2_BOX_CDEF, "CDEF", 0, + {0, jp2_cdef_destroy, jp2_cdef_getdata, jp2_cdef_putdata, jp2_cdef_dumpdata}}, + {JP2_BOX_RES, "RES", JP2_BOX_SUPER, + {0, 0, 0, 0, 0}}, + {JP2_BOX_RESC, "RESC", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_RESD, "RESD", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_JP2C, "JP2C", JP2_BOX_NODATA, + {0, 0, 0, 0, 0}}, + {JP2_BOX_JP2I, "JP2I", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_XML, "XML", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_UUID, "UUID", 0, + //{0, 0, 0, 0, 0}}, + {0, jp2_uuid_destroy, jp2_uuid_getdata, jp2_uuid_putdata, 0}}, // GeoJasper: dima - uuid + {JP2_BOX_UINF, "UINF", JP2_BOX_SUPER, + {0, 0, 0, 0, 0}}, + {JP2_BOX_ULST, "ULST", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_URL, "URL", 0, + {0, 0, 0, 0, 0}}, + {0, 0, 0, {0, 0, 0, 0, 0}}, +}; + +jp2_boxinfo_t jp2_boxinfo_unk = { + 0, "Unknown", 0, {0, 0, 0, 0, 0} +}; + +/******************************************************************************\ +* Box constructor. +\******************************************************************************/ + +jp2_box_t *jp2_box_create(int type) +{ + jp2_box_t *box; + jp2_boxinfo_t *boxinfo; + + if (!(box = jas_malloc(sizeof(jp2_box_t)))) { + return 0; + } + memset(box, 0, sizeof(jp2_box_t)); + box->type = type; + box->len = 0; + if (!(boxinfo = jp2_boxinfolookup(type))) { + return 0; + } + box->info = boxinfo; + box->ops = &boxinfo->ops; + return box; +} + +/******************************************************************************\ +* Box destructor. +\******************************************************************************/ + +void jp2_box_destroy(jp2_box_t *box) +{ + if (box->ops->destroy) { + (*box->ops->destroy)(box); + } + jas_free(box); +} + +static void jp2_bpcc_destroy(jp2_box_t *box) +{ + jp2_bpcc_t *bpcc = &box->data.bpcc; + if (bpcc->bpcs) { + jas_free(bpcc->bpcs); + bpcc->bpcs = 0; + } +} + +static void jp2_cdef_destroy(jp2_box_t *box) +{ + jp2_cdef_t *cdef = &box->data.cdef; + if (cdef->ents) { + jas_free(cdef->ents); + cdef->ents = 0; + } +} + +/******************************************************************************\ +* Box input. +\******************************************************************************/ + +jp2_box_t *jp2_box_get(jas_stream_t *in) +{ + jp2_box_t *box; + jp2_boxinfo_t *boxinfo; + jas_stream_t *tmpstream; + uint_fast32_t len; + uint_fast64_t extlen; + bool dataflag; + + box = 0; + tmpstream = 0; + + if (!(box = jas_malloc(sizeof(jp2_box_t)))) { + goto error; + } + box->ops = &jp2_boxinfo_unk.ops; + if (jp2_getuint32(in, &len) || jp2_getuint32(in, &box->type)) { + goto error; + } + boxinfo = jp2_boxinfolookup(box->type); + box->info = boxinfo; + box->ops = &boxinfo->ops; + box->len = len; + if (box->len == 1) { + if (jp2_getuint64(in, &extlen)) { + goto error; + } + if (extlen > 0xffffffffUL) { + jas_eprintf("warning: cannot handle large 64-bit box length\n"); + extlen = 0xffffffffUL; + } + box->len = extlen; + box->datalen = extlen - JP2_BOX_HDRLEN(true); + } else { + box->datalen = box->len - JP2_BOX_HDRLEN(false); + } + if (box->len != 0 && box->len < 8) { + goto error; + } + + dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA)); + + if (dataflag) { + if (!(tmpstream = jas_stream_memopen(0, 0))) { + goto error; + } + if (jas_stream_copy(tmpstream, in, box->datalen)) { + jas_eprintf("cannot copy box data\n"); + goto error; + } + jas_stream_rewind(tmpstream); + + if (box->ops->getdata) { + if ((*box->ops->getdata)(box, tmpstream)) { + jas_eprintf("cannot parse box data\n"); + goto error; + } + } + jas_stream_close(tmpstream); + } + + if (jas_getdbglevel() >= 1) { + jp2_box_dump(box, stderr); + } + + return box; + abort(); + +error: + if (box) { + jp2_box_destroy(box); + } + if (tmpstream) { + jas_stream_close(tmpstream); + } + return 0; +} + +void jp2_box_dump(jp2_box_t *box, FILE *out) +{ + jp2_boxinfo_t *boxinfo; + boxinfo = jp2_boxinfolookup(box->type); + assert(boxinfo); + + fprintf(out, "JP2 box: "); + fprintf(out, "type=%c%s%c (0x%08x); length=%d\n", '"', boxinfo->name, + '"', box->type, box->len); + if (box->ops->dumpdata) { + (*box->ops->dumpdata)(box, out); + } +} + +static int jp2_jp_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_jp_t *jp = &box->data.jp; + if (jp2_getuint32(in, &jp->magic)) { + return -1; + } + return 0; +} + +static int jp2_ftyp_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_ftyp_t *ftyp = &box->data.ftyp; + unsigned int i; + if (jp2_getuint32(in, &ftyp->majver) || jp2_getuint32(in, &ftyp->minver)) { + return -1; + } + ftyp->numcompatcodes = (box->datalen - 8) / 4; + if (ftyp->numcompatcodes > JP2_FTYP_MAXCOMPATCODES) { + return -1; + } + for (i = 0; i < ftyp->numcompatcodes; ++i) { + if (jp2_getuint32(in, &ftyp->compatcodes[i])) { + return -1; + } + } + return 0; +} + +static int jp2_ihdr_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_ihdr_t *ihdr = &box->data.ihdr; + if (jp2_getuint32(in, &ihdr->height) || jp2_getuint32(in, &ihdr->width) || + jp2_getuint16(in, &ihdr->numcmpts) || jp2_getuint8(in, &ihdr->bpc) || + jp2_getuint8(in, &ihdr->comptype) || jp2_getuint8(in, &ihdr->csunk) || + jp2_getuint8(in, &ihdr->ipr)) { + return -1; + } + return 0; +} + +static int jp2_bpcc_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_bpcc_t *bpcc = &box->data.bpcc; + unsigned int i; + bpcc->numcmpts = box->datalen; + if (!(bpcc->bpcs = jas_malloc(bpcc->numcmpts * sizeof(uint_fast8_t)))) { + return -1; + } + for (i = 0; i < bpcc->numcmpts; ++i) { + if (jp2_getuint8(in, &bpcc->bpcs[i])) { + return -1; + } + } + return 0; +} + +static void jp2_colr_dumpdata(jp2_box_t *box, FILE *out) +{ + jp2_colr_t *colr = &box->data.colr; + fprintf(out, "method=%d; pri=%d; approx=%d\n", (int)colr->method, (int)colr->pri, (int)colr->approx); + switch (colr->method) { + case JP2_COLR_ENUM: + fprintf(out, "csid=%d\n", (int)colr->csid); + break; + case JP2_COLR_ICC: + jas_memdump(out, colr->iccp, colr->iccplen); + break; + } +} + +static int jp2_colr_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_colr_t *colr = &box->data.colr; + colr->csid = 0; + colr->iccp = 0; + colr->iccplen = 0; + + if (jp2_getuint8(in, &colr->method) || jp2_getuint8(in, &colr->pri) || + jp2_getuint8(in, &colr->approx)) { + return -1; + } + switch (colr->method) { + case JP2_COLR_ENUM: + if (jp2_getuint32(in, &colr->csid)) { + return -1; + } + break; + case JP2_COLR_ICC: + colr->iccplen = box->datalen - 3; + if (!(colr->iccp = jas_malloc(colr->iccplen * sizeof(uint_fast8_t)))) { + return -1; + } + if (jas_stream_read(in, colr->iccp, colr->iccplen) != colr->iccplen) { + return -1; + } + break; + } + return 0; +} + +static void jp2_cdef_dumpdata(jp2_box_t *box, FILE *out) +{ + jp2_cdef_t *cdef = &box->data.cdef; + unsigned int i; + for (i = 0; i < cdef->numchans; ++i) { + fprintf(out, "channo=%d; type=%d; assoc=%d\n", + cdef->ents[i].channo, cdef->ents[i].type, cdef->ents[i].assoc); + } +} + +static void jp2_colr_destroy(jp2_box_t *box) +{ + jp2_colr_t *colr = &box->data.colr; + if (colr->iccp) { + jas_free(colr->iccp); + } +} + +static int jp2_cdef_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_cdef_t *cdef = &box->data.cdef; + jp2_cdefchan_t *chan; + unsigned int channo; + if (jp2_getuint16(in, &cdef->numchans)) { + return -1; + } + if (!(cdef->ents = jas_malloc(cdef->numchans * sizeof(jp2_cdefchan_t)))) { + return -1; + } + for (channo = 0; channo < cdef->numchans; ++channo) { + chan = &cdef->ents[channo]; + if (jp2_getuint16(in, &chan->channo) || jp2_getuint16(in, &chan->type) || + jp2_getuint16(in, &chan->assoc)) { + return -1; + } + } + return 0; +} + +/******************************************************************************\ +* Box output. +\******************************************************************************/ + +int jp2_box_put(jp2_box_t *box, jas_stream_t *out) +{ + jas_stream_t *tmpstream; + bool extlen; + bool dataflag; + + tmpstream = 0; + + dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA)); + + if (dataflag) { + tmpstream = jas_stream_memopen(0, 0); + if (box->ops->putdata) { + if ((*box->ops->putdata)(box, tmpstream)) { + goto error; + } + } + box->len = jas_stream_tell(tmpstream) + JP2_BOX_HDRLEN(false); + jas_stream_rewind(tmpstream); + } + extlen = (box->len >= (((uint_fast64_t)1) << 32)) != 0; + if (jp2_putuint32(out, extlen ? 1 : box->len)) { + goto error; + } + if (jp2_putuint32(out, box->type)) { + goto error; + } + if (extlen) { + if (jp2_putuint64(out, box->len)) { + goto error; + } + } + + if (dataflag) { + if (jas_stream_copy(out, tmpstream, box->len - JP2_BOX_HDRLEN(false))) { + goto error; + } + jas_stream_close(tmpstream); + } + + return 0; + abort(); + +error: + + if (tmpstream) { + jas_stream_close(tmpstream); + } + return -1; +} + +static int jp2_jp_putdata(jp2_box_t *box, jas_stream_t *out) +{ + jp2_jp_t *jp = &box->data.jp; + if (jp2_putuint32(out, jp->magic)) { + return -1; + } + return 0; +} + +static int jp2_ftyp_putdata(jp2_box_t *box, jas_stream_t *out) +{ + jp2_ftyp_t *ftyp = &box->data.ftyp; + unsigned int i; + if (jp2_putuint32(out, ftyp->majver) || jp2_putuint32(out, ftyp->minver)) { + return -1; + } + for (i = 0; i < ftyp->numcompatcodes; ++i) { + if (jp2_putuint32(out, ftyp->compatcodes[i])) { + return -1; + } + } + return 0; +} + +static int jp2_ihdr_putdata(jp2_box_t *box, jas_stream_t *out) +{ + jp2_ihdr_t *ihdr = &box->data.ihdr; + if (jp2_putuint32(out, ihdr->height) || jp2_putuint32(out, ihdr->width) || + jp2_putuint16(out, ihdr->numcmpts) || jp2_putuint8(out, ihdr->bpc) || + jp2_putuint8(out, ihdr->comptype) || jp2_putuint8(out, ihdr->csunk) || + jp2_putuint8(out, ihdr->ipr)) { + return -1; + } + return 0; +} + +static int jp2_bpcc_putdata(jp2_box_t *box, jas_stream_t *out) +{ + jp2_bpcc_t *bpcc = &box->data.bpcc; + unsigned int i; + for (i = 0; i < bpcc->numcmpts; ++i) { + if (jp2_putuint8(out, bpcc->bpcs[i])) { + return -1; + } + } + return 0; +} + +static int jp2_colr_putdata(jp2_box_t *box, jas_stream_t *out) +{ + jp2_colr_t *colr = &box->data.colr; + if (jp2_putuint8(out, colr->method) || jp2_putuint8(out, colr->pri) || + jp2_putuint8(out, colr->approx)) { + return -1; + } + switch (colr->method) { + case JP2_COLR_ENUM: + if (jp2_putuint32(out, colr->csid)) { + return -1; + } + break; + case JP2_COLR_ICC: + if (jas_stream_write(out, colr->iccp, + JAS_CAST(int, colr->iccplen)) != JAS_CAST(int, colr->iccplen)) + return -1; + break; + } + return 0; +} + +static int jp2_cdef_putdata(jp2_box_t *box, jas_stream_t *out) +{ + jp2_cdef_t *cdef = &box->data.cdef; + unsigned int i; + jp2_cdefchan_t *ent; + + if (jp2_putuint16(out, cdef->numchans)) { + return -1; + } + + for (i = 0; i < cdef->numchans; ++i) { + ent = &cdef->ents[i]; + if (jp2_putuint16(out, ent->channo) || + jp2_putuint16(out, ent->type) || + jp2_putuint16(out, ent->assoc)) { + return -1; + } + } + return 0; +} + +/******************************************************************************\ +* Input operations for primitive types. +\******************************************************************************/ + +static int jp2_getuint8(jas_stream_t *in, uint_fast8_t *val) +{ + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + if (val) { + *val = c; + } + return 0; +} + +static int jp2_getuint16(jas_stream_t *in, uint_fast16_t *val) +{ + uint_fast16_t v; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if (val) { + *val = v; + } + return 0; +} + +static int jp2_getuint32(jas_stream_t *in, uint_fast32_t *val) +{ + uint_fast32_t v; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if (val) { + *val = v; + } + return 0; +} + +static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val) +{ + uint_fast64_t tmpval; + int i; + int c; + + tmpval = 0; + for (i = 0; i < 8; ++i) { + tmpval <<= 8; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + tmpval |= (c & 0xff); + } + *val = tmpval; + + return 0; +} + +/******************************************************************************\ +* Output operations for primitive types. +\******************************************************************************/ + +static int jp2_putuint8(jas_stream_t *out, uint_fast8_t val) +{ + if (jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; +} + +static int jp2_putuint16(jas_stream_t *out, uint_fast16_t val) +{ + if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF || + jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; +} + +static int jp2_putuint32(jas_stream_t *out, uint_fast32_t val) +{ + if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF || + jas_stream_putc(out, (val >> 16) & 0xff) == EOF || + jas_stream_putc(out, (val >> 8) & 0xff) == EOF || + jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; +} + +static int jp2_putuint64(jas_stream_t *out, uint_fast64_t val) +{ + if (jp2_putuint32(out, (val >> 32) & 0xffffffffUL) || + jp2_putuint32(out, val & 0xffffffffUL)) { + return -1; + } + return 0; +} + +/******************************************************************************\ +* Miscellaneous code. +\******************************************************************************/ + +jp2_boxinfo_t *jp2_boxinfolookup(int type) +{ + jp2_boxinfo_t *boxinfo; + for (boxinfo = jp2_boxinfos; boxinfo->name; ++boxinfo) { + if (boxinfo->type == type) { + return boxinfo; + } + } + return &jp2_boxinfo_unk; +} + + + + + +static void jp2_cmap_destroy(jp2_box_t *box) +{ + jp2_cmap_t *cmap = &box->data.cmap; + if (cmap->ents) { + jas_free(cmap->ents); + } +} + +static int jp2_cmap_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_cmap_t *cmap = &box->data.cmap; + jp2_cmapent_t *ent; + unsigned int i; + + cmap->numchans = (box->datalen) / 4; + if (!(cmap->ents = jas_malloc(cmap->numchans * sizeof(jp2_cmapent_t)))) { + return -1; + } + for (i = 0; i < cmap->numchans; ++i) { + ent = &cmap->ents[i]; + if (jp2_getuint16(in, &ent->cmptno) || + jp2_getuint8(in, &ent->map) || + jp2_getuint8(in, &ent->pcol)) { + return -1; + } + } + + return 0; +} + +static int jp2_cmap_putdata(jp2_box_t *box, jas_stream_t *out) +{ + /* Eliminate compiler warning about unused variables. */ + box = 0; + out = 0; + + return -1; +} + +static void jp2_cmap_dumpdata(jp2_box_t *box, FILE *out) +{ + jp2_cmap_t *cmap = &box->data.cmap; + unsigned int i; + jp2_cmapent_t *ent; + fprintf(out, "numchans = %d\n", (int) cmap->numchans); + for (i = 0; i < cmap->numchans; ++i) { + ent = &cmap->ents[i]; + fprintf(out, "cmptno=%d; map=%d; pcol=%d\n", + (int) ent->cmptno, (int) ent->map, (int) ent->pcol); + } +} + +static void jp2_pclr_destroy(jp2_box_t *box) +{ + jp2_pclr_t *pclr = &box->data.pclr; + if (pclr->lutdata) { + jas_free(pclr->lutdata); + } + if (pclr->bpc) + jas_free(pclr->bpc); +} + +static int jp2_pclr_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_pclr_t *pclr = &box->data.pclr; + int lutsize; + unsigned int i; + unsigned int j; + int_fast32_t x; + + pclr->lutdata = 0; + + if (jp2_getuint16(in, &pclr->numlutents) || + jp2_getuint8(in, &pclr->numchans)) { + return -1; + } + lutsize = pclr->numlutents * pclr->numchans; + if (!(pclr->lutdata = jas_malloc(lutsize * sizeof(int_fast32_t)))) { + return -1; + } + if (!(pclr->bpc = jas_malloc(pclr->numchans * sizeof(uint_fast8_t)))) { + return -1; + } + for (i = 0; i < pclr->numchans; ++i) { + if (jp2_getuint8(in, &pclr->bpc[i])) { + return -1; + } + } + for (i = 0; i < pclr->numlutents; ++i) { + for (j = 0; j < pclr->numchans; ++j) { + if (jp2_getint(in, (pclr->bpc[j] & 0x80) != 0, + (pclr->bpc[j] & 0x7f) + 1, &x)) { + return -1; + } + pclr->lutdata[i * pclr->numchans + j] = x; + } + } + return 0; +} + +static int jp2_pclr_putdata(jp2_box_t *box, jas_stream_t *out) +{ +#if 0 + jp2_pclr_t *pclr = &box->data.pclr; +#endif +/* Eliminate warning about unused variable. */ +box = 0; +out = 0; + return -1; +} + +static void jp2_pclr_dumpdata(jp2_box_t *box, FILE *out) +{ + jp2_pclr_t *pclr = &box->data.pclr; + unsigned int i; + int j; + fprintf(out, "numents=%d; numchans=%d\n", (int) pclr->numlutents, + (int) pclr->numchans); + for (i = 0; i < pclr->numlutents; ++i) { + for (j = 0; j < pclr->numchans; ++j) { + fprintf(out, "LUT[%d][%d]=%d\n", i, j, pclr->lutdata[i * pclr->numchans + j]); + } + } +} + +static void jp2_uuid_destroy(jp2_box_t *box) +{ + jp2_uuid_t *uuid = &box->data.uuid; + if (uuid->data) + { + jas_free(uuid->data); + uuid->data = NULL; + } +} + +static int jp2_uuid_getdata(jp2_box_t *box, jas_stream_t *in) +{ + jp2_uuid_t *uuid = &box->data.uuid; + int i; + + for (i = 0; i < 16; i++) + { + if (jp2_getuint8(in, &uuid->uuid[i])) + return -1; + } + + uuid->data_len = box->datalen - 16; + uuid->data = jas_malloc(uuid->data_len * sizeof(uint_fast8_t)); + for (i = 0; i < uuid->data_len; i++) + { + if (jp2_getuint8(in, &uuid->data[i])) + return -1; + } + return 0; +} + +static int jp2_uuid_putdata(jp2_box_t *box, jas_stream_t *out) +{ + jp2_uuid_t *uuid = &box->data.uuid; + int i; + + for (i = 0; i < 16; i++) + { + if (jp2_putuint8(out, uuid->uuid[i])) + return -1; + } + + for (i = 0; i < uuid->data_len; i++) + { + if (jp2_putuint8(out, uuid->data[i])) + return -1; + } + return 0; +} + +static int jp2_getint(jas_stream_t *in, int s, int n, int_fast32_t *val) +{ + int c; + int i; + uint_fast32_t v; + int m; + + m = (n + 7) / 8; + + v = 0; + for (i = 0; i < m; ++i) { + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + } + v &= ONES(n); + if (s) { + int sb; + sb = v & (1 << (8 * m - 1)); + *val = ((~v) + 1) & ONES(8 * m); + if (sb) { + *val = -*val; + } + } else { + *val = v; + } + + return 0; +} + +jp2_cdefchan_t *jp2_cdef_lookup(jp2_cdef_t *cdef, int channo) +{ + unsigned int i; + jp2_cdefchan_t *cdefent; + for (i = 0; i < cdef->numchans; ++i) { + cdefent = &cdef->ents[i]; + if (cdefent->channo == JAS_CAST(unsigned int, channo)) { + return cdefent; + } + } + return 0; +} diff --git a/src/libjasper/jp2/jp2_cod.h b/src/libjasper/jp2/jp2_cod.h new file mode 100644 index 0000000..5bad06f --- /dev/null +++ b/src/libjasper/jp2/jp2_cod.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 1999-2000 Image Power, Inc. and the University of + * British Columbia. + * Copyright (c) 2001-2002 Michael David Adams. + * All rights reserved. + + GeoJasper revision: Dima (11/07/2003 17:29 - UUID from j_image_t) + Modifications 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_cod.h,v 1.1 2008/10/17 06:14:59 scuri Exp $ + */ + +#ifndef JP2_COD_H +#define JP2_COD_H + +/******************************************************************************\ +* Includes. +\******************************************************************************/ + +#include "jasper/jas_types.h" + +/******************************************************************************\ +* Macros. +\******************************************************************************/ + +#define JP2_SPTOBPC(s, p) \ + ((((p) - 1) & 0x7f) | (((s) & 1) << 7)) + +/******************************************************************************\ +* Box class. +\******************************************************************************/ + +#define JP2_BOX_HDRLEN(ext) ((ext) ? 16 : 8) + +/* Box types. */ +#define JP2_BOX_JP 0x6a502020 /* Signature */ +#define JP2_BOX_FTYP 0x66747970 /* File Type */ +#define JP2_BOX_JP2H 0x6a703268 /* JP2 Header */ +#define JP2_BOX_IHDR 0x69686472 /* Image Header */ +#define JP2_BOX_BPCC 0x62706363 /* Bits Per Component */ +#define JP2_BOX_COLR 0x636f6c72 /* Color Specification */ +#define JP2_BOX_PCLR 0x70636c72 /* Palette */ +#define JP2_BOX_CMAP 0x636d6170 /* Component Mapping */ +#define JP2_BOX_CDEF 0x63646566 /* Channel Definition */ +#define JP2_BOX_RES 0x72657320 /* Resolution */ +#define JP2_BOX_RESC 0x72657363 /* Capture Resolution */ +#define JP2_BOX_RESD 0x72657364 /* Default Display Resolution */ +#define JP2_BOX_JP2C 0x6a703263 /* Contiguous Code Stream */ +#define JP2_BOX_JP2I 0x6a703269 /* Intellectual Property */ +#define JP2_BOX_XML 0x786d6c20 /* XML */ +#define JP2_BOX_UUID 0x75756964 /* UUID */ +#define JP2_BOX_UINF 0x75696e66 /* UUID Info */ +#define JP2_BOX_ULST 0x75637374 /* UUID List */ +#define JP2_BOX_URL 0x75726c20 /* URL */ + +#define JP2_BOX_SUPER 0x01 +#define JP2_BOX_NODATA 0x02 + +/* JP box data. */ + +#define JP2_JP_MAGIC 0x0d0a870a +#define JP2_JP_LEN 12 + +// Magic sequence for GeoJP2 UUID box +static unsigned char msi_uuid[16] = + { 0xb1,0x4b,0xf8,0xbd, + 0x08,0x3d,0x4b,0x43, + 0xa5,0xae,0x8c,0xd7, + 0xd5,0xa6,0xce,0x03}; + +// Magic sequence for XMP UUID box +static unsigned char xmp_uuid[16] = + { 0xBE, 0x7A, 0xCF, 0xCB, + 0x97, 0xA9, 0x42, 0xE8, + 0x9C, 0x71, 0x99, 0x94, + 0x91, 0xE3, 0xAF, 0xAC }; + +typedef struct { + uint_fast32_t magic; +} jp2_jp_t; + +/* FTYP box data. */ + +#define JP2_FTYP_MAXCOMPATCODES 32 +#define JP2_FTYP_MAJVER 0x6a703220 +#define JP2_FTYP_MINVER 0 +#define JP2_FTYP_COMPATCODE JP2_FTYP_MAJVER + +typedef struct { + uint_fast32_t majver; + uint_fast32_t minver; + uint_fast32_t numcompatcodes; + uint_fast32_t compatcodes[JP2_FTYP_MAXCOMPATCODES]; +} jp2_ftyp_t; + +/* IHDR box data. */ + +#define JP2_IHDR_COMPTYPE 7 +#define JP2_IHDR_BPCNULL 255 + +typedef struct { + uint_fast32_t width; + uint_fast32_t height; + uint_fast16_t numcmpts; + uint_fast8_t bpc; + uint_fast8_t comptype; + uint_fast8_t csunk; + uint_fast8_t ipr; +} jp2_ihdr_t; + +/* BPCC box data. */ + +typedef struct { + uint_fast16_t numcmpts; + uint_fast8_t *bpcs; +} jp2_bpcc_t; + +/* COLR box data. */ + +#define JP2_COLR_ENUM 1 +#define JP2_COLR_ICC 2 +#define JP2_COLR_PRI 0 + +#define JP2_COLR_SRGB 16 +#define JP2_COLR_SGRAY 17 +#define JP2_COLR_SYCC 18 + +typedef struct { + uint_fast8_t method; + uint_fast8_t pri; + uint_fast8_t approx; + uint_fast32_t csid; + uint_fast8_t *iccp; + int iccplen; + /* XXX - Someday we ought to add ICC profile data here. */ +} jp2_colr_t; + +/* PCLR box data. */ + +typedef struct { + uint_fast16_t numlutents; + uint_fast8_t numchans; + int_fast32_t *lutdata; + uint_fast8_t *bpc; +} jp2_pclr_t; + +/* CDEF box per-channel data. */ + +#define JP2_CDEF_RGB_R 1 +#define JP2_CDEF_RGB_G 2 +#define JP2_CDEF_RGB_B 3 + +#define JP2_CDEF_YCBCR_Y 1 +#define JP2_CDEF_YCBCR_CB 2 +#define JP2_CDEF_YCBCR_CR 3 + +#define JP2_CDEF_GRAY_Y 1 + +#define JP2_CDEF_TYPE_COLOR 0 +#define JP2_CDEF_TYPE_OPACITY 1 +#define JP2_CDEF_TYPE_UNSPEC 65535 +#define JP2_CDEF_ASOC_ALL 0 +#define JP2_CDEF_ASOC_NONE 65535 + +typedef struct { + uint_fast16_t channo; + uint_fast16_t type; + uint_fast16_t assoc; +} jp2_cdefchan_t; + +/* CDEF box data. */ + +typedef struct { + uint_fast16_t numchans; + jp2_cdefchan_t *ents; +} jp2_cdef_t; + +typedef struct { + uint_fast16_t cmptno; + uint_fast8_t map; + uint_fast8_t pcol; +} jp2_cmapent_t; + +typedef struct { + uint_fast16_t numchans; + jp2_cmapent_t *ents; +} jp2_cmap_t; + +typedef struct { + uint_fast32_t data_len; + uint_fast8_t uuid[16]; + uint_fast8_t *data; +} jp2_uuid_t; + +#define JP2_CMAP_DIRECT 0 +#define JP2_CMAP_PALETTE 1 + +/* Generic box. */ + +struct jp2_boxops_s; +typedef struct { + + struct jp2_boxops_s *ops; + struct jp2_boxinfo_s *info; + + uint_fast32_t type; + + /* The length of the box including the (variable-length) header. */ + uint_fast32_t len; + + /* The length of the box data. */ + uint_fast32_t datalen; + + union { + jp2_jp_t jp; + jp2_ftyp_t ftyp; + jp2_ihdr_t ihdr; + jp2_bpcc_t bpcc; + jp2_colr_t colr; + jp2_pclr_t pclr; + jp2_cdef_t cdef; + jp2_cmap_t cmap; + jp2_uuid_t uuid; + } data; + +} jp2_box_t; + +typedef struct jp2_boxops_s { + void (*init)(jp2_box_t *box); + void (*destroy)(jp2_box_t *box); + int (*getdata)(jp2_box_t *box, jas_stream_t *in); + int (*putdata)(jp2_box_t *box, jas_stream_t *out); + void (*dumpdata)(jp2_box_t *box, FILE *out); +} jp2_boxops_t; + +/******************************************************************************\ +* +\******************************************************************************/ + +typedef struct jp2_boxinfo_s { + int type; + char *name; + int flags; + jp2_boxops_t ops; +} jp2_boxinfo_t; + +/******************************************************************************\ +* Box class. +\******************************************************************************/ + +jp2_box_t *jp2_box_create(int type); +void jp2_box_destroy(jp2_box_t *box); +jp2_box_t *jp2_box_get(jas_stream_t *in); +int jp2_box_put(jp2_box_t *box, jas_stream_t *out); + +#define JP2_DTYPETOBPC(dtype) \ + ((JAS_IMAGE_CDT_GETSGND(dtype) << 7) | (JAS_IMAGE_CDT_GETPREC(dtype) - 1)) +#define JP2_BPCTODTYPE(bpc) \ + (JAS_IMAGE_CDT_SETSGND(bpc >> 7) | JAS_IMAGE_CDT_SETPREC((bpc & 0x7f) + 1)) + +#define ICC_CS_RGB 0x52474220 +#define ICC_CS_YCBCR 0x59436272 +#define ICC_CS_GRAY 0x47524159 + +jp2_cdefchan_t *jp2_cdef_lookup(jp2_cdef_t *cdef, int channo); + + +#endif diff --git a/src/libjasper/jp2/jp2_dec.c b/src/libjasper/jp2/jp2_dec.c new file mode 100644 index 0000000..45a8993 --- /dev/null +++ b/src/libjasper/jp2/jp2_dec.c @@ -0,0 +1,702 @@ +/* + * Copyright (c) 1999-2000 Image Power, Inc. and the University of + * British Columbia. + * Copyright (c) 2001-2003 Michael David Adams. + * All rights reserved. + + GeoJasper revision: Dima (11/07/2003 17:29 - UUID and additional args) + */ + +/* __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_dec.c,v 1.1 2008/10/17 06:14:59 scuri Exp $ + */ + +/******************************************************************************\ +* Includes. +\******************************************************************************/ + +#include "jasper/jas_image.h" +#include "jasper/jas_stream.h" +#include "jasper/jas_math.h" +#include "jasper/jas_debug.h" +#include "jasper/jas_malloc.h" +#include "jasper/jas_version.h" + +// GeoJasper: dima +#if !defined( JAS_GEO_OMIT_PRINTING_CODE ) +#include "../tiff/geotiff_buffer.h" +#endif +// end: dima + +#include "jp2_cod.h" +#include "jp2_dec.h" + +#define JP2_VALIDATELEN (JAS_MIN(JP2_JP_LEN + 16, JAS_STREAM_MAXPUTBACK)) + +static jp2_dec_t *jp2_dec_create(void); +static void jp2_dec_destroy(jp2_dec_t *dec); +static int jp2_getcs(jp2_colr_t *colr); +static int fromiccpcs(int cs); +static int jp2_getct(int colorspace, int type, int assoc); + +/******************************************************************************\ +* Functions. +\******************************************************************************/ + +jas_image_t *jp2_decode(jas_stream_t *in, char *optstr) +{ + jp2_box_t *box; + int found; + jas_image_t *image; + jp2_dec_t *dec; + bool samedtype; + int dtype; + unsigned int i; + jp2_cmap_t *cmapd; + jp2_pclr_t *pclrd; + jp2_cdef_t *cdefd; + unsigned int channo; + int newcmptno; + int_fast32_t *lutents; +#if 0 + jp2_cdefchan_t *cdefent; + int cmptno; +#endif + jp2_cmapent_t *cmapent; + jas_icchdr_t icchdr; + jas_iccprof_t *iccprof; + + // GeoJasper: dima - begin - temporary metadata buffers + //jas_aux_buffer_t aux_buf; + //aux_buf.id = 0; + jas_metadata_boxes_t tmp_metadata; + tmp_metadata.count = JAS_IMAGE_NUM_BOXES; + for (i=0; i<tmp_metadata.count; ++i) + tmp_metadata.boxes[i] = jas_box_init(); + // GeoJasper: dima - end - temporary metadata buffers + + dec = 0; + box = 0; + image = 0; + + if (!(dec = jp2_dec_create())) { + goto error; + } + + /* Get the first box. This should be a JP box. */ + if (!(box = jp2_box_get(in))) { + jas_eprintf("error: cannot get box\n"); + goto error; + } + if (box->type != JP2_BOX_JP) { + jas_eprintf("error: expecting signature box\n"); + goto error; + } + if (box->data.jp.magic != JP2_JP_MAGIC) { + jas_eprintf("incorrect magic number\n"); + goto error; + } + jp2_box_destroy(box); + box = 0; + + /* Get the second box. This should be a FTYP box. */ + if (!(box = jp2_box_get(in))) { + goto error; + } + if (box->type != JP2_BOX_FTYP) { + jas_eprintf("expecting file type box\n"); + goto error; + } + jp2_box_destroy(box); + box = 0; + + /* Get more boxes... */ + found = 0; + while ((box = jp2_box_get(in))) { + if (jas_getdbglevel() >= 1) { + jas_eprintf("box type %s\n", box->info->name); + } + switch (box->type) { + case JP2_BOX_JP2C: + found = 1; + break; + case JP2_BOX_IHDR: + if (!dec->ihdr) { + dec->ihdr = box; + box = 0; + } + break; + case JP2_BOX_BPCC: + if (!dec->bpcc) { + dec->bpcc = box; + box = 0; + } + break; + case JP2_BOX_CDEF: + if (!dec->cdef) { + dec->cdef = box; + box = 0; + } + break; + case JP2_BOX_PCLR: + if (!dec->pclr) { + dec->pclr = box; + box = 0; + } + break; + case JP2_BOX_CMAP: + if (!dec->cmap) { + dec->cmap = box; + box = 0; + } + break; + case JP2_BOX_COLR: + if (!dec->colr) { + dec->colr = box; + box = 0; + } + break; + //------------------------------------------------------- + case JP2_BOX_UUID: // GeoJasper: dima - begin extract uuid + { + int box_id = -1; + if ( memcmp( box->data.uuid.uuid, msi_uuid, sizeof(msi_uuid) ) == 0 ) box_id = JAS_IMAGE_BOX_GEO; + if ( memcmp( box->data.uuid.uuid, xmp_uuid, sizeof(xmp_uuid) ) == 0 ) box_id = JAS_IMAGE_BOX_XMP; + + if( box_id >= 0 ) { + jas_metadata_box_t *metabox = &tmp_metadata.boxes[box_id]; + if ( jas_box_alloc( metabox, box->data.uuid.data_len ) ) { + memcpy( metabox->id, box->data.uuid.uuid, sizeof(msi_uuid) ); + memcpy( metabox->buf, box->data.uuid.data, metabox->size ); + } // if box allocated + } // if uuid box contains info to copy + } + + break; // GeoJasper: end - begin extract uuid + //------------------------------------------------------- + } + if (box) { + jp2_box_destroy(box); + box = 0; + } + if (found) { + break; + } + } + + //------------------------------------------------------- + // GeoJasper: dima - begin - print geojpeg2000 if needed +#if !defined( JAS_GEO_OMIT_PRINTING_CODE ) + if ( (optstr) && ( strstr(optstr, "listgeo") != NULL ) ) { + jas_metadata_box_t *metabox = &tmp_metadata.boxes[JAS_IMAGE_BOX_GEO]; + long w=1, h=1; + + if (dec->ihdr) { + w = dec->ihdr->data.ihdr.width; + h = dec->ihdr->data.ihdr.height; + } + if ( (memcmp(metabox->id, msi_uuid, sizeof(msi_uuid))==0) && metabox->buf != NULL ) + printGTIFFromMemBufA( metabox->buf, metabox->size, w, h ); + else + jas_eprintf("geojasper info: GeoJp2 info not found!\n"); + exit(0); + } + + if ( (optstr) && ( strstr(optstr, "listxmp") != NULL ) ) { + jas_metadata_box_t *metabox = &tmp_metadata.boxes[JAS_IMAGE_BOX_XMP]; + + if ( (memcmp(metabox->id, xmp_uuid, sizeof(xmp_uuid))==0) && metabox->buf != NULL ) { + // xmp buffer in is not guaranteed to be null terminated... + char *strbuf = (char *) jas_malloc(metabox->size+1); + strncpy(strbuf, metabox->buf, metabox->size); + strbuf[metabox->size] = 0; + fprintf( stdout, "%s\n", strbuf ); + jas_free(strbuf); + } else + jas_eprintf("geojasper info: Adobe XMP info not found!\n"); + exit(0); + } + + // simple check if we have boxes + if ( (memcmp(tmp_metadata.boxes[JAS_IMAGE_BOX_GEO].id, msi_uuid, sizeof(msi_uuid))==0) && + tmp_metadata.boxes[JAS_IMAGE_BOX_GEO].buf != NULL ) + jas_eprintf("geojasper info: GeoJp2 found, size: %d\n", tmp_metadata.boxes[JAS_IMAGE_BOX_GEO].size); + + if ( (memcmp(tmp_metadata.boxes[JAS_IMAGE_BOX_XMP].id, xmp_uuid, sizeof(xmp_uuid))==0) && + tmp_metadata.boxes[JAS_IMAGE_BOX_XMP].buf != NULL ) + jas_eprintf("geojasper info: Adobe XMP found, size: %d\n", tmp_metadata.boxes[JAS_IMAGE_BOX_XMP].size); + +#endif // #if !defined( JAS_GEO_OMIT_PRINTING_CODE ) + // GeoJasper: dima - end - print geojpeg2000 if needed + //------------------------------------------------------- + + if (!found) { + jas_eprintf("error: no code stream found\n"); + goto error; + } + + if (!(dec->image = jpc_decode(in, optstr))) { + jas_eprintf("error: cannot decode code stream\n"); + goto error; + } + + /* An IHDR box must be present. */ + if (!dec->ihdr) { + jas_eprintf("error: missing IHDR box\n"); + goto error; + } + + /* Does the number of components indicated in the IHDR box match + the value specified in the code stream? */ + if (dec->ihdr->data.ihdr.numcmpts != JAS_CAST(unsigned int, jas_image_numcmpts(dec->image))) { /* IMLIB - changed unit to unsigned int */ + jas_eprintf("warning: number of components mismatch\n"); + } + + /* At least one component must be present. */ + if (!jas_image_numcmpts(dec->image)) { + jas_eprintf("error: no components\n"); + goto error; + } + + /* Determine if all components have the same data type. */ + samedtype = true; + dtype = jas_image_cmptdtype(dec->image, 0); + for (i = 1; i < JAS_CAST(unsigned int, jas_image_numcmpts(dec->image)); ++i) { /* IMLIB - changed unit to unsigned int */ + if (jas_image_cmptdtype(dec->image, i) != dtype) { + samedtype = false; + break; + } + } + + /* Is the component data type indicated in the IHDR box consistent + with the data in the code stream? */ + if ((samedtype && dec->ihdr->data.ihdr.bpc != JP2_DTYPETOBPC(dtype)) || + (!samedtype && dec->ihdr->data.ihdr.bpc != JP2_IHDR_BPCNULL)) { + jas_eprintf("warning: component data type mismatch\n"); + } + + /* Is the compression type supported? */ + if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) { + jas_eprintf("error: unsupported compression type\n"); + goto error; + } + + if (dec->bpcc) { + /* Is the number of components indicated in the BPCC box + consistent with the code stream data? */ + if (dec->bpcc->data.bpcc.numcmpts != JAS_CAST(unsigned int, jas_image_numcmpts( /* IMLIB - changed unit to unsigned int */ + dec->image))) { + jas_eprintf("warning: number of components mismatch\n"); + } + /* Is the component data type information indicated in the BPCC + box consistent with the code stream data? */ + if (!samedtype) { + for (i = 0; i < JAS_CAST(unsigned int, jas_image_numcmpts(dec->image)); ++i) { /* IMLIB - changed unit to unsigned int */ + if (jas_image_cmptdtype(dec->image, i) != JP2_BPCTODTYPE(dec->bpcc->data.bpcc.bpcs[i])) { + jas_eprintf("warning: component data type mismatch\n"); + } + } + } else { + jas_eprintf("warning: superfluous BPCC box\n"); + } + } + + /* A COLR box must be present. */ + if (!dec->colr) { + jas_eprintf("error: no COLR box\n"); + goto error; + } + + switch (dec->colr->data.colr.method) { + case JP2_COLR_ENUM: + jas_image_setclrspc(dec->image, jp2_getcs(&dec->colr->data.colr)); + break; + case JP2_COLR_ICC: + iccprof = jas_iccprof_createfrombuf(dec->colr->data.colr.iccp, + dec->colr->data.colr.iccplen); + assert(iccprof); + jas_iccprof_gethdr(iccprof, &icchdr); + jas_eprintf("ICC Profile CS %08x\n", icchdr.colorspc); + jas_image_setclrspc(dec->image, fromiccpcs(icchdr.colorspc)); + dec->image->cmprof_ = jas_cmprof_createfromiccprof(iccprof); + assert(dec->image->cmprof_); + jas_iccprof_destroy(iccprof); + break; + } + + /* If a CMAP box is present, a PCLR box must also be present. */ + if (dec->cmap && !dec->pclr) { + jas_eprintf("warning: missing PCLR box or superfluous CMAP box\n"); + jp2_box_destroy(dec->cmap); + dec->cmap = 0; + } + + /* If a CMAP box is not present, a PCLR box must not be present. */ + if (!dec->cmap && dec->pclr) { + jas_eprintf("warning: missing CMAP box or superfluous PCLR box\n"); + jp2_box_destroy(dec->pclr); + dec->pclr = 0; + } + + /* Determine the number of channels (which is essentially the number + of components after any palette mappings have been applied). */ + dec->numchans = dec->cmap ? dec->cmap->data.cmap.numchans : JAS_CAST(unsigned int, jas_image_numcmpts(dec->image)); /* IMLIB - changed unit to unsigned int */ + + /* Perform a basic sanity check on the CMAP box if present. */ + if (dec->cmap) { + for (i = 0; i < dec->numchans; ++i) { + /* Is the component number reasonable? */ + if (dec->cmap->data.cmap.ents[i].cmptno >= JAS_CAST(unsigned int, jas_image_numcmpts(dec->image))) { /* IMLIB - changed unit to unsigned int */ + jas_eprintf("error: invalid component number in CMAP box\n"); + goto error; + } + /* Is the LUT index reasonable? */ + if (dec->cmap->data.cmap.ents[i].pcol >= dec->pclr->data.pclr.numchans) { + jas_eprintf("error: invalid CMAP LUT index\n"); + goto error; + } + } + } + + /* Allocate space for the channel-number to component-number LUT. */ + if (!(dec->chantocmptlut = jas_malloc(dec->numchans * sizeof(uint_fast16_t)))) { + jas_eprintf("error: no memory\n"); + goto error; + } + + if (!dec->cmap) { + for (i = 0; i < dec->numchans; ++i) { + dec->chantocmptlut[i] = i; + } + } else { + cmapd = &dec->cmap->data.cmap; + pclrd = &dec->pclr->data.pclr; + cdefd = &dec->cdef->data.cdef; + for (channo = 0; channo < cmapd->numchans; ++channo) { + cmapent = &cmapd->ents[channo]; + if (cmapent->map == JP2_CMAP_DIRECT) { + dec->chantocmptlut[channo] = channo; + } else if (cmapent->map == JP2_CMAP_PALETTE) { + lutents = jas_malloc(pclrd->numlutents * sizeof(int_fast32_t)); + for (i = 0; i < pclrd->numlutents; ++i) { + lutents[i] = pclrd->lutdata[cmapent->pcol + i * pclrd->numchans]; + } + newcmptno = jas_image_numcmpts(dec->image); + jas_image_depalettize(dec->image, cmapent->cmptno, pclrd->numlutents, lutents, JP2_BPCTODTYPE(pclrd->bpc[cmapent->pcol]), newcmptno); + dec->chantocmptlut[channo] = newcmptno; + jas_free(lutents); +#if 0 + if (dec->cdef) { + cdefent = jp2_cdef_lookup(cdefd, channo); + if (!cdefent) { + abort(); + } + jas_image_setcmpttype(dec->image, newcmptno, jp2_getct(jas_image_clrspc(dec->image), cdefent->type, cdefent->assoc)); + } else { + jas_image_setcmpttype(dec->image, newcmptno, jp2_getct(jas_image_clrspc(dec->image), 0, channo + 1)); + } +#endif + } + } + } + + /* Mark all components as being of unknown type. */ + + for (i = 0; i < JAS_CAST(unsigned int, jas_image_numcmpts(dec->image)); ++i) { /* IMLIB - changed unit to unsigned int */ + jas_image_setcmpttype(dec->image, i, JAS_IMAGE_CT_UNKNOWN); + } + + /* Determine the type of each component. */ + if (dec->cdef) { + for (i = 0; i < dec->numchans; ++i) { + jas_image_setcmpttype(dec->image, + dec->chantocmptlut[dec->cdef->data.cdef.ents[i].channo], + jp2_getct(jas_image_clrspc(dec->image), + dec->cdef->data.cdef.ents[i].type, dec->cdef->data.cdef.ents[i].assoc)); + } + } else { + for (i = 0; i < dec->numchans; ++i) { + jas_image_setcmpttype(dec->image, dec->chantocmptlut[i], + jp2_getct(jas_image_clrspc(dec->image), 0, i + 1)); + } + } + + // GeoJasper: dima - let's preserve the actual image data by marking unknown components as gray + /* Delete any components that are not of interest. */ + /* + for (i = jas_image_numcmpts(dec->image); i > 0; --i) { + if (jas_image_cmpttype(dec->image, i - 1) == JAS_IMAGE_CT_UNKNOWN) { + jas_image_delcmpt(dec->image, i - 1); + } + } + */ + // GeoJasper: dima - let's preserve the actual image data by marking unknown components as gray + for (i = jas_image_numcmpts(dec->image); i > 0; --i) { + if (jas_image_cmpttype(dec->image, i-1) == JAS_IMAGE_CT_UNKNOWN) { + jas_image_setcmpttype(dec->image, i-1, JAS_IMAGE_CT_GRAY_Y); + } + } + + + /* Ensure that some components survived. */ + if (!jas_image_numcmpts(dec->image)) { + jas_eprintf("error: no components\n"); + goto error; + } +#if 0 +jas_eprintf("no of components is %d\n", jas_image_numcmpts(dec->image)); +#endif + + /* Prevent the image from being destroyed later. */ + + // GeoJasper: begin - dima - copy buffers to the output image + for (i=0; i<tmp_metadata.count; ++i) { + dec->image->metadata.boxes[i] = tmp_metadata.boxes[i]; + tmp_metadata.boxes[i] = jas_box_init(); + } + // GeoJasper: end - dima - copy buffers to the output image + + image = dec->image; + dec->image = 0; + + jp2_dec_destroy(dec); + + return image; + +error: + if (box) { + jp2_box_destroy(box); + } + if (dec) { + jp2_dec_destroy(dec); + } + return 0; +} + +int jp2_validate(jas_stream_t *in) +{ + char buf[JP2_VALIDATELEN]; + int i; + int n; +#if 0 + jas_stream_t *tmpstream; + jp2_box_t *box; +#endif + + assert(JAS_STREAM_MAXPUTBACK >= JP2_VALIDATELEN); + + /* Read the validation data (i.e., the data used for detecting + the format). */ + if ((n = jas_stream_read(in, buf, JP2_VALIDATELEN)) < 0) { + return -1; + } + + /* Put the validation data back onto the stream, so that the + stream position will not be changed. */ + for (i = n - 1; i >= 0; --i) { + if (jas_stream_ungetc(in, buf[i]) == EOF) { + return -1; + } + } + + /* Did we read enough data? */ + if (n < JP2_VALIDATELEN) { + return -1; + } + + /* Is the box type correct? */ + if (((buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]) != + JP2_BOX_JP) + { + return -1; + } + + return 0; +} + +static jp2_dec_t *jp2_dec_create(void) +{ + jp2_dec_t *dec; + + if (!(dec = jas_malloc(sizeof(jp2_dec_t)))) { + return 0; + } + dec->ihdr = 0; + dec->bpcc = 0; + dec->cdef = 0; + dec->pclr = 0; + dec->image = 0; + dec->chantocmptlut = 0; + dec->cmap = 0; + dec->colr = 0; + return dec; +} + +static void jp2_dec_destroy(jp2_dec_t *dec) +{ + if (dec->ihdr) { + jp2_box_destroy(dec->ihdr); + } + if (dec->bpcc) { + jp2_box_destroy(dec->bpcc); + } + if (dec->cdef) { + jp2_box_destroy(dec->cdef); + } + if (dec->pclr) { + jp2_box_destroy(dec->pclr); + } + if (dec->image) { + jas_image_destroy(dec->image); + } + if (dec->cmap) { + jp2_box_destroy(dec->cmap); + } + if (dec->colr) { + jp2_box_destroy(dec->colr); + } + if (dec->chantocmptlut) { + jas_free(dec->chantocmptlut); + } + jas_free(dec); +} + +static int jp2_getct(int colorspace, int type, int assoc) +{ + if (type == 1 && assoc == 0) { + return JAS_IMAGE_CT_OPACITY; + } + if (type == 0 && assoc >= 1 && assoc <= 65534) { + switch (colorspace) { + case JAS_CLRSPC_FAM_RGB: + switch (assoc) { + case JP2_CDEF_RGB_R: + return JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R); + break; + case JP2_CDEF_RGB_G: + return JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G); + break; + case JP2_CDEF_RGB_B: + return JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B); + break; + } + break; + case JAS_CLRSPC_FAM_YCBCR: + switch (assoc) { + case JP2_CDEF_YCBCR_Y: + return JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_Y); + break; + case JP2_CDEF_YCBCR_CB: + return JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CB); + break; + case JP2_CDEF_YCBCR_CR: + return JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_YCBCR_CR); + break; + } + break; + case JAS_CLRSPC_FAM_GRAY: + switch (assoc) { + case JP2_CDEF_GRAY_Y: + return JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y); + break; + } + break; + default: + return JAS_IMAGE_CT_COLOR(assoc - 1); + break; + } + } + return JAS_IMAGE_CT_UNKNOWN; +} + +static int jp2_getcs(jp2_colr_t *colr) +{ + if (colr->method == JP2_COLR_ENUM) { + switch (colr->csid) { + case JP2_COLR_SRGB: + return JAS_CLRSPC_SRGB; + break; + case JP2_COLR_SYCC: + return JAS_CLRSPC_SYCBCR; + break; + case JP2_COLR_SGRAY: + return JAS_CLRSPC_SGRAY; + break; + } + } + return JAS_CLRSPC_UNKNOWN; +} + +static int fromiccpcs(int cs) +{ + switch (cs) { + case ICC_CS_RGB: + return JAS_CLRSPC_GENRGB; + break; + case ICC_CS_YCBCR: + return JAS_CLRSPC_GENYCBCR; + break; + case ICC_CS_GRAY: + return JAS_CLRSPC_GENGRAY; + break; + } + return JAS_CLRSPC_UNKNOWN; +} diff --git a/src/libjasper/jp2/jp2_dec.h b/src/libjasper/jp2/jp2_dec.h new file mode 100644 index 0000000..1cb95a2 --- /dev/null +++ b/src/libjasper/jp2/jp2_dec.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1999-2000 Image Power, Inc. and the University of + * British Columbia. + * Copyright (c) 2001-2002 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__ + */ + +#ifndef JP2_DEC_H +#define JP2_DEC_H + +#include "jasper/jas_image.h" +#include "jasper/jas_stream.h" +#include "jp2_cod.h" + +typedef struct { + + jp2_box_t *pclr; + jp2_box_t *cdef; + jp2_box_t *ihdr; + jp2_box_t *bpcc; + jp2_box_t *cmap; + jp2_box_t *colr; + jas_image_t *image; + uint_fast16_t numchans; + uint_fast16_t *chantocmptlut; + +} jp2_dec_t; + +#endif diff --git a/src/libjasper/jp2/jp2_enc.c b/src/libjasper/jp2/jp2_enc.c new file mode 100644 index 0000000..cb6299f --- /dev/null +++ b/src/libjasper/jp2/jp2_enc.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 1999-2000 Image Power, Inc. and the University of + * British Columbia. + * Copyright (c) 2001-2003 Michael David Adams. + * All rights reserved. + + GeoJasper revision: Dima (11/07/2003 17:29 - UUID) + */ + +/* __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.1 2008/10/17 06:14:59 scuri 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_encode(jas_image_t *image, jas_stream_t *out, 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; + 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_malloc(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_malloc(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; + + /* + * Output the UUID box + */ + // GeoJasper: dima - write UUID if received any metadata + if ( image->metadata.count > 0 ) { + int b; + for (b=0; b<image->metadata.count; ++b) { + jas_metadata_box_t *metabox = &image->metadata.boxes[b]; + + if ( metabox->size>0 && metabox->buf ) { + if (!(box = jp2_box_create( JP2_BOX_UUID ))) + goto error; + + memcpy( box->data.uuid.uuid, metabox->id, sizeof(msi_uuid) ); + box->data.uuid.data_len = metabox->size; + if ( !(box->data.uuid.data = (uint_fast8_t *)jas_malloc(metabox->size)) ) + goto error; + memcpy( box->data.uuid.data, metabox->buf, metabox->size ); + + if (jp2_box_put(box, out)) + goto error; + + jp2_box_destroy(box); + box = 0; + } // if box contains data + } // for boxes + } // if there are boxes + // GeoJasper: dima - write UUID if received + + + + /* + * 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); + } + 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: + abort(); + break; + } +} |