xref: /plan9/sys/src/cmd/gs/src/sdeparam.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 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: sdeparam.c,v 1.6 2002/02/21 22:24:54 giles Exp $ */
18 /* DCTEncode filter parameter setting and reading */
19 #include "memory_.h"
20 #include "jpeglib_.h"
21 #include "gserror.h"
22 #include "gserrors.h"
23 #include "gstypes.h"
24 #include "gsmemory.h"
25 #include "gsparam.h"
26 #include "strimpl.h"		/* sdct.h requires this */
27 #include "sdct.h"
28 #include "sdcparam.h"
29 #include "sjpeg.h"
30 
31 /* Define a structure for the DCTEncode scalar parameters. */
32 typedef struct dcte_scalars_s {
33     int Columns;
34     int Rows;
35     int Colors;
36     gs_param_string Markers;
37     bool NoMarker;
38     int Resync;
39     int Blend;
40 } dcte_scalars_t;
41 private const dcte_scalars_t dcte_scalars_default =
42 {
43     0, 0, -1,
44     {0, 0}, 0 /*false */ , 0, 0
45 };
46 private const gs_param_item_t s_DCTE_param_items[] =
47 {
48 #define dctp(key, type, memb) { key, type, offset_of(dcte_scalars_t, memb) }
49     dctp("Columns", gs_param_type_int, Columns),
50     dctp("Rows", gs_param_type_int, Rows),
51     dctp("Colors", gs_param_type_int, Colors),
52     dctp("Marker", gs_param_type_string, Markers),
53     dctp("NoMarker", gs_param_type_bool, NoMarker),
54     dctp("Resync", gs_param_type_int, Resync),
55     dctp("Blend", gs_param_type_int, Blend),
56 #undef dctp
57     gs_param_item_end
58 };
59 
60 /* ================ Get parameters ================ */
61 
62 stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);	/* check */
63 
64 /* Get a set of sampling values. */
65 private int
dcte_get_samples(gs_param_list * plist,gs_param_name key,int num_colors,const jpeg_compress_data * jcdp,gs_memory_t * mem,bool is_vert,bool all)66 dcte_get_samples(gs_param_list * plist, gs_param_name key, int num_colors,
67  const jpeg_compress_data * jcdp, gs_memory_t * mem, bool is_vert, bool all)
68 {
69     const jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
70     int samples[4];
71     bool write = all;
72     int i;
73 
74     for (i = 0; i < num_colors; ++i)
75 	write |= (samples[i] = (is_vert ? comp_info[i].v_samp_factor :
76 				comp_info[i].h_samp_factor)) != 1;
77     if (write) {
78 	int *data = (int *)gs_alloc_byte_array(mem, num_colors, sizeof(int),
79 					       "dcte_get_samples");
80 	gs_param_int_array sa;
81 
82 	if (data == 0)
83 	    return_error(gs_error_VMerror);
84 	sa.data = data;
85 	sa.size = num_colors;
86 	sa.persistent = true;
87 	memcpy(data, samples, num_colors * sizeof(samples[0]));
88 	return param_write_int_array(plist, key, &sa);
89     }
90     return 0;
91 }
92 
93 int
s_DCTE_get_params(gs_param_list * plist,const stream_DCT_state * ss,bool all)94 s_DCTE_get_params(gs_param_list * plist, const stream_DCT_state * ss, bool all)
95 {
96     gs_memory_t *mem = ss->memory;
97     stream_DCT_state dcts_defaults;
98     const stream_DCT_state *defaults = 0;
99     dcte_scalars_t params;
100     const jpeg_compress_data *jcdp = ss->data.compress;
101     int code;
102 
103     if (!all) {
104 	jpeg_compress_data *jcdp_default = gs_alloc_struct_immovable(mem,
105            jpeg_compress_data, &st_jpeg_compress_data, "s_DCTE_get_params");
106 	if (jcdp_default == 0)
107 	    return_error(gs_error_VMerror);
108 	defaults = &dcts_defaults;
109 	(*s_DCTE_template.set_defaults) ((stream_state *) & dcts_defaults);
110 	dcts_defaults.data.compress = jcdp_default;
111 	jcdp_default->memory = dcts_defaults.jpeg_memory = mem;
112 	if ((code = gs_jpeg_create_compress(&dcts_defaults)) < 0)
113 	    goto fail;		/* correct to do jpeg_destroy here */
114 /****** SET DEFAULTS HERE ******/
115 	dcts_defaults.data.common->Picky = 0;
116 	dcts_defaults.data.common->Relax = 0;
117     }
118     params.Columns = jcdp->cinfo.image_width;
119     params.Rows = jcdp->cinfo.image_height;
120     params.Colors = jcdp->cinfo.input_components;
121     params.Markers.data = ss->Markers.data;
122     params.Markers.size = ss->Markers.size;
123     params.Markers.persistent = false;
124     params.NoMarker = ss->NoMarker;
125     params.Resync = jcdp->cinfo.restart_interval;
126     /* What about Blend?? */
127     if ((code = s_DCT_get_params(plist, ss, defaults)) < 0 ||
128 	(code = gs_param_write_items(plist, &params,
129 				     &dcte_scalars_default,
130 				     s_DCTE_param_items)) < 0 ||
131 	(code = dcte_get_samples(plist, "HSamples", params.Colors,
132 				 jcdp, mem, false, all)) < 0 ||
133 	(code = dcte_get_samples(plist, "VSamples", params.Colors,
134 				 jcdp, mem, true, all)) < 0 ||
135     (code = s_DCT_get_quantization_tables(plist, ss, defaults, true)) < 0 ||
136 	(code = s_DCT_get_huffman_tables(plist, ss, defaults, true)) < 0
137 	)
138 	DO_NOTHING;
139 /****** NYI ******/
140   fail:if (defaults) {
141 	gs_jpeg_destroy(&dcts_defaults);
142 	gs_free_object(mem, dcts_defaults.data.compress,
143 		       "s_DCTE_get_params");
144     }
145     return code;
146 }
147 
148 /* ================ Put parameters ================ */
149 
150 stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);	/* check */
151 
152 /* Put a set of sampling values. */
153 private int
dcte_put_samples(gs_param_list * plist,gs_param_name key,int num_colors,jpeg_compress_data * jcdp,bool is_vert)154 dcte_put_samples(gs_param_list * plist, gs_param_name key, int num_colors,
155 		 jpeg_compress_data * jcdp, bool is_vert)
156 {
157     int code;
158     int i;
159     jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
160     UINT8 samples[4];
161 
162     /*
163      * Adobe default is all sampling factors = 1,
164      * which is NOT the IJG default, so we must always assign values.
165      */
166     switch ((code = s_DCT_byte_params(plist, key, 0, num_colors,
167 				      samples))
168 	) {
169 	default:		/* error */
170 	    return code;
171 	case 0:
172 	    break;
173 	case 1:
174 	    samples[0] = samples[1] = samples[2] = samples[3] = 1;
175     }
176     for (i = 0; i < num_colors; i++) {
177 	if (samples[i] < 1 || samples[i] > 4)
178 	    return_error(gs_error_rangecheck);
179 	if (is_vert)
180 	    comp_info[i].v_samp_factor = samples[i];
181 	else
182 	    comp_info[i].h_samp_factor = samples[i];
183     }
184     return 0;
185 }
186 
187 /* Main procedure */
188 int
s_DCTE_put_params(gs_param_list * plist,stream_DCT_state * pdct)189 s_DCTE_put_params(gs_param_list * plist, stream_DCT_state * pdct)
190 {
191     jpeg_compress_data *jcdp = pdct->data.compress;
192     dcte_scalars_t params;
193     int i;
194     int code;
195 
196     params = dcte_scalars_default;
197     /*
198      * Required parameters for DCTEncode.
199      * (DCTDecode gets the equivalent info from the SOF marker.)
200      */
201     code = gs_param_read_items(plist, &params, s_DCTE_param_items);
202     if (code < 0)
203 	return code;
204     if (params.Columns <= 0 || params.Columns > 0xffff ||
205 	params.Rows <= 0 || params.Rows > 0xffff ||
206 	params.Colors <= 0 || params.Colors == 2 || params.Colors > 4 ||
207 	params.Resync < 0 || params.Resync > 0xffff ||
208 	params.Blend < 0 || params.Blend > 1
209 	)
210 	return_error(gs_error_rangecheck);
211     jcdp->Picky = 0;
212     jcdp->Relax = 0;
213     if ((code = s_DCT_put_params(plist, pdct)) < 0)
214 	return code;
215     /* Set up minimal image description & call set_defaults */
216     jcdp->cinfo.image_width = params.Columns;
217     jcdp->cinfo.image_height = params.Rows;
218     jcdp->cinfo.input_components = params.Colors;
219     switch (params.Colors) {
220 	case 1:
221 	    jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
222 	    break;
223 	case 3:
224 	    jcdp->cinfo.in_color_space = JCS_RGB;
225 	    break;
226 	case 4:
227 	    jcdp->cinfo.in_color_space = JCS_CMYK;
228 	    break;
229 	default:
230 	    jcdp->cinfo.in_color_space = JCS_UNKNOWN;
231     }
232     if ((code = gs_jpeg_set_defaults(pdct)) < 0)
233 	return code;
234     if ((code = s_DCT_put_huffman_tables(plist, pdct, false)) < 0)
235 	return code;
236     switch ((code = s_DCT_put_quantization_tables(plist, pdct, false))) {
237 	case 0:
238 	    break;
239 	default:
240 	    return code;
241 	case 1:
242 	    /* No QuantTables, but maybe a QFactor to apply to default. */
243 	    if (pdct->QFactor != 1.0) {
244 		code = gs_jpeg_set_linear_quality(pdct,
245 					     (int)(min(pdct->QFactor, 100.0)
246 						   * 100.0 + 0.5),
247 						  TRUE);
248 		if (code < 0)
249 		    return code;
250 	    }
251     }
252     /* Change IJG colorspace defaults as needed;
253      * set ColorTransform to what will go in the Adobe marker.
254      */
255     switch (params.Colors) {
256 	case 3:
257 	    if (pdct->ColorTransform < 0)
258 		pdct->ColorTransform = 1;	/* default */
259 	    if (pdct->ColorTransform == 0) {
260 		if ((code = gs_jpeg_set_colorspace(pdct, JCS_RGB)) < 0)
261 		    return code;
262 	    } else
263 		pdct->ColorTransform = 1;	/* flag YCC xform */
264 	    break;
265 	case 4:
266 	    if (pdct->ColorTransform < 0)
267 		pdct->ColorTransform = 0;	/* default */
268 	    if (pdct->ColorTransform != 0) {
269 		if ((code = gs_jpeg_set_colorspace(pdct, JCS_YCCK)) < 0)
270 		    return code;
271 		pdct->ColorTransform = 2;	/* flag YCCK xform */
272 	    } else {
273 		if ((code = gs_jpeg_set_colorspace(pdct, JCS_CMYK)) < 0)
274 		    return code;
275 	    }
276 	    break;
277 	default:
278 	    pdct->ColorTransform = 0;	/* no transform otherwise */
279 	    break;
280     }
281     /* Optional encoding-only parameters */
282     pdct->Markers.data = params.Markers.data;
283     pdct->Markers.size = params.Markers.size;
284     pdct->NoMarker = params.NoMarker;
285     if ((code = dcte_put_samples(plist, "HSamples", params.Colors,
286 				 jcdp, false)) < 0 ||
287 	(code = dcte_put_samples(plist, "VSamples", params.Colors,
288 				 jcdp, true)) < 0
289 	)
290 	return code;
291     jcdp->cinfo.write_JFIF_header = FALSE;
292     jcdp->cinfo.write_Adobe_marker = FALSE;	/* must do it myself */
293     jcdp->cinfo.restart_interval = params.Resync;
294     /* What to do with Blend ??? */
295     if (pdct->data.common->Relax == 0) {
296 	jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
297 	int num_samples;
298 
299 	for (i = 0, num_samples = 0; i < params.Colors; i++)
300 	    num_samples += comp_info[i].h_samp_factor *
301 		comp_info[i].v_samp_factor;
302 	if (num_samples > 10)
303 	    return_error(gs_error_rangecheck);
304 	/*
305 	 * Note: by default the IJG software does not allow
306 	 * num_samples to exceed 10, Relax or no.  For full
307 	 * compatibility with Adobe's non-JPEG-compliant
308 	 * software, set MAX_BLOCKS_IN_MCU to 64 in jpeglib.h.
309 	 */
310     }
311     return 0;
312 }
313