mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			829 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			829 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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, int 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:
 | 
						|
 *
 | 
						|
 */
 |