summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Rasmussen <sebras@gmail.com>2016-06-21 10:32:11 +0200
committerSebastian Rasmussen <sebras@gmail.com>2016-07-06 11:52:22 +0800
commitb03381add14f1c22662402d581024308335ec4f9 (patch)
tree94f9b37c370b70829caaed872a4a0230ab893e01
parent10c8945851bf76bd22601411d2708fe2ff1bbea6 (diff)
downloadmupdf-b03381add14f1c22662402d581024308335ec4f9.tar.xz
Add optional support for Luratech JPEG2000 decoder.
-rw-r--r--Makethird161
-rw-r--r--docs/thirdparty.txt3
-rw-r--r--source/fitz/load-jpx.c480
3 files changed, 590 insertions, 54 deletions
diff --git a/Makethird b/Makethird
index 6e0d4c45..c1672f75 100644
--- a/Makethird
+++ b/Makethird
@@ -175,7 +175,7 @@ endif
# --- LURATECH ---
-ifneq "$(wildcard $(LURATECH_DIR)/ldf_jb2)" ""
+ifneq "$(wildcard $(LURATECH_DIR)/ldf_jb2)$(wildcard $(LURATECH_DIR)/lwf_jp2)" ""
LURATECH_OUT := $(OUT)/luratech
LURATECH_SRC := \
@@ -248,7 +248,63 @@ LURATECH_SRC := \
jb2_adt_write_data.c \
jb2_adt_write_pdf.c \
jb2_common.c \
- jb2_license_dummy.c
+ jb2_license_dummy.c \
+ jp2_adt_band_array.c \
+ jp2_adt_band_buffer.c \
+ jp2_adt_block_array.c \
+ jp2_adt_cache.c \
+ jp2_adt_comp.c \
+ jp2_adt_component_array.c \
+ jp2_adt_decomp.c \
+ jp2_adt_ebcot_decoder.c \
+ jp2_adt_external_cache.c \
+ jp2_adt_image.c \
+ jp2_adt_memory.c \
+ jp2_adt_mq_decoder.c \
+ jp2_adt_mq_state.c \
+ jp2_adt_packet_decoder.c \
+ jp2_adt_precinct_array.c \
+ jp2_adt_rate.c \
+ jp2_adt_rate_list.c \
+ jp2_adt_read_bits.c \
+ jp2_adt_read_data.c \
+ jp2_adt_reader_requirements.c \
+ jp2_adt_resolution_array.c \
+ jp2_adt_tile_array.c \
+ jp2_adt_tlm_marker_array.c \
+ jp2_adt_write_data.c \
+ jp2_buffer.c \
+ jp2c_code_cb.c \
+ jp2c_coder.c \
+ jp2c_codestream.c \
+ jp2c_file_format.c \
+ jp2c_format.c \
+ jp2c_memory.c \
+ jp2_code_cb.c \
+ jp2_common.c \
+ jp2c_progression.c \
+ jp2c_quant.c \
+ jp2c_wavelet.c \
+ jp2c_wavelet_lifting.c \
+ jp2c_weights.c \
+ jp2c_write.c \
+ jp2d_codestream.c \
+ jp2d_decoder.c \
+ jp2d_file_format.c \
+ jp2d_format.c \
+ jp2d_image.c \
+ jp2d_memory.c \
+ jp2d_partial_decoding.c \
+ jp2d_progression.c \
+ jp2d_quant.c \
+ jp2d_scale.c \
+ jp2d_wavelet.c \
+ jp2d_wavelet_lifting.c \
+ jp2d_write.c \
+ jp2_icc.c \
+ jp2_license.c \
+ jp2_packet.c \
+ jp2_tag_tree.c
LURATECH_OBJ := $(addprefix $(LURATECH_OUT)/, $(LURATECH_SRC:%.c=%.o))
@@ -256,24 +312,23 @@ $(LURATECH_OUT):
$(MKDIR_CMD)
$(LURATECH_OUT)/%.o: $(LURATECH_DIR)/ldf_jb2/source/common/%.c | $(LURATECH_OUT)
$(CC_CMD) \
- -I$(LURATECH_DIR)/ldf_jb2/source/libraries \
- -I$(LURATECH_DIR)/ldf_jb2/source/compress \
-I$(LURATECH_DIR)/ldf_jb2/source/common \
-DLINUX
$(LURATECH_OUT)/%.o: $(LURATECH_DIR)/ldf_jb2/source/compress/%.c | $(LURATECH_OUT)
$(CC_CMD) \
- -I$(LURATECH_DIR)/ldf_jb2/source/libraries \
- -I$(LURATECH_DIR)/ldf_jb2/source/compress \
-I$(LURATECH_DIR)/ldf_jb2/source/common \
-DLINUX
-$(LURATECH_OUT)/%.o: $(LURATECH_DIR)/lwf_jp2/%.c | $(LURATECH_OUT)
+$(LURATECH_OUT)/%.o: $(LURATECH_DIR)/lwf_jp2/library/source/%.c | $(LURATECH_OUT)
$(CC_CMD) \
- -I$(LURATECH_DIR)/ldf_jb2/source/libraries \
- -I$(LURATECH_DIR)/ldf_jb2/source/compress \
-I$(LURATECH_DIR)/ldf_jb2/source/common \
-DLINUX
-LURATECH_CFLAGS := -I$(LURATECH_DIR)/ldf_jb2/source/libraries -DHAVE_LURATECH
+LURATECH_CFLAGS := \
+-I$(LURATECH_DIR)/ldf_jb2/source/common \
+ -I$(LURATECH_DIR)/ldf_jb2/source/libraries \
+ -I$(LURATECH_DIR)/ldf_jb2/source/compress \
+ -I$(LURATECH_DIR)/lwf_jp2/library/source \
+ -DHAVE_LURATECH
else # --- LURATECH ---
@@ -312,6 +367,49 @@ JBIG2DEC_CFLAGS := $(SYS_JBIG2DEC_CFLAGS)
JBIG2DEC_LIBS := $(SYS_JBIG2DEC_LIBS)
endif
+# --- OpenJPEG ---
+
+ifneq "$(wildcard $(OPENJPEG_DIR)/CMakeLists.txt)" ""
+
+OPENJPEG_OUT := $(OUT)/openjpeg
+OPENJPEG_SRC := \
+ bio.c \
+ cidx_manager.c \
+ cio.c \
+ dwt.c \
+ event.c \
+ function_list.c \
+ image.c \
+ invert.c \
+ j2k.c \
+ jp2.c \
+ mct.c \
+ mqc.c \
+ openjpeg.c \
+ phix_manager.c \
+ pi.c \
+ ppix_manager.c \
+ raw.c \
+ t1.c \
+ t2.c \
+ tcd.c \
+ tgt.c \
+ thix_manager.c \
+ tpix_manager.c \
+
+OPENJPEG_OBJ := $(addprefix $(OPENJPEG_OUT)/, $(OPENJPEG_SRC:%.c=%.o))
+
+$(OPENJPEG_OUT):
+ $(MKDIR_CMD)
+$(OPENJPEG_OUT)/%.o: $(OPENJPEG_DIR)/%.c | $(OPENJPEG_OUT)
+ $(CC_CMD) -DOPJ_STATIC -DOPJ_HAVE_STDINT_H
+
+OPENJPEG_CFLAGS += -I$(OPENJPEG_DIR) -DOPJ_HAVE_INTTYPES_H=1 -DUSE_JPIP=1
+else
+OPENJPEG_CFLAGS := $(SYS_OPENJPEG_CFLAGS)
+OPENJPEG_LIBS := $(SYS_OPENJPEG_LIBS)
+endif
+
endif # --- LURATECH ---
# --- JPEG library from IJG ---
@@ -364,49 +462,6 @@ JPEG_CFLAGS := $(SYS_JPEG_CFLAGS) -DSHARE_JPEG
JPEG_LIBS := $(SYS_JPEG_LIBS)
endif
-# --- OpenJPEG ---
-
-ifneq "$(wildcard $(OPENJPEG_DIR)/CMakeLists.txt)" ""
-
-OPENJPEG_OUT := $(OUT)/openjpeg
-OPENJPEG_SRC := \
- bio.c \
- cidx_manager.c \
- cio.c \
- dwt.c \
- event.c \
- function_list.c \
- image.c \
- invert.c \
- j2k.c \
- jp2.c \
- mct.c \
- mqc.c \
- openjpeg.c \
- phix_manager.c \
- pi.c \
- ppix_manager.c \
- raw.c \
- t1.c \
- t2.c \
- tcd.c \
- tgt.c \
- thix_manager.c \
- tpix_manager.c \
-
-OPENJPEG_OBJ := $(addprefix $(OPENJPEG_OUT)/, $(OPENJPEG_SRC:%.c=%.o))
-
-$(OPENJPEG_OUT):
- $(MKDIR_CMD)
-$(OPENJPEG_OUT)/%.o: $(OPENJPEG_DIR)/%.c | $(OPENJPEG_OUT)
- $(CC_CMD) -DOPJ_STATIC -DOPJ_HAVE_STDINT_H
-
-OPENJPEG_CFLAGS += -I$(OPENJPEG_DIR) -DOPJ_HAVE_INTTYPES_H=1 -DUSE_JPIP=1
-else
-OPENJPEG_CFLAGS := $(SYS_OPENJPEG_CFLAGS)
-OPENJPEG_LIBS := $(SYS_OPENJPEG_LIBS)
-endif
-
# --- ZLIB ---
ifneq "$(wildcard $(ZLIB_DIR)/README)" ""
diff --git a/docs/thirdparty.txt b/docs/thirdparty.txt
index 491d76ee..e8dce82b 100644
--- a/docs/thirdparty.txt
+++ b/docs/thirdparty.txt
@@ -29,6 +29,9 @@ zlib 1.2.7 (De)Flate zlib License http://www.zlib.net/
curl 7.31.0 HTTP data MIT-style http://curl.haxx.se/
transfer
+Luratech JP2 JPEG 2000 commercial http://www.luratech.com/
+ decoding
+
Luratech JBIG2 JBIG2 commercial http://www.luratech.com/
decoding
diff --git a/source/fitz/load-jpx.c b/source/fitz/load-jpx.c
index c1ed831a..a79a268e 100644
--- a/source/fitz/load-jpx.c
+++ b/source/fitz/load-jpx.c
@@ -1,5 +1,480 @@
#include "mupdf/fitz.h"
+#ifdef HAVE_LURATECH
+
+#include <lwf_jp2.h>
+
+typedef struct fz_jpxd_s fz_jpxd;
+
+struct fz_jpxd_s
+{
+ JP2_Decomp_Handle doc;
+ fz_context *ctx;
+ fz_pixmap *pix;
+ JP2_Palette_Params *palette;
+ JP2_Colorspace colorspace;
+ unsigned char *data;
+ int size;
+ JP2_Property_Value width;
+ JP2_Property_Value height;
+ fz_colorspace *cs;
+ int expand_indexed;
+ unsigned long xres;
+ unsigned long yres;
+
+ JP2_Property_Value nchans;
+ JP2_Property_Value *widths;
+ JP2_Property_Value *heights;
+ JP2_Property_Value *hstep;
+ JP2_Property_Value *vstep;
+ JP2_Property_Value *bpss;
+ JP2_Property_Value *signs;
+};
+
+static void * JP2_Callback_Conv
+jpx_alloc(long size, JP2_Callback_Param param)
+{
+ fz_jpxd *state = (fz_jpxd *) param;
+ return fz_malloc(state->ctx, size);
+}
+
+static JP2_Error JP2_Callback_Conv
+jpx_free(void *ptr, JP2_Callback_Param param)
+{
+ fz_jpxd *state = (fz_jpxd *) param;
+ fz_free(state->ctx, ptr);
+ return cJP2_Error_OK;
+}
+
+static unsigned long JP2_Callback_Conv
+jpx_read(unsigned char *pucData,
+ unsigned long ulPos, unsigned long ulSize,
+ JP2_Callback_Param param)
+{
+ fz_jpxd *state = (fz_jpxd *) param;
+
+ if (ulPos < 0 || ulPos >= state->size)
+ return 0;
+
+ ulSize = fz_mini(ulSize, state->size - ulPos);
+ memcpy(pucData, &state->data[ulPos], ulSize);
+ return ulSize;
+}
+
+static JP2_Error JP2_Callback_Conv
+jpx_write(unsigned char * pucData, short sComponent, unsigned long ulRow,
+ unsigned long ulStart, unsigned long ulNum, JP2_Callback_Param param)
+{
+ fz_jpxd *state = (fz_jpxd *) param;
+ unsigned char *row;
+ int x, y, i;
+
+ if (ulRow >= state->pix->h || ulStart >= state->pix->w || sComponent >= state->pix->n)
+ return cJP2_Error_OK;
+
+ ulNum = fz_mini(ulNum, state->pix->w - ulStart);
+
+ if (state->palette)
+ {
+
+ row = &state->pix->samples[state->pix->stride * ulRow * state->vstep[sComponent] +
+ state->pix->n * ulStart * state->hstep[sComponent] +
+ sComponent];
+
+ for (y = 0; ulRow * state->vstep[sComponent] + y < state->pix->h && y < state->vstep[sComponent]; y++)
+ {
+ unsigned char *p = row;
+
+ for (i = 0; i < ulNum; i++)
+ {
+ for (x = 0; (ulStart + i) * state->hstep[sComponent] + x < state->pix->w && x < state->hstep[sComponent]; x++)
+ {
+ unsigned char v = fz_clampi(pucData[i], 0, state->palette->ulEntries);
+
+ if (state->expand_indexed)
+ {
+ int k;
+ for (k = 0; k < state->pix->n; k++)
+ p[k] = state->palette->ppulPalette[k][v];
+ p += state->pix->n;
+ }
+ else
+ {
+ *p= v;
+ p++;
+ }
+ }
+ }
+
+ row += state->pix->stride;
+ }
+ }
+ else
+ {
+ unsigned int signedoffset;
+
+ if (state->signs[sComponent])
+ signedoffset = 1 << (state->bpss[sComponent] - 1);
+ else
+ signedoffset = 0;
+
+ row = &state->pix->samples[state->pix->stride * ulRow * state->vstep[sComponent] +
+ state->pix->n * ulStart * state->hstep[sComponent] +
+ sComponent];
+
+ if (state->bpss[sComponent] > 8)
+ {
+ for (y = 0; ulRow * state->vstep[sComponent] + y < state->pix->h && y < state->vstep[sComponent]; y++)
+ {
+ unsigned char *p = row;
+
+ for (i = 0; i < ulNum; i++)
+ {
+ for (x = 0; (ulStart + i) * state->hstep[sComponent] + x < state->pix->w && x < state->hstep[sComponent]; x++)
+ {
+ unsigned int v = (pucData[2 * i + 1] << 8) | pucData[2 * i + 0];
+ v &= (1 << state->bpss[sComponent]) - 1;
+ v -= signedoffset;
+ *p = v >> (state->bpss[sComponent] - 8);
+ p += state->pix->n;
+ }
+ }
+
+ row += state->pix->stride;
+ }
+ }
+ else if (state->bpss[sComponent] == 8)
+ {
+ for (y = 0; ulRow * state->vstep[sComponent] + y < state->pix->h && y < state->vstep[sComponent]; y++)
+ {
+ unsigned char *p = row;
+
+ for (i = 0; i < ulNum; i++)
+ {
+ for (x = 0; (ulStart + i) * state->hstep[sComponent] + x < state->pix->w && x < state->hstep[sComponent]; x++)
+ {
+ unsigned int v = pucData[i];
+ v &= (1 << state->bpss[sComponent]) - 1;
+ v -= signedoffset;
+ *p = v;
+ p += state->pix->n;
+ }
+ }
+
+ row += state->pix->stride;
+ }
+ }
+ else
+ {
+ for (y = 0; ulRow * state->vstep[sComponent] + y < state->pix->h && y < state->vstep[sComponent]; y++)
+ {
+ unsigned char *p = row;
+
+ for (i = 0; i < ulNum; i++)
+ {
+ for (x = 0; (ulStart + i) * state->hstep[sComponent] + x < state->pix->w && x < state->hstep[sComponent]; x++)
+ {
+ unsigned int v = pucData[i];
+ v &= (1 << state->bpss[sComponent]) - 1;
+ v -= signedoffset;
+ *p = v << (8 - state->bpss[sComponent]);
+ p += state->pix->n;
+ }
+ }
+
+ row += state->pix->stride;
+ }
+ }
+ }
+
+ return cJP2_Error_OK;
+}
+
+static void
+jpx_ycc_to_rgb(fz_context *ctx, fz_jpxd *state)
+{
+ int x, y;
+
+ for (y = 0; y < state->height; y++)
+ {
+ unsigned char * row = &state->pix->samples[state->pix->stride * y];
+ for (x = 0; x < state->width; x++)
+ {
+ int ycc[3];
+ ycc[0] = row[x * 3 + 0];
+ ycc[1] = row[x * 3 + 1];
+ ycc[2] = row[x * 3 + 2];
+
+ /* conciously skip Y */
+ if (!state->signs[1])
+ ycc[1] -= 128;
+ if (!state->signs[2])
+ ycc[2] -= 128;
+
+ row[x * 3 + 0] = fz_clampi((double)ycc[0] + 1.402 * ycc[2], 0, 255);
+ row[x * 3 + 1] = fz_clampi((double)ycc[0] - 0.34413 * ycc[1] - 0.71414 * ycc[2], 0, 255);
+ row[x * 3 + 2] = fz_clampi((double)ycc[0] + 1.772 * ycc[1], 0, 255);
+ }
+ }
+
+}
+
+struct indexed
+{
+ fz_colorspace *base;
+ int high;
+ unsigned char *lookup;
+};
+
+static fz_pixmap *
+jpx_read_image(fz_context *ctx, fz_jpxd *state, unsigned char *data, size_t size, fz_colorspace *defcs, int indexed, int onlymeta)
+{
+ JP2_Channel_Def_Params *chans = NULL;
+ JP2_Error err;
+ int k, colors, alphas, prealphas;
+
+ memset(state, 0x00, sizeof (fz_jpxd));
+ state->ctx = ctx;
+ state->data = data;
+ state->size = size;
+
+ fz_try(ctx)
+ {
+ err = JP2_Decompress_Start(&state->doc,
+ jpx_alloc, (JP2_Callback_Param) state,
+ jpx_free, (JP2_Callback_Param) state,
+ jpx_read, (JP2_Callback_Param) state);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open image: %d", (int) err);
+
+#if defined(JP2_LICENSE_NUM_1) && defined(JP2_LICENSE_NUM_2)
+ err = JP2_Document_SetLicense(state->doc, JP2_LICENSE_NUM_1, JP2_LICENSE_NUM_2);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set license: %d", (int) err);
+#endif
+
+ err = JP2_Decompress_GetProp(state->doc, cJP2_Prop_Extern_Colorspace, (unsigned long *) &state->colorspace, -1, -1);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get colorspace: %d", (int) err);
+
+ if (state->colorspace == cJP2_Colorspace_Palette_Gray ||
+ state->colorspace == cJP2_Colorspace_Palette_RGBa ||
+ state->colorspace == cJP2_Colorspace_Palette_RGB_YCCa ||
+ state->colorspace == cJP2_Colorspace_Palette_CIE_LABa ||
+ state->colorspace == cJP2_Colorspace_Palette_ICCa ||
+ state->colorspace == cJP2_Colorspace_Palette_CMYKa)
+ {
+ err = JP2_Decompress_GetPalette(state->doc, &state->palette);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get indexed palette: %d", (int) err);
+
+ /* no available sample file */
+ for (k = 0; k < state->palette->ulChannels; k++)
+ if (state->palette->pucSignedSample[k])
+ fz_throw(ctx, FZ_ERROR_GENERIC, "signed palette compoments not yet supported");
+ }
+
+ err = JP2_Decompress_GetChannelDefs(state->doc, &chans, &state->nchans);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get channel definitions: %d", (int) err);
+
+ colors = 0;
+ alphas = 0;
+ prealphas = 0;
+ for (k = 0; k < state->nchans; k++)
+ {
+ switch (chans[k].ulType)
+ {
+ case cJP2_Channel_Type_Color: colors++; break;
+ case cJP2_Channel_Type_Opacity: alphas++; break;
+ case cJP2_Channel_Type_Opacity_Pre: prealphas++; break;
+ }
+ }
+
+ if (prealphas> 0)
+ alphas = prealphas;
+ colors = fz_clampi(colors, 0, 4);
+ alphas = fz_clampi(alphas, 0, 1);
+
+ state->nchans = colors + alphas;
+
+ state->widths = fz_malloc(ctx, state->nchans * sizeof (JP2_Property_Value));
+ state->heights = fz_malloc(ctx, state->nchans * sizeof (JP2_Property_Value));
+ state->hstep = fz_malloc(ctx, state->nchans * sizeof (JP2_Property_Value));
+ state->vstep = fz_malloc(ctx, state->nchans * sizeof (JP2_Property_Value));
+ state->bpss = fz_malloc(ctx, state->nchans * sizeof (JP2_Property_Value));
+ state->signs = fz_malloc(ctx, state->nchans * sizeof (JP2_Property_Value));
+
+ if (state->palette)
+ {
+ err = JP2_Decompress_GetProp(state->doc, cJP2_Prop_Width, &state->width, -1, 0);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get width for palette indicies: %d", (int) err);
+ err = JP2_Decompress_GetProp(state->doc, cJP2_Prop_Height, &state->height, -1, 0);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get height for palette indicies: %d", (int) err);
+
+ for (k = 0; k < state->nchans; k++)
+ {
+ state->widths[k] = state->width;
+ state->heights[k] = state->height;
+ state->bpss[k] = state->palette->pucBitsPerSample[k];
+ state->signs[k] = state->palette->pucSignedSample[k];
+ }
+ }
+ else
+ {
+ for (k = 0; k < state->nchans; k++)
+ {
+ err = JP2_Decompress_GetProp(state->doc, cJP2_Prop_Width, &state->widths[k], -1, k);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get width for compoment %d: %d", k, (int) err);
+ err = JP2_Decompress_GetProp(state->doc, cJP2_Prop_Height, &state->heights[k], -1, k);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get height for compomment %d: %d", k, (int) err);
+ err = JP2_Decompress_GetProp(state->doc, cJP2_Prop_Bits_Per_Sample, &state->bpss[k], -1, k);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get bits per sample for compomment %d: %d", k, (int) err);
+ err = JP2_Decompress_GetProp(state->doc, cJP2_Prop_Signed_Samples, &state->signs[k], -1, k);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get signed for compomment %d: %d", k, (int) err);
+
+ state->width = fz_maxi(state->width, state->widths[k]);
+ state->height = fz_maxi(state->height, state->heights[k]);
+ }
+ }
+
+ for (k = 0; k < state->nchans; k++)
+ {
+ state->hstep[k] = (state->width + (state->widths[k] - 1)) / state->widths[k];
+ state->vstep[k] = (state->height + (state->heights[k] - 1)) / state->heights[k];
+ }
+
+ err = JP2_Decompress_GetResolution(state->doc, &state->yres, &state->xres, NULL,
+ cJP2_Resolution_Dots_Per_Inch, cJP2_Resolution_Capture);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get resolution: %d", (int) err);
+
+ if (state->xres == 0 || state->yres == 0)
+ state->xres = state->yres = 72;
+
+ if (defcs)
+ {
+ if (defcs->n == state->nchans)
+ {
+ state->cs = defcs;
+ }
+ else
+ {
+ fz_warn(ctx, "jpx file (%lu) and dict colorspace (%d, %s) do not match", state->nchans, defcs->n, defcs->name);
+ defcs = NULL;
+ }
+ }
+
+ if (!defcs)
+ {
+ switch (colors)
+ {
+ case 4: state->cs = fz_device_cmyk(ctx); break;
+ case 3: if (state->colorspace == cJP2_Colorspace_CIE_LABa)
+ state->cs = fz_device_lab(ctx);
+ else
+ state->cs = fz_device_rgb(ctx);
+ break;
+ case 1: state->cs = fz_device_gray(ctx); break;
+ case 0: if (alphas == 1)
+ {
+ /* alpha only images are rendered as grayscale */
+ state->cs = fz_device_gray(ctx);
+ colors = 1;
+ alphas = 0;
+ break;
+ }
+ /* fallthrough */
+ default: fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported number of components: %lu", state->nchans);
+ }
+ }
+
+ if (state->palette && !fz_colorspace_is_indexed(ctx, state->cs))
+ state->expand_indexed = 1;
+
+ if (!onlymeta)
+ {
+ state->pix = fz_new_pixmap(ctx, state->cs, state->width, state->height, alphas);
+ fz_clear_pixmap_with_value(ctx, state->pix, 0);
+
+ err = JP2_Decompress_SetProp(state->doc, cJP2_Prop_Output_Parameter, (JP2_Property_Value) state);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set write callback userdata: %d", (int) err);
+ err = JP2_Decompress_SetProp(state->doc, cJP2_Prop_Output_Function, (JP2_Property_Value) jpx_write);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set write callback: %d", (int) err);
+
+ err = JP2_Decompress_Image(state->doc);
+ if (err != cJP2_Error_OK)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot decode image: %d", (int) err);
+
+ if (state->colorspace == cJP2_Colorspace_RGB_YCCa)
+ jpx_ycc_to_rgb(ctx, state);
+
+ if (state->pix->alpha && ! (state->palette && !state->expand_indexed))
+ {
+ if (state->pix->n == 5)
+ {
+ fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb(ctx), state->pix->w, state->pix->h, 1);
+ fz_convert_pixmap(ctx, tmp, state->pix);
+ fz_drop_pixmap(ctx, state->pix);
+ state->pix = tmp;
+ }
+
+ if (alphas > 0 && prealphas == 0)
+ fz_premultiply_pixmap(ctx, state->pix);
+ }
+
+ }
+ }
+ fz_always(ctx)
+ {
+ JP2_Decompress_End(state->doc);
+ fz_free(ctx, state->signs);
+ fz_free(ctx, state->widths);
+ fz_free(ctx, state->heights);
+ fz_free(ctx, state->hstep);
+ fz_free(ctx, state->vstep);
+ fz_free(ctx, state->bpss);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+
+ return state->pix;
+}
+
+fz_pixmap *
+fz_load_jpx(fz_context *ctx, unsigned char *data, size_t size, fz_colorspace *defcs, int indexed)
+{
+ fz_jpxd state = { 0 };
+
+ return jpx_read_image(ctx, &state, data, size, defcs, indexed, 0);
+}
+
+void
+fz_load_jpx_info(fz_context *ctx, unsigned char *data, size_t size, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
+{
+ fz_jpxd state = { 0 };
+
+ jpx_read_image(ctx, &state, data, size, NULL, 0, 1);
+
+ *cspacep = state.cs;
+ *wp = state.width;
+ *hp = state.height;
+ *xresp = state.xres;
+ *yresp = state.yres;
+}
+
+#else /* HAVE_LURATECH */
+
/* Without the definition of OPJ_STATIC, compilation fails on windows
* due to the use of __stdcall. We believe it is required on some
* linux toolchains too. */
@@ -185,7 +660,7 @@ jpx_read_image(fz_context *ctx, unsigned char *data, size_t size, fz_colorspace
}
else
{
- fz_warn(ctx, "jpx file and dict colorspaces do not match");
+ fz_warn(ctx, "jpx file and dict colorspace do not match");
defcs = NULL;
}
}
@@ -197,6 +672,7 @@ jpx_read_image(fz_context *ctx, unsigned char *data, size_t size, fz_colorspace
case 1: colorspace = fz_device_gray(ctx); break;
case 3: colorspace = fz_device_rgb(ctx); break;
case 4: colorspace = fz_device_cmyk(ctx); break;
+ default: fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported number of components: %d", n);
}
}
@@ -268,3 +744,5 @@ fz_load_jpx_info(fz_context *ctx, unsigned char *data, size_t size, int *wp, int
*xresp = 72; /* openjpeg does not read the JPEG 2000 resc box */
*yresp = 72; /* openjpeg does not read the JPEG 2000 resc box */
}
+
+#endif /* HAVE_LURATECH */