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