xref: /plan9/sys/src/cmd/gs/src/sjbig2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2003 artofcode LLC.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: sjbig2.c,v 1.7 2005/06/09 07:15:07 giles Exp $ */
18 /* jbig2decode filter implementation -- hooks in libjbig2dec */
19 
20 #include "stdint_.h"
21 #include "memory_.h"
22 #include "stdio_.h" /* sprintf() for debug output */
23 
24 #include "gserrors.h"
25 #include "gserror.h"
26 #include "gdebug.h"
27 #include "strimpl.h"
28 #include "sjbig2.h"
29 
30 /* stream implementation */
31 
32 /* The /JBIG2Decode filter is a fairly memory intensive one to begin with,
33    particularly in the initial jbig2dec library implementation. Furthermore,
34    as a PDF 1.4 feature, we can assume a fairly large (host-level) machine.
35    We therefore dispense with the normal Ghostscript memory discipline and
36    let the library allocate all its resources on the heap. The pointers to
37    these are not enumerated and so will not be garbage collected. We rely
38    on our release() proc being called to deallocate state.
39  */
40 
41 private_st_jbig2decode_state();	/* creates a gc object for our state, defined in sjbig2.h */
42 
43 /* error callback for jbig2 decoder */
44 private int
s_jbig2decode_error(void * error_callback_data,const char * msg,Jbig2Severity severity,int32_t seg_idx)45 s_jbig2decode_error(void *error_callback_data, const char *msg, Jbig2Severity severity,
46 	       int32_t seg_idx)
47 {
48     stream_jbig2decode_state *const state =
49 	(stream_jbig2decode_state *) error_callback_data;
50     const char *type;
51     char segment[22];
52     int code = 0;
53 
54     switch (severity) {
55 #ifdef JBIG2_DEBUG   /* verbose reporting when debugging */
56         case JBIG2_SEVERITY_DEBUG:
57             type = "DEBUG"; break;;
58         case JBIG2_SEVERITY_INFO:
59             type = "info"; break;;
60         case JBIG2_SEVERITY_WARNING:
61             type = "WARNING"; break;;
62 #else  /* suppress most messages in normal operation */
63         case JBIG2_SEVERITY_DEBUG:
64         case JBIG2_SEVERITY_INFO:
65         case JBIG2_SEVERITY_WARNING:
66             return 0;
67             break;;
68 #endif /* JBIG2_DEBUG */
69         case JBIG2_SEVERITY_FATAL:
70             type = "FATAL ERROR decoding image:";
71             /* pass the fatal error upstream if possible */
72 	    code = gs_error_ioerror;
73 	    if (state != NULL) state->error = code;
74 	    break;;
75         default: type = "unknown message:"; break;;
76     }
77     if (seg_idx == -1) segment[0] = '\0';
78     else sprintf(segment, "(segment 0x%02x)", seg_idx);
79 
80     dlprintf3("jbig2dec %s %s %s\n", type, msg, segment);
81 
82     return code;
83 }
84 
85 /* invert the bits in a buffer */
86 /* jbig2 and postscript have different senses of what pixel
87    value is black, so we must invert the image */
88 private void
s_jbig2decode_invert_buffer(unsigned char * buf,int length)89 s_jbig2decode_invert_buffer(unsigned char *buf, int length)
90 {
91     int i;
92 
93     for (i = 0; i < length; i++)
94         *buf++ ^= 0xFF;
95 }
96 
97 /* parse a globals stream packed into a gs_bytestring for us by the postscript
98    layer and stuff the resulting context into a pointer for use in later decoding */
99 public int
s_jbig2decode_make_global_ctx(byte * data,uint length,Jbig2GlobalCtx ** global_ctx)100 s_jbig2decode_make_global_ctx(byte *data, uint length, Jbig2GlobalCtx **global_ctx)
101 {
102     Jbig2Ctx *ctx = NULL;
103     int code;
104 
105     /* the cvision encoder likes to include empty global streams */
106     if (length == 0) {
107         if_debug0('s', "[s] ignoring zero-length jbig2 global stream.\n");
108     	*global_ctx = NULL;
109     	return 0;
110     }
111 
112     /* allocate a context with which to parse our global segments */
113     ctx = jbig2_ctx_new(NULL, JBIG2_OPTIONS_EMBEDDED, NULL,
114                             s_jbig2decode_error, NULL);
115 
116     /* parse the global bitstream */
117     code = jbig2_data_in(ctx, data, length);
118 
119     if (code) {
120 	/* error parsing the global stream */
121 	*global_ctx = NULL;
122 	return code;
123     }
124 
125     /* canonize and store our global state */
126     *global_ctx = jbig2_make_global_ctx(ctx);
127 
128     return 0; /* todo: check for allocation failure */
129 }
130 
131 /* store a global ctx pointer in our state structure */
132 public int
s_jbig2decode_set_global_ctx(stream_state * ss,Jbig2GlobalCtx * global_ctx)133 s_jbig2decode_set_global_ctx(stream_state *ss, Jbig2GlobalCtx *global_ctx)
134 {
135     stream_jbig2decode_state *state = (stream_jbig2decode_state*)ss;
136     state->global_ctx = global_ctx;
137     return 0;
138 }
139 
140 /* initialize the steam.
141    this involves allocating the context structures, and
142    initializing the global context from the /JBIG2Globals object reference
143  */
144 private int
s_jbig2decode_init(stream_state * ss)145 s_jbig2decode_init(stream_state * ss)
146 {
147     stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
148     Jbig2GlobalCtx *global_ctx = state->global_ctx; /* may be NULL */
149 
150     /* initialize the decoder with the parsed global context if any */
151     state->decode_ctx = jbig2_ctx_new(NULL, JBIG2_OPTIONS_EMBEDDED,
152                 global_ctx, s_jbig2decode_error, ss);
153     state->image = 0;
154     state->error = 0;
155     return 0; /* todo: check for allocation failure */
156 }
157 
158 /* process a section of the input and return any decoded data.
159    see strimpl.h for return codes.
160  */
161 private int
s_jbig2decode_process(stream_state * ss,stream_cursor_read * pr,stream_cursor_write * pw,bool last)162 s_jbig2decode_process(stream_state * ss, stream_cursor_read * pr,
163 		  stream_cursor_write * pw, bool last)
164 {
165     stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
166     Jbig2Image *image = state->image;
167     long in_size = pr->limit - pr->ptr;
168     long out_size = pw->limit - pw->ptr;
169     int status = 0;
170 
171     /* there will only be a single page image,
172        so pass all data in before looking for any output.
173        note that the gs stream library expects offset-by-one
174        indexing of the buffers, while jbig2dec uses normal 0 indexes */
175     if (in_size > 0) {
176         /* pass all available input to the decoder */
177         jbig2_data_in(state->decode_ctx, pr->ptr + 1, in_size);
178         pr->ptr += in_size;
179         /* simulate end-of-page segment */
180         if (last == 1) {
181             jbig2_complete_page(state->decode_ctx);
182         }
183 	/* handle fatal decoding errors reported through our callback */
184 	if (state->error) return state->error;
185     }
186     if (out_size > 0) {
187         if (image == NULL) {
188             /* see if a page image in available */
189             image = jbig2_page_out(state->decode_ctx);
190             if (image != NULL) {
191                 state->image = image;
192                 state->offset = 0;
193             }
194         }
195         if (image != NULL) {
196             /* copy data out of the decoded image, if any */
197             long image_size = image->height*image->stride;
198             long usable = min(image_size - state->offset, out_size);
199             memcpy(pw->ptr + 1, image->data + state->offset, usable);
200             s_jbig2decode_invert_buffer(pw->ptr + 1, usable);
201             state->offset += usable;
202             pw->ptr += usable;
203             status = (state->offset < image_size) ? 1 : 0;
204         }
205     }
206 
207     return status;
208 }
209 
210 /* stream release.
211    free all our decoder state.
212  */
213 private void
s_jbig2decode_release(stream_state * ss)214 s_jbig2decode_release(stream_state *ss)
215 {
216     stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
217 
218     if (state->decode_ctx) {
219         if (state->image) jbig2_release_page(state->decode_ctx, state->image);
220         jbig2_ctx_free(state->decode_ctx);
221     }
222     /* the interpreter takes care of freeing the global_ctx */
223 }
224 
225 /* set stream defaults.
226    this hook exists to avoid confusing the gc with bogus
227    pointers. we use it similarly just to NULL all the pointers.
228    (could just be done in _init?)
229  */
230 private void
s_jbig2decode_set_defaults(stream_state * ss)231 s_jbig2decode_set_defaults(stream_state *ss)
232 {
233     stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
234 
235     /* state->global_ctx is not owned by us */
236     state->global_ctx = NULL;
237     state->decode_ctx = NULL;
238     state->image = NULL;
239     state->offset = 0;
240     state->error = 0;
241 }
242 
243 
244 /* stream template */
245 const stream_template s_jbig2decode_template = {
246     &st_jbig2decode_state,
247     s_jbig2decode_init,
248     s_jbig2decode_process,
249     1, 1, /* min in and out buffer sizes we can handle --should be ~32k,64k for efficiency? */
250     s_jbig2decode_release,
251     s_jbig2decode_set_defaults
252 };
253