1
/* Copyright (C) 2001-2008 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: sjbig2_luratech.c 8784 2008-05-28 18:16:26Z giles $ */
15
/* jbig2decode filter implementation -- hooks in luratech JBIG2 */
18
#include "malloc_.h" /* should use a gs mem pointer */
23
#include "sjbig2_luratech.h"
27
/* JBIG2Decode stream implementation using the Luratech library */
29
/* if linking against a SDK build that requires a separate license key,
30
you can change the following undefs to defines and set them here. */
32
#ifndef JB2_LICENSE_NUM_1
33
# undef JB2_LICENSE_NUM_1
35
#ifndef JB2_LICENSE_NUM_2
36
# undef JB2_LICENSE_NUM_2
40
/* The /JBIG2Decode filter is a fairly memory intensive one to begin with,
41
Furthermore, as a PDF 1.4 feature, we can assume a fairly large
42
(host-level) machine. We therefore dispense with the normal
43
Ghostscript memory discipline and let the library allocate all its
44
resources on the heap. The pointers to these are not enumerated and
45
so will not be garbage collected. We rely on our release() proc being
46
called to deallocate state.
48
/* TODO: check allocations for integer overflow */
50
/* create a gc object for our state, defined in sjbig2_luratech.h */
51
private_st_jbig2decode_state();
53
#define JBIG2_BUFFER_SIZE 4096
55
/* our implementation of the "parsed" /JBIG2Globals filter parameter */
56
typedef struct s_jbig2decode_global_data_s {
59
} s_jbig2decode_global_data;
61
/* create a global data struct and copy data into it */
63
s_jbig2decode_make_global_data(byte *data, uint size, void **result)
65
s_jbig2decode_global_data *global = NULL;
67
global = malloc(sizeof(*global));
68
if (global == NULL) return gs_error_VMerror;
70
global->data = malloc(size);
71
if (global->data == NULL) {
73
return gs_error_VMerror;
75
memcpy(global->data, data, size);
82
/* free a global data struct and its data */
84
s_jbig2decode_free_global_data(void *data)
86
s_jbig2decode_global_data *global = (s_jbig2decode_global_data*)data;
88
if (global->size && global->data) {
95
/* store a global ctx pointer in our state structure */
97
s_jbig2decode_set_global_data(stream_state *ss, s_jbig2_global_data_t *gd)
99
stream_jbig2decode_state *state = (stream_jbig2decode_state*)ss;
101
return gs_error_VMerror;
103
state->global_struct = gd;
105
s_jbig2decode_global_data *global = (s_jbig2decode_global_data*)(gd->data);
106
state->global_data = global->data;
107
state->global_size = global->size;
109
state->global_data = NULL;
110
state->global_size = 0;
115
/* invert the bits in a buffer */
116
/* jbig2 and postscript have different senses of what pixel
117
value is black, so we must invert the image */
119
s_jbig2_invert_buffer(unsigned char *buf, int length)
123
for (i = 0; i < length; i++)
127
/** callbacks passed to the luratech library */
129
/* memory allocator */
130
static void * JB2_Callback
131
s_jbig2_alloc(unsigned long size, void *userdata)
133
void *result = malloc(size);
138
static JB2_Error JB2_Callback
139
s_jbig2_free(void *ptr, void *userdata)
142
return cJB2_Error_OK;
145
/* error callback for jbig2 codec */
146
static void JB2_Callback
147
s_jbig2_message(const char *message, JB2_Message_Level level, void *userdata)
151
if (message == NULL) return;
152
if (message[0] == '\0') return;
155
case cJB2_Message_Information:
156
type = "info"; break;;
157
case cJB2_Message_Warning:
158
type = "WARNING"; break;;
159
case cJB2_Message_Error:
160
type = "ERROR"; break;;
162
type = "unknown message"; break;;
165
if (level == cJB2_Message_Error) {
166
dprintf2("Luratech JBIG2 %s %s\n", type, message);
168
if_debug2('w', "[w]Luratech JBIG2 %s %s\n", type, message);
174
/* compressed read callback for jbig2 codec */
175
static JB2_Size_T JB2_Callback
176
s_jbig2_read(unsigned char *buffer,
177
JB2_Size_T offset, JB2_Size_T size, void *userdata)
179
stream_jbig2decode_state *const state = (stream_jbig2decode_state *) userdata;
182
/* return data from the Globals stream */
183
if (offset < state->global_size) {
184
available = state->global_size - offset;
185
if (available > size) available = size;
186
memcpy(buffer, state->global_data + offset, available);
190
/* else return data from the image stream */
191
offset -= state->global_size;
192
available = state->infill - offset;
193
if (available > size) available = size;
194
if (available <= 0) return 0;
196
memcpy(buffer, state->inbuf + offset, available);
200
/* uncompressed write callback for jbig2 codec */
201
static JB2_Error JB2_Callback
202
s_jbig2_write(unsigned char *buffer,
203
unsigned long row, unsigned long width,
204
unsigned long bbp, void *userdata)
206
stream_jbig2decode_state *const state = (stream_jbig2decode_state *) userdata;
207
unsigned char *line = state->image + row*state->stride;
208
long available = ((width - 1) >> 3) + 1;
210
if (row >= state->height) {
211
dlprintf2("jbig2decode: output for row index %lu of %lu called!\n", row, state->height);
212
return cJB2_Error_Invalid_Index;
215
memcpy(line, buffer, available);
216
s_jbig2_invert_buffer(line, available);
218
return cJB2_Error_OK;
223
s_jbig2decode_inbuf(stream_jbig2decode_state *state, stream_cursor_read * pr)
225
long in_size = pr->limit - pr->ptr;
227
/* allocate the input buffer if needed */
228
if (state->inbuf == NULL) {
229
state->inbuf = malloc(JBIG2_BUFFER_SIZE);
230
if (state->inbuf == NULL) return gs_error_VMerror;
231
state->insize = JBIG2_BUFFER_SIZE;
235
/* grow the input buffer if needed */
236
while (state->insize < state->infill + in_size) {
238
unsigned long new_size = state->insize;
240
while (new_size < state->infill + in_size)
241
new_size = new_size << 1;
243
if_debug1('s', "[s]jbig2decode growing input buffer to %lu bytes\n",
245
new = realloc(state->inbuf, new_size);
246
if (new == NULL) return gs_error_VMerror;
249
state->insize = new_size;
252
/* copy the available input into our buffer */
253
/* note that the gs stream library uses offset-by-one
254
indexing of its buffers while we use zero indexing */
255
memcpy(state->inbuf + state->infill, pr->ptr + 1, in_size);
256
state->infill += in_size;
262
/* initialize the steam. */
264
s_jbig2decode_init(stream_state * ss)
266
stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
283
/* process a section of the input and return any decoded data.
284
see strimpl.h for return codes.
287
s_jbig2decode_process(stream_state * ss, stream_cursor_read * pr,
288
stream_cursor_write * pw, bool last)
290
stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
291
long in_size = pr->limit - pr->ptr;
292
long out_size = pw->limit - pw->ptr;
295
JB2_Scaling_Factor scale = {1,1};
296
JB2_Rect rect = {0,0,0,0};
301
/* buffer all available input for the decoder */
302
result = s_jbig2decode_inbuf(state, pr);
303
if (result) return ERRC;
306
if (last && out_size > 0) {
308
if (state->doc == NULL) {
310
/* initialize the codec state and pass our callbacks */
311
error = JB2_Document_Start( &(state->doc),
312
s_jbig2_alloc, ss, /* alloc and its data */
313
s_jbig2_free, ss, /* free and its data */
314
s_jbig2_read, ss, /* read callback and data */
315
s_jbig2_message, ss); /* message callback and data */
316
if (error != cJB2_Error_OK) return ERRC;
318
#if defined(JB2_LICENSE_NUM_1) && defined(JB2_LICENSE_NUM_2)
319
/* set the license keys if appropriate */
320
error = JB2_Document_Set_License(state->doc,
321
JB2_LICENSE_NUM_1, JB2_LICENSE_NUM_2);
322
if (error != cJB2_Error_OK) return ERRC;
324
/* decode relevent image parameters */
325
error = JB2_Document_Set_Page(state->doc, 0);
326
if (error != cJB2_Error_OK) return ERRC;
327
error = JB2_Document_Get_Property(state->doc,
328
cJB2_Prop_Page_Width, &result);
329
state->width = result;
330
error = JB2_Document_Get_Property(state->doc,
331
cJB2_Prop_Page_Height, &result);
332
if (error != cJB2_Error_OK) return ERRC;
333
state->height = result;
334
state->stride = ((state->width - 1) >> 3) + 1;
335
if_debug2('w', "[w]jbig2decode page is %ldx%ld; allocating image\n", state->width, state->height);
336
state->image = malloc(state->height*state->stride);
338
/* start image decode */
339
error = JB2_Document_Decompress_Page(state->doc, scale, rect,
341
if (error != cJB2_Error_OK) return ERRC;
345
/* copy any buffered image data out */
346
available = state->stride*state->height - state->offset;
348
out_size = (out_size > available) ? available : out_size;
349
memcpy(pw->ptr+1, state->image + state->offset, out_size);
350
state->offset += out_size;
353
/* more data to output? */
354
available = state->stride*state->height - state->offset;
355
if (available > 0) return 1;
359
/* handle fatal decoding errors reported through our callback */
360
if (state->error) return ERRC;
365
/* stream release. free all our decoder state. */
367
s_jbig2decode_release(stream_state *ss)
369
stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
372
JB2_Document_End(&(state->doc));
373
if (state->inbuf) free(state->inbuf);
374
if (state->image) free(state->image);
376
/* the interpreter calls jbig2decode_free_global_data() separately */
379
/* stream template */
380
const stream_template s_jbig2decode_template = {
381
&st_jbig2decode_state,
383
s_jbig2decode_process,
384
1, 1, /* min in and out buffer sizes we can handle --should be ~32k,64k for efficiency? */
385
s_jbig2decode_release
390
/** encode support **/
392
/* we provide a C-only encode filter for generating embedded JBIG2 image
395
/* create a gc object for our state, defined in sjbig2_luratech.h */
396
private_st_jbig2encode_state();
398
/* helper - start up the compression context */
400
s_jbig2encode_start(stream_jbig2encode_state *state)
404
/* initialize the compression handle */
405
err = JB2_Compress_Start(&(state->cmp),
406
s_jbig2_alloc, state, /* alloc and its parameter data */
407
s_jbig2_free, state, /* free callback */
408
s_jbig2_message, state);/* message callback */
409
if (err != cJB2_Error_OK) return err;
411
/* set the license keys if appropriate */
412
#if defined(JB2_LICENSE_NUM_1) && defined(JB2_LICENSE_NUM_2)
413
err = JB2_Document_Set_License(state->cmp,
414
JB2_LICENSE_NUM_1, JB2_LICENSE_NUM_2);
415
if (err != cJB2_Error_OK) return err;
418
/* set the image properties */
419
err = JB2_Compress_Set_Property(state->cmp,
420
cJB2_Prop_Page_Width, state->width);
422
err = JB2_Compress_Set_Property(state->cmp,
423
cJB2_Prop_Page_Height, state->height);
424
if (err != cJB2_Error_OK) return err;
426
/* we otherwise use the default compression parameters */
428
return cJB2_Error_OK;
431
/* callback for compressed data output */
432
static JB2_Size_T JB2_Callback
433
s_jbig2encode_write(const unsigned char *buffer,
434
JB2_Size_T pos, JB2_Size_T size, void *userdata)
436
stream_jbig2encode_state *state = (stream_jbig2encode_state *)userdata;
438
/* allocate the output buffer if necessary */
439
if (state->outbuf == NULL) {
440
state->outbuf = malloc(JBIG2_BUFFER_SIZE);
441
if (state->outbuf == NULL) {
442
dprintf("jbig2encode: failed to allocate output buffer\n");
443
return 0; /* can't return an error! */
445
state->outsize = JBIG2_BUFFER_SIZE;
448
/* grow the output buffer if necessary */
449
while (pos+size > state->outsize) {
450
unsigned char *new = realloc(state->outbuf, state->outsize*2);
452
dprintf1("jbig2encode: failed to resize output buffer"
453
" beyond %lu bytes\n", state->outsize);
454
return 0; /* can't return an error! */
460
/* copy data into our buffer; there will now be enough room. */
461
memcpy(state->outbuf + pos, buffer, size);
462
if (state->outfill < pos + size) state->outfill = pos + size;
468
/* initialize the steam. */
470
s_jbig2encode_init(stream_state * ss)
472
stream_jbig2encode_state *state = (stream_jbig2encode_state *)ss;
474
/* null library context handles */
475
state->cmp = (JB2_Handle_Compress)NULL;
476
state->doc = (JB2_Handle_Document)NULL;
478
/* width and height are set by the client */
479
/* calculate a stride based on those values */
480
state->stride = ((state->width - 1) >> 3) + 1;
482
state->line = malloc(state->stride);
483
if (state->line == NULL) return ERRC;
486
/* null output buffer */
487
state->outbuf = NULL;
495
/* process a section of the input and return any encoded data.
496
see strimpl.h for return codes.
499
s_jbig2encode_process(stream_state * ss, stream_cursor_read * pr,
500
stream_cursor_write * pw, bool last)
502
stream_jbig2encode_state *state = (stream_jbig2encode_state *)ss;
503
long in_size = pr->limit - pr->ptr;
504
long out_size = pw->limit - pw->ptr;
505
long available, segment;
508
/* Be greedy in filling our internal line buffer so we always
509
make read progress on a stream. */
511
/* initialize the encoder if necessary */
512
if (state->cmp == (JB2_Handle_Compress)NULL)
513
s_jbig2encode_start(state);
517
/* try to fill the line buffer */
518
segment = state->stride - state->linefill;
520
segment = (segment < available) ? segment : available;
521
memcpy(state->line + state->linefill, pr->ptr+1, segment);
523
available -= segment;
524
state->linefill += segment;
526
/* pass a full line buffer to the encoder library */
527
if (state->linefill == state->stride) {
528
s_jbig2_invert_buffer(state->line, state->stride);
529
err = JB2_Compress_Line(state->cmp, state->line);
531
if (err != cJB2_Error_OK) return ERRC;
533
/* pass remaining full lines to the encoder library */
534
while (available >= state->stride) {
535
memcpy(state->line, pr->ptr+1, state->stride);
536
s_jbig2_invert_buffer(state->line, state->stride);
537
err = JB2_Compress_Line(state->cmp, state->line);
538
pr->ptr += state->stride;
539
available = pr->limit - pr->ptr;
540
if (err != cJB2_Error_OK) return ERRC;
542
/* copy remaining data into the line buffer */
544
/* available is always < stride here */
545
memcpy(state->line, pr->ptr+1, available);
546
pr->ptr += available;
547
state->linefill = available;
549
if (!last) return 0; /* request more data */
552
if (last && state->outbuf == NULL) {
553
/* convert the compression context to a document context */
554
err = JB2_Compress_End(&(state->cmp), &(state->doc));
555
if (err != cJB2_Error_OK) return ERRC;
556
/* dump the compressed data out through a callback;
557
unfortunately we can't serialize this across process calls */
558
err = JB2_Document_Export_Document(state->doc,
559
s_jbig2encode_write, state,
560
cJB2_Export_Format_Stream_For_PDF);
561
if (err != cJB2_Error_OK) return ERRC;
564
if (state->outbuf != NULL) {
565
/* copy available output data */
566
available = min(out_size, state->outfill - state->offset);
567
memcpy(pw->ptr + 1, state->outbuf + state->offset, available);
568
pw->ptr += available;
569
state->offset += available;
571
/* need further output space? */
572
if (state->outfill - state->offset > 0) return 1;
573
else return EOFC; /* all done */
576
/* something went wrong above */
580
/* stream release. free all our decoder state.
583
s_jbig2encode_release(stream_state *ss)
585
stream_jbig2encode_state *state = (stream_jbig2encode_state *)ss;
587
if (state->outbuf != NULL) free(state->outbuf);
588
if (state->line != NULL) free(state->line);
591
/* stream template */
592
const stream_template s_jbig2encode_template = {
593
&st_jbig2encode_state,
595
s_jbig2encode_process,
596
1024, 1024, /* min in and out buffer sizes; could be smaller, but
597
this is more efficient */
598
s_jbig2encode_release