/src/ghostpdl/pcl/pcl/pcjob.c
Line | Count | Source |
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 | | /* pcjob.c - PCL5 job control commands */ |
18 | | #include "std.h" |
19 | | #include "gx.h" |
20 | | #include "gsmemory.h" |
21 | | #include "gspaint.h" |
22 | | #include "gsmatrix.h" /* for gsdevice.h */ |
23 | | #include "gsdevice.h" |
24 | | #include "pcommand.h" |
25 | | #include "pcursor.h" /* for pcl_home_cursor() */ |
26 | | #include "pcstate.h" |
27 | | #include "pcparam.h" |
28 | | #include "pcdraw.h" |
29 | | #include "pcpage.h" |
30 | | #include "pjtop.h" |
31 | | #include <stdlib.h> /* for atof() */ |
32 | | #include "gzstate.h" |
33 | | #include "plparams.h" |
34 | | |
35 | | /* Commands */ |
36 | | |
37 | | int |
38 | | pcl_do_printer_reset(pcl_state_t * pcs) |
39 | 28.5k | { |
40 | 28.5k | int code = 0; |
41 | 28.5k | if (pcs->macro_level) |
42 | 0 | return e_Range; /* not allowed inside macro */ |
43 | | |
44 | | /* reset the other parser in case we have gotten the |
45 | | pcl_printer_reset while in gl/2 mode. */ |
46 | 28.5k | code = pcl_implicit_gl2_finish(pcs); |
47 | 28.5k | if (code < 0) |
48 | 0 | return code; |
49 | | /* Print any partial page if not pclxl snippet mode. */ |
50 | 28.5k | if (pcs->end_page == pcl_end_page_top) { |
51 | 28.5k | code = pcl_end_page_if_marked(pcs); |
52 | | |
53 | 28.5k | if (code < 0) |
54 | 0 | return code; |
55 | | /* if duplex start on the front side of the paper */ |
56 | 28.5k | if (pcs->duplex) |
57 | 59 | code = put_param1_bool(pcs, "FirstSide", true); |
58 | 28.5k | if (code < 0) |
59 | 0 | return code; |
60 | 28.5k | } |
61 | | /* unload fonts */ |
62 | | |
63 | | /* Reset to user default state. */ |
64 | 28.5k | return pcl_do_resets(pcs, pcl_reset_printer); |
65 | 28.5k | } |
66 | | |
67 | | static int /* ESC E */ |
68 | | pcl_printer_reset(pcl_args_t * pargs, pcl_state_t * pcs) |
69 | 20.1k | { |
70 | 20.1k | return pcl_do_printer_reset(pcs); |
71 | 20.1k | } |
72 | | |
73 | | static int /* ESC % -12345 X */ |
74 | | pcl_exit_language(pcl_args_t * pargs, pcl_state_t * pcs) |
75 | 10.7k | { |
76 | 10.7k | if (int_arg(pargs) != -12345) |
77 | 3.33k | return e_Range; |
78 | 7.38k | { |
79 | 7.38k | int code = pcl_printer_reset(pargs, pcs); |
80 | | |
81 | 7.38k | return (code < 0 ? code : e_ExitLanguage); |
82 | 10.7k | } |
83 | 10.7k | } |
84 | | |
85 | | static int /* ESC & l <num_copies> X */ |
86 | | pcl_number_of_copies(pcl_args_t * pargs, pcl_state_t * pcs) |
87 | 2.41k | { |
88 | 2.41k | int i = int_arg(pargs); |
89 | | |
90 | 2.41k | if (i < 1) |
91 | 27 | return 0; |
92 | 2.39k | pcs->num_copies = i; |
93 | 2.39k | return put_param1_int(pcs, "NumCopies", i); |
94 | 2.41k | } |
95 | | |
96 | | static int /* ESC & l <sd_enum> S */ |
97 | | pcl_simplex_duplex_print(pcl_args_t * pargs, pcl_state_t * pcs) |
98 | 154 | { |
99 | 154 | int code; |
100 | 154 | bool reopen = false; |
101 | | |
102 | | /* oddly the command goes to the next page irrespective of |
103 | | arguments */ |
104 | 154 | code = pcl_end_page_if_marked(pcs); |
105 | 154 | if (code < 0) |
106 | 0 | return code; |
107 | 154 | code = pcl_home_cursor(pcs); |
108 | 154 | if (code < 0) |
109 | 0 | return code; |
110 | 154 | switch (int_arg(pargs)) { |
111 | 76 | case 0: |
112 | 76 | pcs->duplex = false; |
113 | 76 | pcs->back_side = false; |
114 | 76 | break; |
115 | 64 | case 1: |
116 | 64 | pcs->duplex = true; |
117 | 64 | pcs->back_side = false; |
118 | 64 | pcs->bind_short_edge = false; |
119 | 64 | break; |
120 | 11 | case 2: |
121 | 11 | pcs->duplex = true; |
122 | 11 | pcs->back_side = false; |
123 | 11 | pcs->bind_short_edge = true; |
124 | 11 | break; |
125 | 3 | default: |
126 | 3 | return 0; |
127 | 154 | } |
128 | 151 | code = put_param1_bool(pcs, "Duplex", pcs->duplex); |
129 | 151 | switch (code) { |
130 | 0 | case 1: /* reopen device */ |
131 | 0 | reopen = true; |
132 | 151 | case 0: |
133 | 151 | break; |
134 | 0 | case gs_error_undefined: |
135 | 0 | return 0; |
136 | 0 | default: /* error */ |
137 | 0 | if (code < 0) |
138 | 0 | return code; |
139 | 151 | } |
140 | 151 | code = put_param1_bool(pcs, "FirstSide", !pcs->back_side); |
141 | 151 | switch (code) { |
142 | 0 | case 1: /* reopen device */ |
143 | 0 | reopen = true; |
144 | 151 | case 0: |
145 | 151 | break; |
146 | 0 | case gs_error_undefined: |
147 | 0 | return 0; |
148 | 0 | default: /* error */ |
149 | 0 | if (code < 0) |
150 | 0 | return code; |
151 | 151 | } |
152 | 151 | code = put_param1_bool(pcs, "BindShortEdge", pcs->bind_short_edge); |
153 | 151 | switch (code) { |
154 | 0 | case 1: /* reopen device */ |
155 | 0 | reopen = true; |
156 | 151 | case 0: |
157 | 151 | case gs_error_undefined: |
158 | 151 | break; |
159 | 0 | default: /* error */ |
160 | 0 | if (code < 0) |
161 | 0 | return code; |
162 | 151 | } |
163 | 151 | return (reopen ? gs_setdevice_no_erase(pcs->pgs, |
164 | 151 | gs_currentdevice(pcs->pgs)) : 0); |
165 | 151 | } |
166 | | |
167 | | static int /* ESC & a <side_enum> G */ |
168 | | pcl_duplex_page_side_select(pcl_args_t * pargs, pcl_state_t * pcs) |
169 | 46 | { |
170 | 46 | uint i = uint_arg(pargs); |
171 | 46 | int code = 0; |
172 | | |
173 | | /* oddly the command goes to the next page irrespective of |
174 | | arguments */ |
175 | 46 | code = pcl_end_page_if_marked(pcs); |
176 | 46 | if (i > 2) |
177 | 40 | return 0; |
178 | | |
179 | | /* home the cursor even if the command has no effect */ |
180 | 6 | if (code >= 0) { |
181 | 6 | int errcode = pcl_home_cursor(pcs); |
182 | 6 | if (errcode < 0) |
183 | 0 | return errcode; |
184 | 6 | } |
185 | | |
186 | | /* if there is an error (code < 0) or the page is unmarked (code |
187 | | == 0) then nothing to update */ |
188 | 6 | if (code <= 0) |
189 | 1 | return code; |
190 | | |
191 | | |
192 | 5 | if (pcs->duplex) { |
193 | 0 | switch (i) { |
194 | 0 | case 0: |
195 | | /* do nothing, back_side was updated by |
196 | | pcl_end_page_if_marked() above */ |
197 | 0 | break; |
198 | 0 | case 1: |
199 | 0 | pcs->back_side = false; |
200 | 0 | break; |
201 | 0 | case 2: |
202 | 0 | pcs->back_side = true; |
203 | 0 | break; |
204 | 0 | default: |
205 | | /* can't happen */ |
206 | 0 | break; |
207 | 0 | } |
208 | 0 | code = put_param1_bool(pcs, "FirstSide", !pcs->back_side); |
209 | 0 | } |
210 | 5 | return code; |
211 | 5 | } |
212 | | |
213 | | static int /* ESC & l 1 T */ |
214 | | pcl_job_separation(pcl_args_t * pargs, pcl_state_t * pcs) |
215 | 528 | { |
216 | 528 | int i = int_arg(pargs); |
217 | | |
218 | 528 | if (i != 1) |
219 | 229 | return 0; |
220 | | /**** NEED A DRIVER PROCEDURE FOR END-OF-JOB ****/ |
221 | 299 | return 0; |
222 | 528 | } |
223 | | |
224 | | static int /* ESC & l <bin_enum> G */ |
225 | | pcl_output_bin_selection(pcl_args_t * pargs, pcl_state_t * pcs) |
226 | 3 | { |
227 | 3 | uint i = uint_arg(pargs); |
228 | | |
229 | 3 | if (i < 1 || i > 2) |
230 | 2 | return e_Range; |
231 | 1 | return put_param1_int(pcs, "OutputBin", i); |
232 | 3 | } |
233 | | |
234 | | static int /* ESC & u <upi> B */ |
235 | | pcl_set_unit_of_measure(pcl_args_t * pargs, pcl_state_t * pcs) |
236 | 61.4k | { |
237 | 61.4k | int num = int_arg(pargs); |
238 | | |
239 | 61.4k | if (num <= 96) |
240 | 10 | num = 96; |
241 | 61.4k | else if (num >= 7200) |
242 | 0 | num = 7200; |
243 | 61.4k | else if (7200 % num != 0) { /* Pick the exact divisor of 7200 with the smallest */ |
244 | | /* relative error. */ |
245 | 41 | static const int values[] = { |
246 | 41 | 96, 100, 120, 144, 150, 160, 180, 200, 225, 240, 288, |
247 | 41 | 300, 360, 400, 450, 480, 600, 720, 800, 900, |
248 | 41 | 1200, 1440, 1800, 2400, 3600, 7200 |
249 | 41 | }; |
250 | 41 | const int *p = values; |
251 | | |
252 | 658 | while (num > p[1]) |
253 | 617 | p++; |
254 | | /* Now *p < num < p[1]. */ |
255 | 41 | if ((p[1] - (float)num) / p[1] < ((float)num - *p) / *p) |
256 | 39 | p++; |
257 | 41 | num = *p; |
258 | 41 | } |
259 | 61.4k | pcs->uom_cp = pcl_coord_scale / num; |
260 | 61.4k | return 0; |
261 | 61.4k | } |
262 | | |
263 | | /* Initialization */ |
264 | | static int |
265 | | pcjob_do_registration(pcl_parser_state_t * pcl_parser_state, |
266 | | gs_memory_t * mem) |
267 | 16.0k | { /* Register commands */ |
268 | 16.0k | DEFINE_ESCAPE_ARGS('E', "Printer Reset", pcl_printer_reset, pca_in_rtl) |
269 | 16.0k | DEFINE_CLASS('%') { |
270 | 16.0k | 0, 'X', { |
271 | 16.0k | pcl_exit_language, pca_neg_ok | pca_big_error | pca_in_rtl}}, |
272 | 16.0k | END_CLASS DEFINE_CLASS('&') { |
273 | 16.0k | 'l', 'X', |
274 | 16.0k | PCL_COMMAND("Number of Copies", pcl_number_of_copies, |
275 | 16.0k | pca_neg_ignore | pca_big_clamp)}, { |
276 | 16.0k | 'l', 'S', |
277 | 16.0k | PCL_COMMAND("Simplex/Duplex Print", pcl_simplex_duplex_print, |
278 | 16.0k | pca_neg_ignore | pca_big_ignore)}, { |
279 | 16.0k | 'a', 'G', |
280 | 16.0k | PCL_COMMAND("Duplex Page Side Select", |
281 | 16.0k | pcl_duplex_page_side_select, |
282 | 16.0k | pca_neg_ignore | pca_big_ignore)}, { |
283 | 16.0k | 'l', 'T', |
284 | 16.0k | PCL_COMMAND("Job Separation", pcl_job_separation, |
285 | 16.0k | pca_neg_error | pca_big_error)}, { |
286 | 16.0k | 'l', 'G', |
287 | 16.0k | PCL_COMMAND("Output Bin Selection", pcl_output_bin_selection, |
288 | 16.0k | pca_neg_error | pca_big_error)}, { |
289 | 16.0k | 'u', 'D', |
290 | 16.0k | PCL_COMMAND("Set Unit of Measure", pcl_set_unit_of_measure, |
291 | 16.0k | pca_neg_error | pca_big_error | pca_in_rtl)}, |
292 | 16.0k | END_CLASS return 0; |
293 | 16.0k | } |
294 | | |
295 | | static inline float |
296 | | pcl_pjl_res(pcl_state_t * pcs) |
297 | 16.0k | { |
298 | 16.0k | pjl_envvar_t *pres = pjl_proc_get_envvar(pcs->pjls, "resolution"); |
299 | | |
300 | 16.0k | return atof(pres); |
301 | 16.0k | } |
302 | | |
303 | | static int |
304 | | pcjob_do_copy(pcl_state_t *psaved, const pcl_state_t *pcs, |
305 | | pcl_copy_operation_t operation) |
306 | 0 | { |
307 | 0 | if (operation & pcl_copy_after_overlay) { |
308 | 0 | psaved->back_side = pcs->back_side; |
309 | 0 | } |
310 | 0 | return 0; |
311 | 0 | } |
312 | | |
313 | | static int |
314 | | pcjob_do_reset(pcl_state_t * pcs, pcl_reset_type_t type) |
315 | 60.2k | { |
316 | 60.2k | int code; |
317 | | |
318 | 60.2k | if (type & (pcl_reset_initial | pcl_reset_printer)) { |
319 | | /* check for a resolution setting from PJL and set it right |
320 | | away, there is no pcl command to set the resolution so a |
321 | | state variable is not needed. Don't override -r from the command line. */ |
322 | 60.2k | if (!pcs->res_set_on_command_line) { |
323 | 16.0k | gx_device *pdev = gs_currentdevice(pcs->pgs); |
324 | 16.0k | float res[2]; |
325 | 16.0k | gs_point device_res; |
326 | | |
327 | 16.0k | device_res.x = pdev->HWResolution[0]; |
328 | 16.0k | device_res.y = pdev->HWResolution[1]; |
329 | | |
330 | | /* resolution is always a single number in PJL */ |
331 | 16.0k | res[0] = res[1] = pcl_pjl_res(pcs); |
332 | | |
333 | | /* |
334 | | * again we only have a single number from PJL so just |
335 | | * check the width |
336 | | */ |
337 | | |
338 | 16.0k | if (res[0] != 0 && res[0] != device_res.x) { |
339 | 0 | code = put_param1_float_array(pcs, "HWResolution", res); |
340 | 0 | if (code < 0) |
341 | 0 | return code; |
342 | 0 | code = gs_erasepage(pcs->pgs); |
343 | 0 | if (code < 0) |
344 | 0 | return code; |
345 | 0 | } |
346 | 16.0k | } |
347 | | |
348 | 60.2k | pcs->num_copies = pjl_proc_vartoi(pcs->pjls, |
349 | 60.2k | pjl_proc_get_envvar(pcs->pjls, |
350 | 60.2k | "copies")); |
351 | 60.2k | pcs->duplex = |
352 | 60.2k | !pjl_proc_compare(pcs->pjls, |
353 | 60.2k | pjl_proc_get_envvar(pcs->pjls, "duplex"), |
354 | 60.2k | "off") ? false : true; |
355 | 60.2k | pcs->bind_short_edge = |
356 | 60.2k | !pjl_proc_compare(pcs->pjls, |
357 | 60.2k | pjl_proc_get_envvar(pcs->pjls, "binding"), |
358 | 60.2k | "longedge") ? false : true; |
359 | 60.2k | pcs->back_side = false; |
360 | 60.2k | pcs->output_bin = 1; |
361 | 60.2k | code = put_param1_bool(pcs, "Duplex", pcs->duplex); |
362 | 60.2k | if (code < 0) |
363 | 0 | return code; |
364 | 60.2k | code = put_param1_bool(pcs, "FirstSide", !pcs->back_side); |
365 | 60.2k | if (code < 0) |
366 | 0 | return code; |
367 | 60.2k | code = put_param1_bool(pcs, "BindShortEdge", pcs->bind_short_edge); |
368 | 60.2k | if (code < 0) |
369 | 0 | return code; |
370 | 60.2k | code = put_param1_int(pcs, "PageSpotColors", 0); |
371 | 60.2k | if (code < 0) |
372 | 0 | return code; |
373 | 60.2k | } |
374 | | |
375 | 60.2k | if (type & (pcl_reset_initial ^ pcl_reset_cold ^ pcl_reset_printer)) |
376 | 60.2k | { |
377 | 60.2k | pjl_envvar_t *pres; |
378 | | |
379 | 60.2k | pres = pjl_proc_get_envvar(pcs->pjls, "pdfmark"); |
380 | 60.2k | if (strlen(pres) > 0) { |
381 | 0 | code = pcl_pjl_pdfmark(pcs->memory, pcs->pgs->device, pres); |
382 | 0 | if (code < 0) |
383 | 0 | return code; |
384 | 0 | } |
385 | | |
386 | 60.2k | pres = pjl_proc_get_envvar(pcs->pjls, "setdistillerparams"); |
387 | 60.2k | if (strlen(pres) > 0) { |
388 | 0 | code = pcl_pjl_setdistillerparams(pcs->memory, pcs->pgs->device, pres); |
389 | 0 | if (code < 0) |
390 | 0 | return code; |
391 | 0 | } |
392 | 60.2k | } |
393 | | |
394 | 60.2k | if (type & (pcl_reset_initial | pcl_reset_printer | pcl_reset_overlay)) { |
395 | | /* rtl always uses native units for user units. The hp |
396 | | documentation does not say what to do if the resolution is |
397 | | assymetric... */ |
398 | 60.2k | pcl_args_t args; |
399 | | |
400 | 60.2k | if (pcs->personality == rtl) { |
401 | 0 | float res[2]; |
402 | | |
403 | | /* resolution is always a single number in PJL */ |
404 | 0 | res[0] = res[1] = pcl_pjl_res(pcs); |
405 | |
|
406 | 0 | if (res[0] != 0) |
407 | 0 | arg_set_uint(&args, (uint)res[0]); |
408 | 0 | else |
409 | 0 | arg_set_uint(&args, |
410 | 0 | (uint) gs_currentdevice(pcs->pgs)-> |
411 | 0 | HWResolution[0]); |
412 | 0 | } else |
413 | 60.2k | arg_set_uint(&args, 300); |
414 | 60.2k | code = pcl_set_unit_of_measure(&args, pcs); |
415 | 60.2k | if (code < 0) |
416 | 0 | return code; |
417 | 60.2k | } |
418 | 60.2k | return 0; |
419 | 60.2k | } |
420 | | const pcl_init_t pcjob_init = { |
421 | | pcjob_do_registration, pcjob_do_reset, pcjob_do_copy |
422 | | }; |