Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
};