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