1 /* Copyright (C) 1994, 1995, 1997, 1998, 1999 Aladdin Enterprises. 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: sdctd.c,v 1.4 2002/02/21 22:24:53 giles Exp $ */
18 /* DCT decoding filter stream */
19 #include "memory_.h"
20 #include "stdio_.h"
21 #include "jpeglib_.h"
22 #include "jerror_.h"
23 #include "gdebug.h"
24 #include "gsmemory.h" /* for gsmalloc.h */
25 #include "gsmalloc.h" /* for gs_memory_default */
26 #include "strimpl.h"
27 #include "sdct.h"
28 #include "sjpeg.h"
29
30 /* ------ DCTDecode ------ */
31
32 /* JPEG source manager procedures */
33 private void
dctd_init_source(j_decompress_ptr dinfo)34 dctd_init_source(j_decompress_ptr dinfo)
35 {
36 }
37 static const JOCTET fake_eoi[2] =
38 {0xFF, JPEG_EOI};
39 private boolean
dctd_fill_input_buffer(j_decompress_ptr dinfo)40 dctd_fill_input_buffer(j_decompress_ptr dinfo)
41 {
42 jpeg_decompress_data *jddp =
43 (jpeg_decompress_data *) ((char *)dinfo -
44 offset_of(jpeg_decompress_data, dinfo));
45
46 if (!jddp->input_eod)
47 return FALSE; /* normal case: suspend processing */
48 /* Reached end of source data without finding EOI */
49 WARNMS(dinfo, JWRN_JPEG_EOF);
50 /* Insert a fake EOI marker */
51 dinfo->src->next_input_byte = fake_eoi;
52 dinfo->src->bytes_in_buffer = 2;
53 jddp->faked_eoi = true; /* so process routine doesn't use next_input_byte */
54 return TRUE;
55 }
56 private void
dctd_skip_input_data(j_decompress_ptr dinfo,long num_bytes)57 dctd_skip_input_data(j_decompress_ptr dinfo, long num_bytes)
58 {
59 struct jpeg_source_mgr *src = dinfo->src;
60 jpeg_decompress_data *jddp =
61 (jpeg_decompress_data *) ((char *)dinfo -
62 offset_of(jpeg_decompress_data, dinfo));
63
64 if (num_bytes > 0) {
65 if (num_bytes > src->bytes_in_buffer) {
66 jddp->skip += num_bytes - src->bytes_in_buffer;
67 src->next_input_byte += src->bytes_in_buffer;
68 src->bytes_in_buffer = 0;
69 return;
70 }
71 src->next_input_byte += num_bytes;
72 src->bytes_in_buffer -= num_bytes;
73 }
74 }
75 private void
dctd_term_source(j_decompress_ptr dinfo)76 dctd_term_source(j_decompress_ptr dinfo)
77 {
78 }
79
80 /* Set the defaults for the DCTDecode filter. */
81 private void
s_DCTD_set_defaults(stream_state * st)82 s_DCTD_set_defaults(stream_state * st)
83 {
84 s_DCT_set_defaults(st);
85 }
86
87 /* Initialize DCTDecode filter */
88 private int
s_DCTD_init(stream_state * st)89 s_DCTD_init(stream_state * st)
90 {
91 stream_DCT_state *const ss = (stream_DCT_state *) st;
92 struct jpeg_source_mgr *src = &ss->data.decompress->source;
93
94 src->init_source = dctd_init_source;
95 src->fill_input_buffer = dctd_fill_input_buffer;
96 src->skip_input_data = dctd_skip_input_data;
97 src->term_source = dctd_term_source;
98 src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
99 ss->data.common->memory = ss->jpeg_memory;
100 ss->data.decompress->dinfo.src = src;
101 ss->data.decompress->skip = 0;
102 ss->data.decompress->input_eod = false;
103 ss->data.decompress->faked_eoi = false;
104 ss->phase = 0;
105 return 0;
106 }
107
108 /* Process a buffer */
109 private int
s_DCTD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)110 s_DCTD_process(stream_state * st, stream_cursor_read * pr,
111 stream_cursor_write * pw, bool last)
112 {
113 stream_DCT_state *const ss = (stream_DCT_state *) st;
114 jpeg_decompress_data *jddp = ss->data.decompress;
115 struct jpeg_source_mgr *src = jddp->dinfo.src;
116 int code;
117
118 if_debug3('w', "[wdd]process avail=%u, skip=%u, last=%d\n",
119 (uint) (pr->limit - pr->ptr), (uint) jddp->skip, last);
120 if (jddp->skip != 0) {
121 long avail = pr->limit - pr->ptr;
122
123 if (avail < jddp->skip) {
124 jddp->skip -= avail;
125 pr->ptr = pr->limit;
126 if (!last)
127 return 0; /* need more data */
128 jddp->skip = 0; /* don't skip past input EOD */
129 }
130 pr->ptr += jddp->skip;
131 jddp->skip = 0;
132 }
133 src->next_input_byte = pr->ptr + 1;
134 src->bytes_in_buffer = pr->limit - pr->ptr;
135 jddp->input_eod = last;
136 switch (ss->phase) {
137 case 0: /* not initialized yet */
138 /*
139 * Adobe implementations seem to ignore leading garbage bytes,
140 * even though neither the standard nor Adobe's own
141 * documentation mention this.
142 */
143 while (pr->ptr < pr->limit && pr->ptr[1] != 0xff)
144 pr->ptr++;
145 if (pr->ptr == pr->limit)
146 return 0;
147 src->next_input_byte = pr->ptr + 1;
148 src->bytes_in_buffer = pr->limit - pr->ptr;
149 ss->phase = 1;
150 /* falls through */
151 case 1: /* reading header markers */
152 if ((code = gs_jpeg_read_header(ss, TRUE)) < 0)
153 return ERRC;
154 pr->ptr =
155 (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
156 switch (code) {
157 case JPEG_SUSPENDED:
158 return 0;
159 /*case JPEG_HEADER_OK: */
160 }
161 /* If we have a ColorTransform parameter, and it's not
162 * overridden by an Adobe marker in the data, set colorspace.
163 */
164 if (ss->ColorTransform >= 0 &&
165 !jddp->dinfo.saw_Adobe_marker) {
166 switch (jddp->dinfo.num_components) {
167 case 3:
168 jddp->dinfo.jpeg_color_space =
169 (ss->ColorTransform ? JCS_YCbCr : JCS_RGB);
170 /* out_color_space will default to JCS_RGB */
171 break;
172 case 4:
173 jddp->dinfo.jpeg_color_space =
174 (ss->ColorTransform ? JCS_YCCK : JCS_CMYK);
175 /* out_color_space will default to JCS_CMYK */
176 break;
177 }
178 }
179 ss->phase = 2;
180 /* falls through */
181 case 2: /* start_decompress */
182 if ((code = gs_jpeg_start_decompress(ss)) < 0)
183 return ERRC;
184 pr->ptr =
185 (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
186 if (code == 0)
187 return 0;
188 ss->scan_line_size =
189 jddp->dinfo.output_width * jddp->dinfo.output_components;
190 if_debug4('w', "[wdd]width=%u, components=%d, scan_line_size=%u, min_out_size=%u\n",
191 jddp->dinfo.output_width,
192 jddp->dinfo.output_components,
193 ss->scan_line_size, jddp->template.min_out_size);
194 if (ss->scan_line_size > (uint) jddp->template.min_out_size) {
195 /* Create a spare buffer for oversize scanline */
196 jddp->scanline_buffer =
197 gs_alloc_bytes_immovable(jddp->memory,
198 ss->scan_line_size,
199 "s_DCTD_process(scanline_buffer)");
200 if (jddp->scanline_buffer == NULL)
201 return ERRC;
202 }
203 jddp->bytes_in_scanline = 0;
204 ss->phase = 3;
205 /* falls through */
206 case 3: /* reading data */
207 dumpbuffer:
208 if (jddp->bytes_in_scanline != 0) {
209 uint avail = pw->limit - pw->ptr;
210 uint tomove = min(jddp->bytes_in_scanline,
211 avail);
212
213 if_debug2('w', "[wdd]moving %u/%u\n",
214 tomove, avail);
215 memcpy(pw->ptr + 1, jddp->scanline_buffer +
216 (ss->scan_line_size - jddp->bytes_in_scanline),
217 tomove);
218 pw->ptr += tomove;
219 jddp->bytes_in_scanline -= tomove;
220 if (jddp->bytes_in_scanline != 0)
221 return 1; /* need more room */
222 }
223 while (jddp->dinfo.output_height > jddp->dinfo.output_scanline) {
224 int read;
225 byte *samples;
226
227 if (jddp->scanline_buffer != NULL)
228 samples = jddp->scanline_buffer;
229 else {
230 if ((uint) (pw->limit - pw->ptr) < ss->scan_line_size)
231 return 1; /* need more room */
232 samples = pw->ptr + 1;
233 }
234 read = gs_jpeg_read_scanlines(ss, &samples, 1);
235 if (read < 0)
236 return ERRC;
237 if_debug3('w', "[wdd]read returns %d, used=%u, faked_eoi=%d\n",
238 read,
239 (uint) (src->next_input_byte - 1 - pr->ptr),
240 (int)jddp->faked_eoi);
241 pr->ptr =
242 (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
243 if (!read)
244 return 0; /* need more data */
245 if (jddp->scanline_buffer != NULL) {
246 jddp->bytes_in_scanline = ss->scan_line_size;
247 goto dumpbuffer;
248 }
249 pw->ptr += ss->scan_line_size;
250 }
251 ss->phase = 4;
252 /* falls through */
253 case 4: /* end of image; scan for EOI */
254 if ((code = gs_jpeg_finish_decompress(ss)) < 0)
255 return ERRC;
256 pr->ptr =
257 (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
258 if (code == 0)
259 return 0;
260 ss->phase = 5;
261 /* falls through */
262 case 5: /* we are DONE */
263 return EOFC;
264 }
265 /* Default case can't happen.... */
266 return ERRC;
267 }
268
269 /* Release the stream */
270 private void
s_DCTD_release(stream_state * st)271 s_DCTD_release(stream_state * st)
272 {
273 stream_DCT_state *const ss = (stream_DCT_state *) st;
274
275 gs_jpeg_destroy(ss);
276 if (ss->data.decompress->scanline_buffer != NULL)
277 gs_free_object(ss->data.common->memory,
278 ss->data.decompress->scanline_buffer,
279 "s_DCTD_release(scanline_buffer)");
280 gs_free_object(ss->data.common->memory, ss->data.decompress,
281 "s_DCTD_release");
282 /* Switch the template pointer back in case we still need it. */
283 st->template = &s_DCTD_template;
284 }
285
286 /* Stream template */
287 const stream_template s_DCTD_template =
288 {&st_DCT_state, s_DCTD_init, s_DCTD_process, 2000, 4000, s_DCTD_release,
289 s_DCTD_set_defaults
290 };
291