1#include "mupdf/fitz.h"
2
3#ifdef HAVE_LURATECH
4
5#include <string.h>
6#include <ldf_jb2.h>
7
8struct info
9{
10 fz_context *ctx;
11 unsigned long width, height;
12 unsigned long xres, yres;
13 unsigned long stride;
14 unsigned long pages;
15 fz_colorspace *cspace;
16 JB2_Handle_Document doc;
17
18 const unsigned char *data;
19 size_t len;
20
21 unsigned char *output;
22};
23
24static void * JB2_Callback
25jbig2_alloc(unsigned long size, void *userdata)
26{
27 struct info *state = userdata;
28 return fz_malloc(state->ctx, size);
29}
30
31static JB2_Error JB2_Callback
32jbig2_free(void *ptr, void *userdata)
33{
34 struct info *state = userdata;
35 fz_free(state->ctx, ptr);
36 return cJB2_Error_OK;
37}
38
39static void JB2_Callback
40jbig2_message(const char *msg, JB2_Message_Level level, void *userdata)
41{
42 struct info *state = userdata;
43
44 if (msg != NULL && msg[0] != '\0')
45 switch (level)
46 {
47 case cJB2_Message_Information:
48#ifndef NDEBUG
49 fz_warn(state->ctx, "luratech jbig2 info: %s", msg);
50#endif
51 break;
52 case cJB2_Message_Warning:
53 fz_warn(state->ctx, "luratech jbig2 warning: %s", msg);
54 break;
55 case cJB2_Message_Error:
56 fz_warn(state->ctx, "luratech jbig2 error: %s", msg);
57 break;
58 default:
59 fz_warn(state->ctx, "luratech jbig2 message: %s", msg);
60 break;
61 }
62}
63
64static JB2_Size_T JB2_Callback
65jbig2_read(unsigned char *buf, JB2_Size_T offset, JB2_Size_T size, void *userdata)
66{
67 struct info *state = userdata;
68 size_t available;
69
70 if (state->len <= offset)
71 return 0;
72 available = fz_minz(state->len - offset, size);
73 memcpy(buf, state->data + offset, available);
74 return (JB2_Size_T)available;
75}
76
77static JB2_Error JB2_Callback
78jbig2_write(unsigned char *buf, unsigned long row, unsigned long width, unsigned long bpp, void *userdata)
79{
80 struct info *state = userdata;
81 int stride = (width + 7) >> 3;
82 unsigned char *dp = state->output + row * stride;
83
84 if (row >= state->height)
85 {
86 fz_warn(state->ctx, "row %lu outside of image", row);
87 return cJB2_Error_OK;
88 }
89
90 while (stride--)
91 *(dp++) = *(buf++) ^ 0xff;
92
93 return cJB2_Error_OK;
94}
95
96
97static fz_pixmap *
98jbig2_read_image(fz_context *ctx, struct info *jbig2, const unsigned char *buf, size_t len, int only_metadata, int subimage)
99{
100 struct info *state = jbig2;
101 JB2_Error err;
102 JB2_Scaling_Factor scale = {1, 1};
103 JB2_Rect rect = {0, 0, 0, 0};
104 fz_pixmap *pix = NULL;
105
106 fz_var(pix);
107
108 fz_try(ctx)
109 {
110 state->ctx = ctx;
111 state->data = buf;
112 state->len = len;
113
114 err = JB2_Document_Start(&state->doc,
115 jbig2_alloc, state,
116 jbig2_free, state,
117 jbig2_read, state,
118 jbig2_message, state);
119 if (err != cJB2_Error_OK)
120 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open image: %d", (int) err);
121
122#if defined(JB2_LICENSE_NUM_1) && defined(JB2_LICENSE_NUM_2)
123 err = JB2_Document_Set_License(doc, JB2_LICENSE_NUM_1, JB2_LICENSE_NUM_2);
124 if (err != cJB2_Error_OK)
125 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot set license: %d", (int) err);
126#endif
127
128 err = JB2_Document_Get_Property(state->doc, cJB2_Prop_Number_Of_Pages, &state->pages);
129 if (err != cJB2_Error_OK)
130 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get number of pages: %d", (int) err);
131 if (subimage != -1)
132 {
133 if (subimage < 0 || subimage >= state->pages)
134 fz_throw(ctx, FZ_ERROR_GENERIC, "page number out of bounds %d vs %ld", subimage, state->pages);
135 err = JB2_Document_Set_Page(state->doc, subimage);
136 if (err != cJB2_Error_OK)
137 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot select page: %d", (int) err);
138 }
139
140 err = JB2_Document_Get_Property(state->doc, cJB2_Prop_Page_Resolution_X, &state->xres);
141 if (err != cJB2_Error_OK)
142 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get page x resolution: %d", (int) err);
143 err = JB2_Document_Get_Property(state->doc, cJB2_Prop_Page_Resolution_Y, &state->yres);
144 if (err != cJB2_Error_OK)
145 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get page y resolution: %d", (int) err);
146
147 err = JB2_Document_Get_Property(state->doc, cJB2_Prop_Page_Width, &state->width);
148 if (err != cJB2_Error_OK)
149 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get page width: %d", (int) err);
150 err = JB2_Document_Get_Property(state->doc, cJB2_Prop_Page_Height, &state->height);
151 if (err != cJB2_Error_OK)
152 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot get page height: %d", (int) err);
153
154 if (!only_metadata)
155 {
156 state->stride = (state->width + 7) >> 3;
157 state->output = fz_malloc(state->ctx, state->stride * state->height);
158
159 err = JB2_Document_Decompress_Page(state->doc, scale, rect, jbig2_write, state);
160 if (err != cJB2_Error_OK)
161 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot decode image: %d", (int) err);
162
163 pix = fz_new_pixmap(ctx, fz_device_gray(ctx), state->width, state->height, NULL, 0);
164 fz_unpack_tile(ctx, pix, state->output, 1, 1, state->stride, 0);
165 }
166
167 }
168 fz_always(ctx)
169 {
170 JB2_Document_End(&state->doc);
171 }
172 fz_catch(ctx)
173 {
174 fz_drop_pixmap(ctx, pix);
175 fz_rethrow(ctx);
176 }
177
178 return pix;
179}
180
181int
182fz_load_jbig2_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len)
183{
184 struct info jbig2 = { 0 };
185 int subimage_count = 0;
186
187 fz_try(ctx)
188 {
189 jbig2_read_image(ctx, &jbig2, buf, len, 1, -1);
190 subimage_count = jbig2.pages;
191 }
192 fz_catch(ctx)
193 fz_rethrow(ctx);
194
195 return subimage_count;
196}
197
198void
199fz_load_jbig2_info_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep, int subimage)
200{
201 struct info jbig2 = { 0 };
202
203 jbig2_read_image(ctx, &jbig2, buf, len, 1, subimage);
204 *cspacep = fz_keep_colorspace(ctx, jbig2.cspace);
205 *wp = jbig2.width;
206 *hp = jbig2.height;
207 *xresp = jbig2.xres;
208 *yresp = jbig2.yres;
209}
210
211fz_pixmap *
212fz_load_jbig2_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage)
213{
214 struct info jbig2 = { 0 };
215 return jbig2_read_image(ctx, &jbig2, buf, len, 0, subimage);
216}
217
218fz_pixmap *
219fz_load_jbig2(fz_context *ctx, const unsigned char *buf, size_t len)
220{
221 return fz_load_jbig2_subimage(ctx, buf, len, 0);
222}
223
224void
225fz_load_jbig2_info(fz_context *ctx, const unsigned char *buf, size_t len, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
226{
227 fz_load_jbig2_info_subimage(ctx, buf, len, wp, hp, xresp, yresp, cspacep, 0);
228}
229
230#else /* HAVE_LURATECH */
231
232#include <jbig2.h>
233
234struct info
235{
236 int width, height;
237 int xres, yres;
238 int pages;
239 fz_colorspace *cspace;
240};
241
242struct fz_jbig2_alloc_s
243{
244 Jbig2Allocator super;
245 fz_context *ctx;
246};
247
248static void
249error_callback(void *data, const char *msg, Jbig2Severity severity, int32_t seg_idx)
250{
251 fz_context *ctx = data;
252 if (severity == JBIG2_SEVERITY_FATAL)
253 fz_warn(ctx, "jbig2dec error: %s (segment %d)", msg, seg_idx);
254 else if (severity == JBIG2_SEVERITY_WARNING)
255 fz_warn(ctx, "jbig2dec warning: %s (segment %d)", msg, seg_idx);
256#ifndef NDEBUG
257 else if (severity == JBIG2_SEVERITY_INFO)
258 fz_warn(ctx, "jbig2dec info: %s (segment %d)", msg, seg_idx);
259 else if (severity == JBIG2_SEVERITY_DEBUG)
260 fz_warn(ctx, "jbig2dec debug: %s (segment %d)", msg, seg_idx);
261#endif
262}
263
264static void *fz_jbig2_alloc(Jbig2Allocator *allocator, size_t size)
265{
266 fz_context *ctx = ((struct fz_jbig2_alloc_s *) allocator)->ctx;
267 return fz_malloc_no_throw(ctx, size);
268}
269
270static void fz_jbig2_free(Jbig2Allocator *allocator, void *p)
271{
272 fz_context *ctx = ((struct fz_jbig2_alloc_s *) allocator)->ctx;
273 fz_free(ctx, p);
274}
275
276static void *fz_jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size)
277{
278 fz_context *ctx = ((struct fz_jbig2_alloc_s *) allocator)->ctx;
279 if (size == 0)
280 {
281 fz_free(ctx, p);
282 return NULL;
283 }
284 if (p == NULL)
285 return fz_malloc(ctx, size);
286 return fz_realloc_no_throw(ctx, p, size);
287}
288
289static fz_pixmap *
290jbig2_read_image(fz_context *ctx, struct info *jbig2, const unsigned char *buf, size_t len, int only_metadata, int subimage)
291{
292 Jbig2Ctx *jctx = NULL;
293 Jbig2Image *page = NULL;
294 struct fz_jbig2_alloc_s allocator;
295 fz_pixmap *pix = NULL;
296
297 allocator.super.alloc = fz_jbig2_alloc;
298 allocator.super.free = fz_jbig2_free;
299 allocator.super.realloc = fz_jbig2_realloc;
300 allocator.ctx = ctx;
301
302 fz_var(jctx);
303 fz_var(page);
304 fz_var(pix);
305
306 fz_try(ctx)
307 {
308 jctx = jbig2_ctx_new((Jbig2Allocator *) &allocator, 0, NULL, error_callback, ctx);
309 if (jctx == NULL)
310 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot create jbig2 context");
311 if (jbig2_data_in(jctx, buf, len) < 0)
312 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot decode jbig2 image");
313 if (jbig2_complete_page(jctx) < 0)
314 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot complete jbig2 image");
315
316 if (only_metadata && subimage < 0)
317 {
318 while ((page = jbig2_page_out(jctx)) != NULL)
319 {
320 jbig2_release_page(jctx, page);
321 jbig2->pages++;
322 }
323 }
324 else if (only_metadata && subimage >= 0)
325 {
326 while ((page = jbig2_page_out(jctx)) != NULL && subimage > 0)
327 {
328 jbig2_release_page(jctx, page);
329 subimage--;
330 }
331
332 if (page == NULL)
333 fz_throw(ctx, FZ_ERROR_GENERIC, "no jbig2 image decoded");
334
335 jbig2->cspace = fz_device_gray(ctx);
336 jbig2->width = page->width;
337 jbig2->height = page->height;
338 jbig2->xres = 72;
339 jbig2->yres = 72;
340 }
341 else if (subimage >= 0)
342 {
343 while ((page = jbig2_page_out(jctx)) != NULL && subimage > 0)
344 {
345 jbig2_release_page(jctx, page);
346 subimage--;
347 }
348
349 if (page == NULL)
350 fz_throw(ctx, FZ_ERROR_GENERIC, "no jbig2 image decoded");
351
352 jbig2->cspace = fz_device_gray(ctx);
353 jbig2->width = page->width;
354 jbig2->height = page->height;
355 jbig2->xres = 72;
356 jbig2->yres = 72;
357
358 pix = fz_new_pixmap(ctx, jbig2->cspace, jbig2->width, jbig2->height, NULL, 0);
359 fz_unpack_tile(ctx, pix, page->data, 1, 1, page->stride, 0);
360 fz_invert_pixmap(ctx, pix);
361 }
362 }
363 fz_always(ctx)
364 {
365 jbig2_release_page(jctx, page);
366 jbig2_ctx_free(jctx);
367 }
368 fz_catch(ctx)
369 {
370 fz_drop_pixmap(ctx, pix);
371 fz_rethrow(ctx);
372 }
373
374 return pix;
375}
376
377int
378fz_load_jbig2_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len)
379{
380 struct info jbig2 = { 0 };
381 int subimage_count = 0;
382
383 fz_try(ctx)
384 {
385 jbig2_read_image(ctx, &jbig2, buf, len, 1, -1);
386 subimage_count = jbig2.pages;
387 }
388 fz_catch(ctx)
389 fz_rethrow(ctx);
390
391 return subimage_count;
392}
393
394void
395fz_load_jbig2_info_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep, int subimage)
396{
397 struct info jbig2 = { 0 };
398
399 jbig2_read_image(ctx, &jbig2, buf, len, 1, subimage);
400 *cspacep = fz_keep_colorspace(ctx, jbig2.cspace);
401 *wp = jbig2.width;
402 *hp = jbig2.height;
403 *xresp = jbig2.xres;
404 *yresp = jbig2.yres;
405}
406
407fz_pixmap *
408fz_load_jbig2_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage)
409{
410 struct info jbig2 = { 0 };
411 return jbig2_read_image(ctx, &jbig2, buf, len, 0, subimage);
412}
413
414fz_pixmap *
415fz_load_jbig2(fz_context *ctx, const unsigned char *buf, size_t len)
416{
417 return fz_load_jbig2_subimage(ctx, buf, len, 0);
418}
419
420void
421fz_load_jbig2_info(fz_context *ctx, const unsigned char *buf, size_t len, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
422{
423 fz_load_jbig2_info_subimage(ctx, buf, len, wp, hp, xresp, yresp, cspacep, 0);
424}
425
426#endif /* HAVE_LURATECH */
427