forked from old/legacy-imlib2
288 lines
7.0 KiB
C
288 lines
7.0 KiB
C
#include "loader_common.h"
|
|
|
|
#include <openjpeg.h>
|
|
|
|
#define DBG_PFX "LDR-j2k"
|
|
|
|
#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
|
|
#define JP2_MAGIC "\x0d\x0a\x87\x0a"
|
|
/* position 45: "\xff\x52" */
|
|
#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
|
|
|
|
#if IMLIB2_DEBUG
|
|
static void
|
|
_j2k_cb(const char *type, const char *msg, void *data)
|
|
{
|
|
DL("%s: %p: %s: %s", __func__, data, type, msg);
|
|
}
|
|
|
|
static void
|
|
_j2k_cb_info(const char *msg, void *data)
|
|
{
|
|
_j2k_cb("info", msg, data);
|
|
}
|
|
|
|
static void
|
|
_j2k_cb_warn(const char *msg, void *data)
|
|
{
|
|
_j2k_cb("warn", msg, data);
|
|
}
|
|
|
|
static void
|
|
_j2k_cb_err(const char *msg, void *data)
|
|
{
|
|
_j2k_cb("err", msg, data);
|
|
}
|
|
#endif /*IMLIB2_DEBUG */
|
|
|
|
static struct {
|
|
const unsigned char *data, *dptr;
|
|
unsigned int size;
|
|
} mdata;
|
|
|
|
static void
|
|
mm_init(const void *src, unsigned int size)
|
|
{
|
|
mdata.data = mdata.dptr = src;
|
|
mdata.size = size;
|
|
}
|
|
|
|
static OPJ_SIZE_T
|
|
mm_read(void *dst, OPJ_SIZE_T len, void *data)
|
|
{
|
|
DL("%s: len=%ld\n", __func__, len);
|
|
|
|
if (mdata.dptr >= mdata.data + mdata.size)
|
|
return -1; /* Out of data */
|
|
if (mdata.dptr + len > mdata.data + mdata.size)
|
|
len = mdata.data + mdata.size - mdata.dptr;
|
|
|
|
memcpy(dst, mdata.dptr, len);
|
|
mdata.dptr += len;
|
|
|
|
return len;
|
|
}
|
|
|
|
static OPJ_OFF_T
|
|
mm_seek_cur(OPJ_OFF_T offs, void *data)
|
|
{
|
|
DL("%s: offs=%ld\n", __func__, offs);
|
|
|
|
if (mdata.dptr + offs > mdata.data + mdata.size)
|
|
return 0; /* Out of data */
|
|
|
|
mdata.dptr += offs;
|
|
|
|
return mdata.dptr - mdata.data;
|
|
}
|
|
|
|
static OPJ_BOOL
|
|
mm_seek_set(OPJ_OFF_T offs, void *data)
|
|
{
|
|
DL("%s: offs=%ld\n", __func__, offs);
|
|
|
|
if (offs > mdata.size)
|
|
return OPJ_FALSE; /* Out of data */
|
|
|
|
mdata.dptr = mdata.data + offs;
|
|
|
|
return OPJ_TRUE;
|
|
}
|
|
|
|
int
|
|
load2(ImlibImage * im, int load_data)
|
|
{
|
|
int rc;
|
|
void *fdata;
|
|
int ok;
|
|
opj_dparameters_t jparam;
|
|
opj_codec_t *jcodec;
|
|
opj_stream_t *jstream;
|
|
opj_image_t *jimage;
|
|
OPJ_CODEC_FORMAT jfmt;
|
|
int i, j;
|
|
uint32_t *dst;
|
|
OPJ_INT32 *pa, *pr, *pg, *pb;
|
|
unsigned char a, r, g, b;
|
|
|
|
fdata = mmap(NULL, im->fsize, PROT_READ, MAP_SHARED, fileno(im->fp), 0);
|
|
if (fdata == MAP_FAILED)
|
|
return LOAD_BADFILE;
|
|
|
|
rc = LOAD_FAIL;
|
|
jcodec = NULL;
|
|
jstream = NULL;
|
|
jimage = NULL;
|
|
|
|
/* Signature check */
|
|
if (im->fsize < 12)
|
|
goto quit;
|
|
|
|
if (memcmp(fdata, JP2_MAGIC, 4) == 0 ||
|
|
memcmp(fdata, JP2_RFC3745_MAGIC, 12) == 0)
|
|
jfmt = OPJ_CODEC_JP2;
|
|
else if (memcmp(fdata, J2K_CODESTREAM_MAGIC, 4) == 0)
|
|
jfmt = OPJ_CODEC_J2K;
|
|
else
|
|
goto quit;
|
|
|
|
DL("format=%d\n", jfmt);
|
|
|
|
memset(&jparam, 0, sizeof(opj_dparameters_t));
|
|
opj_set_default_decoder_parameters(&jparam);
|
|
|
|
jcodec = opj_create_decompress(jfmt);
|
|
if (!jcodec)
|
|
goto quit;
|
|
|
|
rc = LOAD_BADIMAGE; /* Format accepted */
|
|
|
|
#if IMLIB2_DEBUG
|
|
opj_set_info_handler(jcodec, _j2k_cb_info, NULL);
|
|
opj_set_warning_handler(jcodec, _j2k_cb_warn, NULL);
|
|
opj_set_error_handler(jcodec, _j2k_cb_err, NULL);
|
|
#endif
|
|
|
|
ok = opj_setup_decoder(jcodec, &jparam);
|
|
if (!ok)
|
|
goto quit;
|
|
|
|
// May be set with OPJ_NUM_THREADS=number or ALL_CPUS
|
|
// opj_codec_set_threads(jcodec, 4);
|
|
|
|
if (getenv("JP2_USE_FILE"))
|
|
{
|
|
jstream =
|
|
opj_stream_create_default_file_stream(im->real_file, OPJ_TRUE);
|
|
}
|
|
else
|
|
{
|
|
jstream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, OPJ_TRUE);
|
|
if (!jstream)
|
|
goto quit;
|
|
|
|
mm_init(fdata, im->fsize);
|
|
opj_stream_set_user_data(jstream, &mdata, NULL);
|
|
opj_stream_set_user_data_length(jstream, im->fsize);
|
|
opj_stream_set_read_function(jstream, mm_read);
|
|
opj_stream_set_skip_function(jstream, mm_seek_cur);
|
|
opj_stream_set_seek_function(jstream, mm_seek_set);
|
|
}
|
|
|
|
opj_read_header(jstream, jcodec, &jimage);
|
|
if (!jimage)
|
|
goto quit;
|
|
im->w = jimage->x1 - jimage->x0;
|
|
im->h = jimage->y1 - jimage->y0;
|
|
IM_FLAG_UPDATE(im, F_HAS_ALPHA,
|
|
jimage->numcomps == 4 || jimage->numcomps == 2);
|
|
D("WxH=%dx%d alpha=%d numcomp=%d colorspace=%d\n",
|
|
im->w, im->h, IM_FLAG_ISSET(im, F_HAS_ALPHA),
|
|
jimage->numcomps, jimage->color_space);
|
|
|
|
for (i = 0; i < (int)jimage->numcomps; i++)
|
|
{
|
|
DL("%d: dx/y=%d/%d wxh=%d,%d prec=%d bpp=%d sgnd=%d fact=%d\n", i,
|
|
jimage->comps[i].dx, jimage->comps[i].dy,
|
|
jimage->comps[i].w, jimage->comps[i].h,
|
|
jimage->comps[i].prec, jimage->comps[i].bpp,
|
|
jimage->comps[i].sgnd, jimage->comps[i].factor);
|
|
if (jimage->comps[0].dx != jimage->comps[i].dx ||
|
|
jimage->comps[0].dy != jimage->comps[i].dy ||
|
|
(int)jimage->comps[i].w != im->w ||
|
|
(int)jimage->comps[i].h != im->h)
|
|
goto quit;
|
|
}
|
|
|
|
if (!load_data)
|
|
QUIT_WITH_RC(LOAD_SUCCESS);
|
|
|
|
/* Load data */
|
|
|
|
ok = opj_decode(jcodec, jstream, jimage);
|
|
if (!ok)
|
|
goto quit;
|
|
|
|
ok = opj_end_decompress(jcodec, jstream);
|
|
if (!ok)
|
|
goto quit;
|
|
|
|
if (!__imlib_AllocateData(im))
|
|
QUIT_WITH_RC(LOAD_OOM);
|
|
|
|
/* Ignoring color_space and data format details... */
|
|
|
|
dst = im->data;
|
|
pa = jimage->comps[0].data; /* Avoid compiler warning */
|
|
|
|
switch (jimage->numcomps)
|
|
{
|
|
default:
|
|
goto quit;
|
|
|
|
case 4: /* RGBA */
|
|
pa = jimage->comps[3].data;
|
|
/* FALLTHROUGH */
|
|
case 3: /* RGB */
|
|
pr = jimage->comps[0].data;
|
|
pg = jimage->comps[1].data;
|
|
pb = jimage->comps[2].data;
|
|
for (i = 0; i < im->h; i++)
|
|
{
|
|
for (j = 0; j < im->w; j++)
|
|
{
|
|
r = *pr++;
|
|
g = *pg++;
|
|
b = *pb++;
|
|
a = (jimage->numcomps == 4) ? *pa++ : 0xff;
|
|
|
|
*dst++ = PIXEL_ARGB(a, r, g, b);
|
|
}
|
|
|
|
if (im->lc && __imlib_LoadProgressRows(im, i, 1))
|
|
QUIT_WITH_RC(LOAD_BREAK);
|
|
}
|
|
break;
|
|
|
|
case 2: /* Gray with A */
|
|
pa = jimage->comps[1].data;
|
|
/* FALLTHROUGH */
|
|
case 1: /* Gray */
|
|
pg = jimage->comps[0].data;
|
|
for (i = 0; i < im->h; i++)
|
|
{
|
|
for (j = 0; j < im->w; j++)
|
|
{
|
|
g = *pg++;
|
|
a = (jimage->numcomps == 2) ? *pa++ : 0xff;
|
|
|
|
*dst++ = PIXEL_ARGB(a, g, g, g);
|
|
}
|
|
|
|
if (im->lc && __imlib_LoadProgressRows(im, i, 1))
|
|
QUIT_WITH_RC(LOAD_BREAK);
|
|
}
|
|
break;
|
|
}
|
|
|
|
rc = LOAD_SUCCESS;
|
|
|
|
quit:
|
|
if (jimage)
|
|
opj_image_destroy(jimage);
|
|
if (jstream)
|
|
opj_stream_destroy(jstream);
|
|
if (jcodec)
|
|
opj_destroy_codec(jcodec);
|
|
munmap(fdata, im->fsize);
|
|
|
|
return rc;
|
|
}
|
|
|
|
void
|
|
formats(ImlibLoader * l)
|
|
{
|
|
static const char *const list_formats[] = { "jp2", "j2k" };
|
|
__imlib_LoaderSetFormats(l, list_formats, ARRAY_SIZE(list_formats));
|
|
}
|