xref: /plan9/sys/src/cmd/gs/src/sdcte.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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