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