1 /* Copyright (C) 1994, 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: sdcte.c,v 1.7 2002/02/21 22:24:53 giles Exp $ */
18 /* DCT encoding 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 public_st_jpeg_compress_data();
31
32 /* ------ DCTEncode ------ */
33
34 /* JPEG destination manager procedures */
35 private void
dcte_init_destination(j_compress_ptr cinfo)36 dcte_init_destination(j_compress_ptr cinfo)
37 {
38 }
39 private boolean
dcte_empty_output_buffer(j_compress_ptr cinfo)40 dcte_empty_output_buffer(j_compress_ptr cinfo)
41 {
42 return FALSE;
43 }
44 private void
dcte_term_destination(j_compress_ptr cinfo)45 dcte_term_destination(j_compress_ptr cinfo)
46 {
47 }
48
49 /* Set the defaults for the DCTEncode filter. */
50 private void
s_DCTE_set_defaults(stream_state * st)51 s_DCTE_set_defaults(stream_state * st)
52 {
53 stream_DCT_state *const ss = (stream_DCT_state *) st;
54
55 s_DCT_set_defaults(st);
56 ss->QFactor = 1.0;
57 ss->ColorTransform = -1;
58 ss->Markers.data = 0;
59 ss->Markers.size = 0;
60 ss->NoMarker = true;
61 }
62
63 /* Initialize DCTEncode filter */
64 private int
s_DCTE_init(stream_state * st)65 s_DCTE_init(stream_state * st)
66 {
67 stream_DCT_state *const ss = (stream_DCT_state *) st;
68 struct jpeg_destination_mgr *dest = &ss->data.compress->destination;
69
70 dest->init_destination = dcte_init_destination;
71 dest->empty_output_buffer = dcte_empty_output_buffer;
72 dest->term_destination = dcte_term_destination;
73 ss->data.common->memory = ss->jpeg_memory;
74 ss->data.compress->cinfo.dest = dest;
75 ss->phase = 0;
76 return 0;
77 }
78
79 /* Process a buffer */
80 private int
s_DCTE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)81 s_DCTE_process(stream_state * st, stream_cursor_read * pr,
82 stream_cursor_write * pw, bool last)
83 {
84 stream_DCT_state *const ss = (stream_DCT_state *) st;
85 jpeg_compress_data *jcdp = ss->data.compress;
86 struct jpeg_destination_mgr *dest = jcdp->cinfo.dest;
87
88 if_debug2('w', "[wde]process avail=%u, last=%d\n",
89 (uint) (pr->limit - pr->ptr), last);
90 dest->next_output_byte = pw->ptr + 1;
91 dest->free_in_buffer = pw->limit - pw->ptr;
92 switch (ss->phase) {
93 case 0: /* not initialized yet */
94 if (gs_jpeg_start_compress(ss, TRUE) < 0)
95 return ERRC;
96 if_debug4('w', "[wde]width=%u, height=%u, components=%d, scan_line_size=%u\n",
97 jcdp->cinfo.image_width,
98 jcdp->cinfo.image_height,
99 jcdp->cinfo.input_components,
100 ss->scan_line_size);
101 pw->ptr = dest->next_output_byte - 1;
102 ss->phase = 1;
103 /* falls through */
104 case 1: /* initialized, Markers not written */
105 if (pw->limit - pw->ptr < ss->Markers.size)
106 return 1;
107 memcpy(pw->ptr + 1, ss->Markers.data, ss->Markers.size);
108 pw->ptr += ss->Markers.size;
109 ss->phase = 2;
110 /* falls through */
111 case 2: /* still need to write Adobe marker */
112 if (!ss->NoMarker) {
113 static const byte Adobe[] =
114 {
115 0xFF, JPEG_APP0 + 14, 0, 14, /* parameter length */
116 'A', 'd', 'o', 'b', 'e',
117 0, 100, /* Version */
118 0, 0, /* Flags0 */
119 0, 0, /* Flags1 */
120 0 /* ColorTransform */
121 };
122
123 #define ADOBE_MARKER_LEN sizeof(Adobe)
124 if (pw->limit - pw->ptr < ADOBE_MARKER_LEN)
125 return 1;
126 memcpy(pw->ptr + 1, Adobe, ADOBE_MARKER_LEN);
127 pw->ptr += ADOBE_MARKER_LEN;
128 *pw->ptr = ss->ColorTransform;
129 #undef ADOBE_MARKER_LEN
130 }
131 dest->next_output_byte = pw->ptr + 1;
132 dest->free_in_buffer = pw->limit - pw->ptr;
133 ss->phase = 3;
134 /* falls through */
135 case 3: /* markers written, processing data */
136 while (jcdp->cinfo.image_height > jcdp->cinfo.next_scanline) {
137 int written;
138
139 /*
140 * The data argument for jpeg_write_scanlines is
141 * declared as a JSAMPARRAY. There is no corresponding
142 * const type, so we must remove const from the
143 * argument that we are passing here. (Tom Lane of IJG
144 * judges that providing const analogues of the
145 * interface types wouldn't be worth the trouble.)
146 */
147 /*const */ byte *samples = (byte *) (pr->ptr + 1);
148
149 if_debug1('w', "[wde]next_scanline=%u\n",
150 jcdp->cinfo.next_scanline);
151 if ((uint) (pr->limit - pr->ptr) < ss->scan_line_size) {
152 if (last)
153 return ERRC; /* premature EOD */
154 return 0; /* need more data */
155 }
156 written = gs_jpeg_write_scanlines(ss, &samples, 1);
157 if (written < 0)
158 return ERRC;
159 if_debug3('w', "[wde]write returns %d, used=%u, written=%u\n",
160 written,
161 (uint) (samples - 1 - pr->ptr),
162 (uint) (dest->next_output_byte - 1 - pw->ptr));
163 pw->ptr = dest->next_output_byte - 1;
164 if (!written)
165 return 1; /* output full */
166 pr->ptr += ss->scan_line_size;
167 }
168 ss->phase = 4;
169 /* falls through */
170 case 4: /* all data processed, finishing */
171 /* jpeg_finish_compress can't suspend, so write its output
172 * to a fixed-size internal buffer.
173 */
174 dest->next_output_byte = jcdp->finish_compress_buf;
175 dest->free_in_buffer = sizeof(jcdp->finish_compress_buf);
176 if (gs_jpeg_finish_compress(ss) < 0)
177 return ERRC;
178 jcdp->fcb_size =
179 dest->next_output_byte - jcdp->finish_compress_buf;
180 jcdp->fcb_pos = 0;
181 ss->phase = 5;
182 /* falls through */
183 case 5: /* copy the final data to the output */
184 if (jcdp->fcb_pos < jcdp->fcb_size) {
185 int count = min(jcdp->fcb_size - jcdp->fcb_pos,
186 pw->limit - pw->ptr);
187
188 if_debug1('w', "[wde]copying final %d\n", count);
189 memcpy(pw->ptr + 1, jcdp->finish_compress_buf + jcdp->fcb_pos,
190 count);
191 jcdp->fcb_pos += count;
192 pw->ptr += count;
193 if (jcdp->fcb_pos < jcdp->fcb_size)
194 return 1;
195 }
196 return EOFC;
197 }
198 /* Default case can't happen.... */
199 return ERRC;
200 }
201
202 /* Release the stream */
203 private void
s_DCTE_release(stream_state * st)204 s_DCTE_release(stream_state * st)
205 {
206 stream_DCT_state *const ss = (stream_DCT_state *) st;
207
208 gs_jpeg_destroy(ss);
209 gs_free_object(ss->data.common->memory, ss->data.compress,
210 "s_DCTE_release");
211 /* Switch the template pointer back in case we still need it. */
212 st->template = &s_DCTE_template;
213 }
214
215 /* Stream template */
216 const stream_template s_DCTE_template =
217 {&st_DCT_state, s_DCTE_init, s_DCTE_process, 1000, 4000, s_DCTE_release,
218 s_DCTE_set_defaults
219 };
220