Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7640 views
1
#include "mupdf/fitz.h"
2
3
#include <openjpeg.h>
4
5
static void fz_opj_error_callback(const char *msg, void *client_data)
6
{
7
fz_context *ctx = (fz_context *)client_data;
8
fz_warn(ctx, "openjpeg error: %s", msg);
9
}
10
11
static void fz_opj_warning_callback(const char *msg, void *client_data)
12
{
13
fz_context *ctx = (fz_context *)client_data;
14
fz_warn(ctx, "openjpeg warning: %s", msg);
15
}
16
17
static void fz_opj_info_callback(const char *msg, void *client_data)
18
{
19
/* fz_warn("openjpeg info: %s", msg); */
20
}
21
22
typedef struct stream_block_s
23
{
24
unsigned char *data;
25
int size;
26
int pos;
27
} stream_block;
28
29
static OPJ_SIZE_T fz_opj_stream_read(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data)
30
{
31
stream_block *sb = (stream_block *)p_user_data;
32
int len;
33
34
len = sb->size - sb->pos;
35
if (len < 0)
36
len = 0;
37
if (len == 0)
38
return (OPJ_SIZE_T)-1; /* End of file! */
39
if ((OPJ_SIZE_T)len > p_nb_bytes)
40
len = p_nb_bytes;
41
memcpy(p_buffer, sb->data + sb->pos, len);
42
sb->pos += len;
43
return len;
44
}
45
46
static OPJ_OFF_T fz_opj_stream_skip(OPJ_OFF_T skip, void * p_user_data)
47
{
48
stream_block *sb = (stream_block *)p_user_data;
49
50
if (skip > sb->size - sb->pos)
51
skip = sb->size - sb->pos;
52
sb->pos += skip;
53
return sb->pos;
54
}
55
56
static OPJ_BOOL fz_opj_stream_seek(OPJ_OFF_T seek_pos, void * p_user_data)
57
{
58
stream_block *sb = (stream_block *)p_user_data;
59
60
if (seek_pos > sb->size)
61
return OPJ_FALSE;
62
sb->pos = seek_pos;
63
return OPJ_TRUE;
64
}
65
66
fz_pixmap *
67
fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs, int indexed)
68
{
69
fz_pixmap *img;
70
opj_dparameters_t params;
71
opj_codec_t *codec;
72
opj_image_t *jpx;
73
opj_stream_t *stream;
74
fz_colorspace *colorspace;
75
unsigned char *p;
76
OPJ_CODEC_FORMAT format;
77
int a, n, w, h, depth, sgnd;
78
int x, y, k, v;
79
stream_block sb;
80
81
if (size < 2)
82
fz_throw(ctx, FZ_ERROR_GENERIC, "not enough data to determine image format");
83
84
/* Check for SOC marker -- if found we have a bare J2K stream */
85
if (data[0] == 0xFF && data[1] == 0x4F)
86
format = OPJ_CODEC_J2K;
87
else
88
format = OPJ_CODEC_JP2;
89
90
opj_set_default_decoder_parameters(&params);
91
if (indexed)
92
params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
93
94
codec = opj_create_decompress(format);
95
opj_set_info_handler(codec, fz_opj_info_callback, ctx);
96
opj_set_warning_handler(codec, fz_opj_warning_callback, ctx);
97
opj_set_error_handler(codec, fz_opj_error_callback, ctx);
98
if (!opj_setup_decoder(codec, &params))
99
{
100
opj_destroy_codec(codec);
101
fz_throw(ctx, FZ_ERROR_GENERIC, "j2k decode failed");
102
}
103
104
stream = opj_stream_default_create(OPJ_TRUE);
105
sb.data = data;
106
sb.pos = 0;
107
sb.size = size;
108
109
opj_stream_set_read_function(stream, fz_opj_stream_read);
110
opj_stream_set_skip_function(stream, fz_opj_stream_skip);
111
opj_stream_set_seek_function(stream, fz_opj_stream_seek);
112
opj_stream_set_user_data(stream, &sb, NULL);
113
/* Set the length to avoid an assert */
114
opj_stream_set_user_data_length(stream, size);
115
116
if (!opj_read_header(stream, codec, &jpx))
117
{
118
opj_stream_destroy(stream);
119
opj_destroy_codec(codec);
120
fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to read JPX header");
121
}
122
123
if (!opj_decode(codec, stream, jpx))
124
{
125
opj_stream_destroy(stream);
126
opj_destroy_codec(codec);
127
opj_image_destroy(jpx);
128
fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to decode JPX image");
129
}
130
131
opj_stream_destroy(stream);
132
opj_destroy_codec(codec);
133
134
/* jpx should never be NULL here, but check anyway */
135
if (!jpx)
136
fz_throw(ctx, FZ_ERROR_GENERIC, "opj_decode failed");
137
138
for (k = 1; k < (int)jpx->numcomps; k++)
139
{
140
if (!jpx->comps[k].data)
141
{
142
opj_image_destroy(jpx);
143
fz_throw(ctx, FZ_ERROR_GENERIC, "image components are missing data");
144
}
145
if (jpx->comps[k].w != jpx->comps[0].w)
146
{
147
opj_image_destroy(jpx);
148
fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different width");
149
}
150
if (jpx->comps[k].h != jpx->comps[0].h)
151
{
152
opj_image_destroy(jpx);
153
fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different height");
154
}
155
if (jpx->comps[k].prec != jpx->comps[0].prec)
156
{
157
opj_image_destroy(jpx);
158
fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different precision");
159
}
160
}
161
162
n = jpx->numcomps;
163
w = jpx->comps[0].w;
164
h = jpx->comps[0].h;
165
depth = jpx->comps[0].prec;
166
sgnd = jpx->comps[0].sgnd;
167
168
if (jpx->color_space == OPJ_CLRSPC_SRGB && n == 4) { n = 3; a = 1; }
169
else if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 4) { n = 3; a = 1; }
170
else if (n == 2) { n = 1; a = 1; }
171
else if (n > 4) { n = 4; a = 1; }
172
else { a = 0; }
173
174
if (defcs)
175
{
176
if (defcs->n == n)
177
{
178
colorspace = defcs;
179
}
180
else
181
{
182
fz_warn(ctx, "jpx file and dict colorspaces do not match");
183
defcs = NULL;
184
}
185
}
186
187
if (!defcs)
188
{
189
switch (n)
190
{
191
case 1: colorspace = fz_device_gray(ctx); break;
192
case 3: colorspace = fz_device_rgb(ctx); break;
193
case 4: colorspace = fz_device_cmyk(ctx); break;
194
}
195
}
196
197
fz_try(ctx)
198
{
199
img = fz_new_pixmap(ctx, colorspace, w, h);
200
}
201
fz_catch(ctx)
202
{
203
opj_image_destroy(jpx);
204
fz_rethrow_message(ctx, "out of memory loading jpx");
205
}
206
207
p = img->samples;
208
for (y = 0; y < h; y++)
209
{
210
for (x = 0; x < w; x++)
211
{
212
for (k = 0; k < n + a; k++)
213
{
214
v = jpx->comps[k].data[y * w + x];
215
if (sgnd)
216
v = v + (1 << (depth - 1));
217
if (depth > 8)
218
v = v >> (depth - 8);
219
*p++ = v;
220
}
221
if (!a)
222
*p++ = 255;
223
}
224
}
225
226
opj_image_destroy(jpx);
227
228
if (a)
229
{
230
if (n == 4)
231
{
232
fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb(ctx), w, h);
233
fz_convert_pixmap(ctx, tmp, img);
234
fz_drop_pixmap(ctx, img);
235
img = tmp;
236
}
237
fz_premultiply_pixmap(ctx, img);
238
}
239
240
return img;
241
}
242
243