123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- /*
- * The Python Imaging Library.
- * $Id$
- *
- * decoder for JPEG2000 image data.
- *
- * history:
- * 2014-03-12 ajh Created
- *
- * Copyright (c) 2014 Coriolis Systems Limited
- * Copyright (c) 2014 Alastair Houghton
- *
- * See the README file for details on usage and redistribution.
- */
- #include "Imaging.h"
- #ifdef HAVE_OPENJPEG
- #include <stdlib.h>
- #include "Jpeg2K.h"
- typedef struct {
- OPJ_UINT32 tile_index;
- OPJ_UINT32 data_size;
- OPJ_INT32 x0, y0, x1, y1;
- OPJ_UINT32 nb_comps;
- } JPEG2KTILEINFO;
- /* -------------------------------------------------------------------- */
- /* Error handler */
- /* -------------------------------------------------------------------- */
- static void
- j2k_error(const char *msg, void *client_data)
- {
- JPEG2KDECODESTATE *state = (JPEG2KDECODESTATE *) client_data;
- free((void *)state->error_msg);
- state->error_msg = strdup(msg);
- }
- /* -------------------------------------------------------------------- */
- /* Buffer input stream */
- /* -------------------------------------------------------------------- */
- static OPJ_SIZE_T
- j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
- {
- ImagingCodecState state = (ImagingCodecState)p_user_data;
- size_t len = _imaging_read_pyFd(state->fd, p_buffer, p_nb_bytes);
- return len ? len : (OPJ_SIZE_T)-1;
- }
- static OPJ_OFF_T
- j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
- {
- off_t pos;
- ImagingCodecState state = (ImagingCodecState)p_user_data;
- _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_CUR);
- pos = _imaging_tell_pyFd(state->fd);
- return pos ? pos : (OPJ_OFF_T)-1;
- }
- /* -------------------------------------------------------------------- */
- /* Unpackers */
- /* -------------------------------------------------------------------- */
- typedef void (*j2k_unpacker_t)(opj_image_t *in,
- const JPEG2KTILEINFO *tileInfo,
- const UINT8 *data,
- Imaging im);
- struct j2k_decode_unpacker {
- const char *mode;
- OPJ_COLOR_SPACE color_space;
- unsigned components;
- j2k_unpacker_t unpacker;
- };
- static inline
- unsigned j2ku_shift(unsigned x, int n)
- {
- if (n < 0)
- return x >> -n;
- else
- return x << n;
- }
- static void
- j2ku_gray_l(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shift = 8 - in->comps[0].prec;
- int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
- int csiz = (in->comps[0].prec + 7) >> 3;
- unsigned x, y;
- if (csiz == 3)
- csiz = 4;
- if (shift < 0)
- offset += 1 << (-shift - 1);
- switch (csiz) {
- case 1:
- for (y = 0; y < h; ++y) {
- const UINT8 *data = &tiledata[y * w];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x)
- *row++ = j2ku_shift(offset + *data++, shift);
- }
- break;
- case 2:
- for (y = 0; y < h; ++y) {
- const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x)
- *row++ = j2ku_shift(offset + *data++, shift);
- }
- break;
- case 4:
- for (y = 0; y < h; ++y) {
- const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x)
- *row++ = j2ku_shift(offset + *data++, shift);
- }
- break;
- }
- }
- static void
- j2ku_gray_i(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shift = 16 - in->comps[0].prec;
- int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
- int csiz = (in->comps[0].prec + 7) >> 3;
- unsigned x, y;
- if (csiz == 3)
- csiz = 4;
- if (shift < 0)
- offset += 1 << (-shift - 1);
- switch (csiz) {
- case 1:
- for (y = 0; y < h; ++y) {
- const UINT8 *data = &tiledata[y * w];
- UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x)
- *row++ = j2ku_shift(offset + *data++, shift);
- }
- break;
- case 2:
- for (y = 0; y < h; ++y) {
- const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w];
- UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x)
- *row++ = j2ku_shift(offset + *data++, shift);
- }
- break;
- case 4:
- for (y = 0; y < h; ++y) {
- const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w];
- UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x)
- *row++ = j2ku_shift(offset + *data++, shift);
- }
- break;
- }
- }
- static void
- j2ku_gray_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shift = 8 - in->comps[0].prec;
- int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
- int csiz = (in->comps[0].prec + 7) >> 3;
- unsigned x, y;
- if (shift < 0)
- offset += 1 << (-shift - 1);
- if (csiz == 3)
- csiz = 4;
- switch (csiz) {
- case 1:
- for (y = 0; y < h; ++y) {
- const UINT8 *data = &tiledata[y * w];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x) {
- UINT8 byte = j2ku_shift(offset + *data++, shift);
- row[0] = row[1] = row[2] = byte;
- row[3] = 0xff;
- row += 4;
- }
- }
- break;
- case 2:
- for (y = 0; y < h; ++y) {
- const UINT16 *data = (UINT16 *)&tiledata[2 * y * w];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x) {
- UINT8 byte = j2ku_shift(offset + *data++, shift);
- row[0] = row[1] = row[2] = byte;
- row[3] = 0xff;
- row += 4;
- }
- }
- break;
- case 4:
- for (y = 0; y < h; ++y) {
- const UINT32 *data = (UINT32 *)&tiledata[4 * y * w];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
- for (x = 0; x < w; ++x) {
- UINT8 byte = j2ku_shift(offset + *data++, shift);
- row[0] = row[1] = row[2] = byte;
- row[3] = 0xff;
- row += 4;
- }
- }
- break;
- }
- }
- static void
- j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shift = 8 - in->comps[0].prec;
- int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
- int csiz = (in->comps[0].prec + 7) >> 3;
- int ashift = 8 - in->comps[1].prec;
- int aoffset = in->comps[1].sgnd ? 1 << (in->comps[1].prec - 1) : 0;
- int acsiz = (in->comps[1].prec + 7) >> 3;
- const UINT8 *atiledata;
- unsigned x, y;
- if (csiz == 3)
- csiz = 4;
- if (acsiz == 3)
- acsiz = 4;
- if (shift < 0)
- offset += 1 << (-shift - 1);
- if (ashift < 0)
- aoffset += 1 << (-ashift - 1);
- atiledata = tiledata + csiz * w * h;
- for (y = 0; y < h; ++y) {
- const UINT8 *data = &tiledata[csiz * y * w];
- const UINT8 *adata = &atiledata[acsiz * y * w];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
- for (x = 0; x < w; ++x) {
- UINT32 word = 0, aword = 0, byte;
- switch (csiz) {
- case 1: word = *data++; break;
- case 2: word = *(const UINT16 *)data; data += 2; break;
- case 4: word = *(const UINT32 *)data; data += 4; break;
- }
- switch (acsiz) {
- case 1: aword = *adata++; break;
- case 2: aword = *(const UINT16 *)adata; adata += 2; break;
- case 4: aword = *(const UINT32 *)adata; adata += 4; break;
- }
- byte = j2ku_shift(offset + word, shift);
- row[0] = row[1] = row[2] = byte;
- row[3] = j2ku_shift(aoffset + aword, ashift);
- row += 4;
- }
- }
- }
- static void
- j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shifts[3], offsets[3], csiz[3];
- const UINT8 *cdata[3];
- const UINT8 *cptr = tiledata;
- unsigned n, x, y;
- for (n = 0; n < 3; ++n) {
- cdata[n] = cptr;
- shifts[n] = 8 - in->comps[n].prec;
- offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
- csiz[n] = (in->comps[n].prec + 7) >> 3;
- if (csiz[n] == 3)
- csiz[n] = 4;
- if (shifts[n] < 0)
- offsets[n] += 1 << (-shifts[n] - 1);
- cptr += csiz[n] * w * h;
- }
- for (y = 0; y < h; ++y) {
- const UINT8 *data[3];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
- for (n = 0; n < 3; ++n)
- data[n] = &cdata[n][csiz[n] * y * w];
- for (x = 0; x < w; ++x) {
- for (n = 0; n < 3; ++n) {
- UINT32 word = 0;
- switch (csiz[n]) {
- case 1: word = *data[n]++; break;
- case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
- case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
- }
- row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
- }
- row[3] = 0xff;
- row += 4;
- }
- }
- }
- static void
- j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shifts[3], offsets[3], csiz[3];
- const UINT8 *cdata[3];
- const UINT8 *cptr = tiledata;
- unsigned n, x, y;
- for (n = 0; n < 3; ++n) {
- cdata[n] = cptr;
- shifts[n] = 8 - in->comps[n].prec;
- offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
- csiz[n] = (in->comps[n].prec + 7) >> 3;
- if (csiz[n] == 3)
- csiz[n] = 4;
- if (shifts[n] < 0)
- offsets[n] += 1 << (-shifts[n] - 1);
- cptr += csiz[n] * w * h;
- }
- for (y = 0; y < h; ++y) {
- const UINT8 *data[3];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
- UINT8 *row_start = row;
- for (n = 0; n < 3; ++n)
- data[n] = &cdata[n][csiz[n] * y * w];
- for (x = 0; x < w; ++x) {
- for (n = 0; n < 3; ++n) {
- UINT32 word = 0;
- switch (csiz[n]) {
- case 1: word = *data[n]++; break;
- case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
- case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
- }
- row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
- }
- row[3] = 0xff;
- row += 4;
- }
- ImagingConvertYCbCr2RGB(row_start, row_start, w);
- }
- }
- static void
- j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shifts[4], offsets[4], csiz[4];
- const UINT8 *cdata[4];
- const UINT8 *cptr = tiledata;
- unsigned n, x, y;
- for (n = 0; n < 4; ++n) {
- cdata[n] = cptr;
- shifts[n] = 8 - in->comps[n].prec;
- offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
- csiz[n] = (in->comps[n].prec + 7) >> 3;
- if (csiz[n] == 3)
- csiz[n] = 4;
- if (shifts[n] < 0)
- offsets[n] += 1 << (-shifts[n] - 1);
- cptr += csiz[n] * w * h;
- }
- for (y = 0; y < h; ++y) {
- const UINT8 *data[4];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
- for (n = 0; n < 4; ++n)
- data[n] = &cdata[n][csiz[n] * y * w];
- for (x = 0; x < w; ++x) {
- for (n = 0; n < 4; ++n) {
- UINT32 word = 0;
- switch (csiz[n]) {
- case 1: word = *data[n]++; break;
- case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
- case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
- }
- row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
- }
- row += 4;
- }
- }
- }
- static void
- j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
- const UINT8 *tiledata, Imaging im)
- {
- unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
- unsigned w = tileinfo->x1 - tileinfo->x0;
- unsigned h = tileinfo->y1 - tileinfo->y0;
- int shifts[4], offsets[4], csiz[4];
- const UINT8 *cdata[4];
- const UINT8 *cptr = tiledata;
- unsigned n, x, y;
- for (n = 0; n < 4; ++n) {
- cdata[n] = cptr;
- shifts[n] = 8 - in->comps[n].prec;
- offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
- csiz[n] = (in->comps[n].prec + 7) >> 3;
- if (csiz[n] == 3)
- csiz[n] = 4;
- if (shifts[n] < 0)
- offsets[n] += 1 << (-shifts[n] - 1);
- cptr += csiz[n] * w * h;
- }
- for (y = 0; y < h; ++y) {
- const UINT8 *data[4];
- UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
- UINT8 *row_start = row;
- for (n = 0; n < 4; ++n)
- data[n] = &cdata[n][csiz[n] * y * w];
- for (x = 0; x < w; ++x) {
- for (n = 0; n < 4; ++n) {
- UINT32 word = 0;
- switch (csiz[n]) {
- case 1: word = *data[n]++; break;
- case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
- case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
- }
- row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
- }
- row += 4;
- }
- ImagingConvertYCbCr2RGB(row_start, row_start, w);
- }
- }
- static const struct j2k_decode_unpacker j2k_unpackers[] = {
- { "L", OPJ_CLRSPC_GRAY, 1, j2ku_gray_l },
- { "I;16", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i },
- { "I;16B", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i },
- { "LA", OPJ_CLRSPC_GRAY, 2, j2ku_graya_la },
- { "RGB", OPJ_CLRSPC_GRAY, 1, j2ku_gray_rgb },
- { "RGB", OPJ_CLRSPC_GRAY, 2, j2ku_gray_rgb },
- { "RGB", OPJ_CLRSPC_SRGB, 3, j2ku_srgb_rgb },
- { "RGB", OPJ_CLRSPC_SYCC, 3, j2ku_sycc_rgb },
- { "RGB", OPJ_CLRSPC_SRGB, 4, j2ku_srgb_rgb },
- { "RGB", OPJ_CLRSPC_SYCC, 4, j2ku_sycc_rgb },
- { "RGBA", OPJ_CLRSPC_GRAY, 1, j2ku_gray_rgb },
- { "RGBA", OPJ_CLRSPC_GRAY, 2, j2ku_graya_la },
- { "RGBA", OPJ_CLRSPC_SRGB, 3, j2ku_srgb_rgb },
- { "RGBA", OPJ_CLRSPC_SYCC, 3, j2ku_sycc_rgb },
- { "RGBA", OPJ_CLRSPC_SRGB, 4, j2ku_srgba_rgba },
- { "RGBA", OPJ_CLRSPC_SYCC, 4, j2ku_sycca_rgba },
- };
- /* -------------------------------------------------------------------- */
- /* Decoder */
- /* -------------------------------------------------------------------- */
- enum {
- J2K_STATE_START = 0,
- J2K_STATE_DECODING = 1,
- J2K_STATE_DONE = 2,
- J2K_STATE_FAILED = 3,
- };
- static int
- j2k_decode_entry(Imaging im, ImagingCodecState state)
- {
- JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
- opj_stream_t *stream = NULL;
- opj_image_t *image = NULL;
- opj_codec_t *codec = NULL;
- opj_dparameters_t params;
- OPJ_COLOR_SPACE color_space;
- j2k_unpacker_t unpack = NULL;
- size_t buffer_size = 0;
- unsigned n;
- stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
- if (!stream) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- opj_stream_set_read_function(stream, j2k_read);
- opj_stream_set_skip_function(stream, j2k_skip);
- /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
- #ifndef OPJ_VERSION_MAJOR
- opj_stream_set_user_data(stream, state);
- #else
- opj_stream_set_user_data(stream, state, NULL);
- /* Hack: if we don't know the length, the largest file we can
- possibly support is 4GB. We can't go larger than this, because
- OpenJPEG truncates this value for the final box in the file, and
- the box lengths in OpenJPEG are currently 32 bit. */
- if (context->length < 0)
- opj_stream_set_user_data_length(stream, 0xffffffff);
- else
- opj_stream_set_user_data_length(stream, context->length);
- #endif
- /* Setup decompression context */
- context->error_msg = NULL;
- opj_set_default_decoder_parameters(¶ms);
- params.cp_reduce = context->reduce;
- params.cp_layer = context->layers;
- codec = opj_create_decompress(context->format);
- if (!codec) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- opj_set_error_handler(codec, j2k_error, context);
- opj_setup_decoder(codec, ¶ms);
- if (!opj_read_header(stream, codec, &image)) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- /* Check that this image is something we can handle */
- if (image->numcomps < 1 || image->numcomps > 4
- || image->color_space == OPJ_CLRSPC_UNKNOWN) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- for (n = 1; n < image->numcomps; ++n) {
- if (image->comps[n].dx != 1 || image->comps[n].dy != 1) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- }
- /*
- Colorspace Number of components PIL mode
- ------------------------------------------------------
- sRGB 3 RGB
- sRGB 4 RGBA
- gray 1 L or I
- gray 2 LA
- YCC 3 YCbCr
- If colorspace is unspecified, we assume:
- Number of components Colorspace
- -----------------------------------------
- 1 gray
- 2 gray (+ alpha)
- 3 sRGB
- 4 sRGB (+ alpha)
- */
- /* Find the correct unpacker */
- color_space = image->color_space;
- if (color_space == OPJ_CLRSPC_UNSPECIFIED) {
- switch (image->numcomps) {
- case 1: case 2: color_space = OPJ_CLRSPC_GRAY; break;
- case 3: case 4: color_space = OPJ_CLRSPC_SRGB; break;
- }
- }
- for (n = 0; n < sizeof(j2k_unpackers) / sizeof (j2k_unpackers[0]); ++n) {
- if (color_space == j2k_unpackers[n].color_space
- && image->numcomps == j2k_unpackers[n].components
- && strcmp (im->mode, j2k_unpackers[n].mode) == 0) {
- unpack = j2k_unpackers[n].unpacker;
- break;
- }
- }
- if (!unpack) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- /* Decode the image tile-by-tile; this means we only need use as much
- memory as is required for one tile's worth of components. */
- for (;;) {
- JPEG2KTILEINFO tile_info;
- OPJ_BOOL should_continue;
- unsigned correction = (1 << params.cp_reduce) - 1;
- if (!opj_read_tile_header(codec,
- stream,
- &tile_info.tile_index,
- &tile_info.data_size,
- &tile_info.x0, &tile_info.y0,
- &tile_info.x1, &tile_info.y1,
- &tile_info.nb_comps,
- &should_continue)) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- if (!should_continue)
- break;
- /* Adjust the tile co-ordinates based on the reduction (OpenJPEG
- doesn't do this for us) */
- tile_info.x0 = (tile_info.x0 + correction) >> context->reduce;
- tile_info.y0 = (tile_info.y0 + correction) >> context->reduce;
- tile_info.x1 = (tile_info.x1 + correction) >> context->reduce;
- tile_info.y1 = (tile_info.y1 + correction) >> context->reduce;
- if (buffer_size < tile_info.data_size) {
- /* malloc check ok, tile_info.data_size from openjpeg */
- UINT8 *new = realloc (state->buffer, tile_info.data_size);
- if (!new) {
- state->errcode = IMAGING_CODEC_MEMORY;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- state->buffer = new;
- buffer_size = tile_info.data_size;
- }
- if (!opj_decode_tile_data(codec,
- tile_info.tile_index,
- (OPJ_BYTE *)state->buffer,
- tile_info.data_size,
- stream)) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- /* Check the tile bounds; if the tile is outside the image area,
- or if it has a negative width or height (i.e. the coordinates are
- swapped), bail. */
- if (tile_info.x0 >= tile_info.x1
- || tile_info.y0 >= tile_info.y1
- || tile_info.x0 < image->x0
- || tile_info.y0 < image->y0
- || tile_info.x1 - image->x0 > im->xsize
- || tile_info.y1 - image->y0 > im->ysize) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- unpack(image, &tile_info, state->buffer, im);
- }
- if (!opj_end_decompress(codec, stream)) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- goto quick_exit;
- }
- state->state = J2K_STATE_DONE;
- state->errcode = IMAGING_CODEC_END;
- if (context->pfile) {
- if(fclose(context->pfile)){
- context->pfile = NULL;
- }
- }
- quick_exit:
- if (codec)
- opj_destroy_codec(codec);
- if (image)
- opj_image_destroy(image);
- if (stream)
- opj_stream_destroy(stream);
- return -1;
- }
- int
- ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
- {
- if (bytes){
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- return -1;
- }
- if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED)
- return -1;
- if (state->state == J2K_STATE_START) {
- state->state = J2K_STATE_DECODING;
- return j2k_decode_entry(im, state);
- }
- if (state->state == J2K_STATE_DECODING) {
- state->errcode = IMAGING_CODEC_BROKEN;
- state->state = J2K_STATE_FAILED;
- return -1;
- }
- return -1;
- }
- /* -------------------------------------------------------------------- */
- /* Cleanup */
- /* -------------------------------------------------------------------- */
- int
- ImagingJpeg2KDecodeCleanup(ImagingCodecState state) {
- JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *)state->context;
- if (context->error_msg) {
- free ((void *)context->error_msg);
- }
- context->error_msg = NULL;
- return -1;
- }
- const char *
- ImagingJpeg2KVersion(void)
- {
- return opj_version();
- }
- #endif /* HAVE_OPENJPEG */
- /*
- * Local Variables:
- * c-basic-offset: 4
- * End:
- *
- */
|