Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8436 | maxcodehac | 1 | /* |
2 | jbig2dec |
||
3 | |||
4 | Copyright (C) 2001-2005 Artifex Software, Inc. |
||
5 | |||
6 | This software is distributed under license and may not |
||
7 | be copied, modified or distributed except as expressly |
||
8 | authorized under the terms of the license contained in |
||
9 | the file LICENSE in this distribution. |
||
10 | |||
11 | For further licensing information refer to http://artifex.com/ or |
||
12 | contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, |
||
13 | San Rafael, CA 94903, U.S.A., +1(415)492-9861. |
||
14 | */ |
||
15 | |||
16 | #ifdef HAVE_CONFIG_H |
||
17 | #include "config.h" |
||
18 | #endif |
||
19 | #include "os_types.h" |
||
20 | |||
21 | #include |
||
22 | |||
23 | #include "jbig2.h" |
||
24 | #include "jbig2_priv.h" |
||
25 | |||
26 | #ifdef OUTPUT_PBM |
||
27 | #include |
||
28 | #include "jbig2_image.h" |
||
29 | #endif |
||
30 | |||
31 | /* dump the page struct info */ |
||
32 | static void |
||
33 | dump_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Page *page) |
||
34 | { |
||
35 | if (page->x_resolution == 0) { |
||
36 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
37 | "page %d image is %dx%d (unknown res)", page->number, |
||
38 | page->width, page->height); |
||
39 | } else if (page->x_resolution == page->y_resolution) { |
||
40 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
41 | "page %d image is %dx%d (%d ppm)", page->number, |
||
42 | page->width, page->height, |
||
43 | page->x_resolution); |
||
44 | } else { |
||
45 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
46 | "page %d image is %dx%d (%dx%d ppm)", page->number, |
||
47 | page->width, page->height, |
||
48 | page->x_resolution, page->y_resolution); |
||
49 | } |
||
50 | if (page->striped) { |
||
51 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
52 | "\tmaximum stripe size: %d", page->stripe_size); |
||
53 | } |
||
54 | } |
||
55 | |||
56 | /** |
||
57 | * jbig2_page_info: parse page info segment |
||
58 | * |
||
59 | * Parse the page info segment data and fill out a corresponding |
||
60 | * Jbig2Page struct and ready it for subsequent rendered data, |
||
61 | * including allocating an image buffer for the page (or the first stripe) |
||
62 | **/ |
||
63 | int |
||
64 | jbig2_page_info (Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
||
65 | { |
||
66 | Jbig2Page *page; |
||
67 | |||
68 | /* a new page info segment implies the previous page is finished */ |
||
69 | page = &(ctx->pages[ctx->current_page]); |
||
70 | if ((page->number != 0) && |
||
71 | ((page->state == JBIG2_PAGE_NEW) || (page->state == JBIG2_PAGE_FREE))) { |
||
72 | page->state = JBIG2_PAGE_COMPLETE; |
||
73 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
74 | "unexpected page info segment, marking previous page finished"); |
||
75 | } |
||
76 | |||
77 | /* find a free page */ |
||
78 | { |
||
79 | int index, j; |
||
80 | index = ctx->current_page; |
||
81 | while (ctx->pages[index].state != JBIG2_PAGE_FREE) { |
||
82 | index++; |
||
83 | if (index >= ctx->max_page_index) { |
||
84 | /* grow the list */ |
||
85 | ctx->pages = jbig2_realloc(ctx->allocator, ctx->pages, |
||
86 | (ctx->max_page_index <<= 2) * sizeof(Jbig2Page)); |
||
87 | for (j=index; j < ctx->max_page_index; j++) { |
||
88 | ctx->pages[j].state = JBIG2_PAGE_FREE; |
||
89 | ctx->pages[j].number = 0; |
||
90 | ctx->pages[j].image = NULL; |
||
91 | |||
92 | } |
||
93 | } |
||
94 | } |
||
95 | page = &(ctx->pages[index]); |
||
96 | ctx->current_page = index; |
||
97 | page->state = JBIG2_PAGE_NEW; |
||
98 | page->number = segment->page_association; |
||
99 | } |
||
100 | |||
101 | /* FIXME: would be nice if we tried to work around this */ |
||
102 | if (segment->data_length < 19) { |
||
103 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
104 | "segment too short"); |
||
105 | } |
||
106 | |||
107 | /* 7.4.8.x */ |
||
108 | page->width = jbig2_get_int32(segment_data); |
||
109 | page->height = jbig2_get_int32(segment_data + 4); |
||
110 | |||
111 | page->x_resolution = jbig2_get_int32(segment_data + 8); |
||
112 | page->y_resolution = jbig2_get_int32(segment_data + 12); |
||
113 | page->flags = segment_data[16]; |
||
114 | |||
115 | /* 7.4.8.6 */ |
||
116 | { |
||
117 | int16_t striping = jbig2_get_int16(segment_data +17); |
||
118 | if (striping & 0x8000) { |
||
119 | page->striped = TRUE; |
||
120 | page->stripe_size = striping & 0x7FFF; |
||
121 | } else { |
||
122 | page->striped = FALSE; |
||
123 | page->stripe_size = 0; /* would page->height be better? */ |
||
124 | } |
||
125 | } |
||
126 | if (page->height == 0xFFFFFFFF && page->striped == FALSE) { |
||
127 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
128 | "height is unspecified but page is not markes as striped"); |
||
129 | page->striped = TRUE; |
||
130 | } |
||
131 | page->end_row = 0; |
||
132 | |||
133 | if (segment->data_length > 19) { |
||
134 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
135 | "extra data in segment"); |
||
136 | } |
||
137 | |||
138 | dump_page_info(ctx, segment, page); |
||
139 | |||
140 | /* allocate an approprate page image buffer */ |
||
141 | /* 7.4.8.2 */ |
||
142 | if (page->height == 0xFFFFFFFF) { |
||
143 | page->image = jbig2_image_new(ctx, page->width, page->stripe_size); |
||
144 | } else { |
||
145 | page->image = jbig2_image_new(ctx, page->width, page->height); |
||
146 | } |
||
147 | if (page->image == NULL) { |
||
148 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
149 | "failed to allocate buffer for page image"); |
||
150 | } else { |
||
151 | /* 8.2 (3) fill the page with the default pixel value */ |
||
152 | jbig2_image_clear(ctx, page->image, (page->flags & 4)); |
||
153 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
154 | "allocated %dx%d page image (%d bytes)", |
||
155 | page->image->width, page->image->height, |
||
156 | page->image->stride*page->image->height); |
||
157 | } |
||
158 | |||
159 | return 0; |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * jbig2_end_of_stripe: parse and implement an end of stripe segment |
||
164 | **/ |
||
165 | int |
||
166 | jbig2_end_of_stripe(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
||
167 | { |
||
168 | Jbig2Page page = ctx->pages[ctx->current_page]; |
||
169 | int end_row; |
||
170 | |||
171 | end_row = jbig2_get_int32(segment_data); |
||
172 | if (end_row < page.end_row) { |
||
173 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
174 | "end of stripe segment with non-positive end row advance" |
||
175 | " (new end row %d vs current end row %d)", |
||
176 | end_row, page.end_row); |
||
177 | } else { |
||
178 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
179 | "end of stripe: advancing end row to %d", end_row); |
||
180 | } |
||
181 | |||
182 | page.end_row = end_row; |
||
183 | |||
184 | return 0; |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * jbig2_complete_page: complete a page image |
||
189 | * |
||
190 | * called upon seeing an 'end of page' segment, this routine |
||
191 | * marks a page as completed so it can be returned. |
||
192 | * compositing will have already happened in the previous |
||
193 | * segment handlers. |
||
194 | **/ |
||
195 | int |
||
196 | jbig2_complete_page (Jbig2Ctx *ctx) |
||
197 | { |
||
198 | |||
199 | /* check for unfinished segments */ |
||
200 | if (ctx->segment_index != ctx->n_segments) { |
||
201 | Jbig2Segment *segment = ctx->segments[ctx->segment_index]; |
||
202 | int code = 0; |
||
203 | /* Some versions of Xerox Workcentre generate PDF files |
||
204 | with the segment data length field of the last segment |
||
205 | set to -1. Try to cope with this here. */ |
||
206 | if ((segment->data_length & 0xffffffff) == 0xffffffff) { |
||
207 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
208 | "File has an invalid segment data length!" |
||
209 | " Trying to decode using the available data."); |
||
210 | segment->data_length = ctx->buf_wr_ix - ctx->buf_rd_ix; |
||
211 | code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix); |
||
212 | ctx->buf_rd_ix += segment->data_length; |
||
213 | ctx->segment_index++; |
||
214 | } |
||
215 | } |
||
216 | ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE; |
||
217 | |||
218 | return 0; |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * jbig2_end_of_page: parse and implement an end of page segment |
||
223 | **/ |
||
224 | int |
||
225 | jbig2_end_of_page(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
||
226 | { |
||
227 | uint32_t page_number = ctx->pages[ctx->current_page].number; |
||
228 | |||
229 | if (segment->page_association != page_number) { |
||
230 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
231 | "end of page marker for page %d doesn't match current page number %d", |
||
232 | segment->page_association, page_number); |
||
233 | } |
||
234 | |||
235 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
236 | "end of page %d", page_number); |
||
237 | |||
238 | jbig2_complete_page(ctx); |
||
239 | |||
240 | #ifdef OUTPUT_PBM |
||
241 | jbig2_image_write_pbm(ctx->pages[ctx->current_page].image, stdout); |
||
242 | #endif |
||
243 | |||
244 | return 0; |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * jbig2_add_page_result: composite a decoding result onto a page |
||
249 | * |
||
250 | * this is called to add the results of segment decode (when it |
||
251 | * is an image) to a page image buffer |
||
252 | **/ |
||
253 | int |
||
254 | jbig2_page_add_result(Jbig2Ctx *ctx, Jbig2Page *page, Jbig2Image *image, |
||
255 | int x, int y, Jbig2ComposeOp op) |
||
256 | { |
||
257 | /* grow the page to accomodate a new stripe if necessary */ |
||
258 | if (page->striped) { |
||
259 | int new_height = y + image->height + page->end_row; |
||
260 | if (page->image->height < new_height) { |
||
261 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, |
||
262 | "growing page buffer to %d rows " |
||
263 | "to accomodate new stripe", new_height); |
||
264 | jbig2_image_resize(ctx, page->image, |
||
265 | page->image->width, new_height); |
||
266 | } |
||
267 | } |
||
268 | |||
269 | jbig2_image_compose(ctx, page->image, image, |
||
270 | x, y + page->end_row, JBIG2_COMPOSE_OR); |
||
271 | |||
272 | return 0; |
||
273 | } |
||
274 | |||
275 | /** |
||
276 | * jbig2_get_page: return the next available page image buffer |
||
277 | * |
||
278 | * the client can call this at any time to check if any pages |
||
279 | * have been decoded. If so, it returns the first available |
||
280 | * one. The client should then call jbig2_release_page() when |
||
281 | * it no longer needs to refer to the image buffer. |
||
282 | * |
||
283 | * since this is a public routine for the library clients, we |
||
284 | * return an image structure pointer, even though the function |
||
285 | * name refers to a page; the page structure is private. |
||
286 | **/ |
||
287 | Jbig2Image *jbig2_page_out(Jbig2Ctx *ctx) |
||
288 | { |
||
289 | int index; |
||
290 | |||
291 | /* search for a completed page */ |
||
292 | for (index=0; index < ctx->max_page_index; index++) { |
||
293 | if (ctx->pages[index].state == JBIG2_PAGE_COMPLETE) { |
||
294 | ctx->pages[index].state = JBIG2_PAGE_RETURNED; |
||
295 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, |
||
296 | "page %d returned to the client", ctx->pages[index].number); |
||
297 | return jbig2_image_clone(ctx, ctx->pages[index].image); |
||
298 | } |
||
299 | } |
||
300 | |||
301 | /* no pages available */ |
||
302 | return NULL; |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * jbig2_release_page: tell the library a page can be freed |
||
307 | **/ |
||
308 | int jbig2_release_page(Jbig2Ctx *ctx, Jbig2Image *image) |
||
309 | { |
||
310 | int index; |
||
311 | |||
312 | /* find the matching page struct and mark it released */ |
||
313 | for (index = 0; index < ctx->max_page_index; index++) { |
||
314 | if (ctx->pages[index].image == image) { |
||
315 | jbig2_image_release(ctx, image); |
||
316 | ctx->pages[index].state = JBIG2_PAGE_RELEASED; |
||
317 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, |
||
318 | "page %d released by the client", ctx->pages[index].number); |
||
319 | return 0; |
||
320 | } |
||
321 | } |
||
322 | |||
323 | /* no matching pages */ |
||
324 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, |
||
325 | "jbig2_release_page called on unknown page"); |
||
326 | return 1; |
||
327 | }>>>>>>=><=> |