/src/ghostpdl/pdf/pdf_device.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2019-2025 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 | | /* Routines for dealing with devices */ |
17 | | |
18 | | #include "pdf_int.h" |
19 | | #include "pdf_stack.h" |
20 | | #include "pdf_device.h" |
21 | | #include "gsdevice.h" /* For gs_setdevice_no_erase */ |
22 | | #include "gspaint.h" /* For gs_erasepage */ |
23 | | #include "gdevvec.h" /* for gs_device_vector */ |
24 | | #include "gxdevsop.h" /* For special ops : dev_param_req_t */ |
25 | | |
26 | | int pdfi_device_check_param(gx_device *dev, const char *param, gs_c_param_list *list) |
27 | 1.05M | { |
28 | 1.05M | dev_param_req_t request; |
29 | 1.05M | int code; |
30 | | |
31 | 1.05M | gs_c_param_list_write(list, dev->memory); |
32 | | /* Stuff the data into a structure for passing to the spec_op */ |
33 | 1.05M | request.Param = (char *)param; |
34 | 1.05M | request.list = list; |
35 | 1.05M | code = dev_proc(dev, dev_spec_op)(dev, gxdso_get_dev_param, &request, sizeof(dev_param_req_t)); |
36 | 1.05M | if (code < 0) { |
37 | 809k | gs_c_param_list_release(list); |
38 | 809k | return code; |
39 | 809k | } |
40 | 241k | return 0; |
41 | 1.05M | } |
42 | | |
43 | | /* Check value of boolean device parameter */ |
44 | | bool pdfi_device_check_param_bool(gx_device *dev, const char *param) |
45 | 965k | { |
46 | 965k | int code; |
47 | 965k | gs_c_param_list list; |
48 | 965k | bool value; |
49 | | |
50 | 965k | code = pdfi_device_check_param(dev, param, &list); |
51 | 965k | if (code < 0) |
52 | 727k | return false; |
53 | 237k | gs_c_param_list_read(&list); |
54 | 237k | code = param_read_bool((gs_param_list *)&list, |
55 | 237k | param, |
56 | 237k | &value); |
57 | 237k | if (code < 0) |
58 | 0 | value = false; |
59 | 237k | gs_c_param_list_release(&list); |
60 | 237k | return value; |
61 | 965k | } |
62 | | |
63 | | /* Set value of string device parameter */ |
64 | | int pdfi_device_set_param_string(gx_device *dev, const char *paramname, const char *value) |
65 | 0 | { |
66 | 0 | int code; |
67 | 0 | gs_c_param_list list; |
68 | 0 | gs_param_string paramstring; |
69 | |
|
70 | 0 | paramstring.data = (byte *)value; |
71 | 0 | paramstring.size = strlen(value); |
72 | 0 | paramstring.persistent = 0; |
73 | |
|
74 | 0 | gs_c_param_list_write(&list, dev->memory); |
75 | |
|
76 | 0 | gs_param_list_set_persistent_keys((gs_param_list *) &list, false); |
77 | 0 | code = param_write_string((gs_param_list *)&list, paramname, ¶mstring); |
78 | 0 | if (code < 0) goto exit; |
79 | 0 | gs_c_param_list_read(&list); |
80 | 0 | code = gs_putdeviceparams(dev, (gs_param_list *)&list); |
81 | |
|
82 | 0 | exit: |
83 | 0 | gs_c_param_list_release(&list); |
84 | 0 | return code; |
85 | 0 | } |
86 | | |
87 | | /* Set value of boolean device parameter */ |
88 | | int pdfi_device_set_param_bool(gx_device *dev, const char *param, bool value) |
89 | 0 | { |
90 | 0 | int code; |
91 | 0 | gs_c_param_list list; |
92 | 0 | bool paramval = value; |
93 | |
|
94 | 0 | gs_c_param_list_write(&list, dev->memory); |
95 | |
|
96 | 0 | code = param_write_bool((gs_param_list *)&list, param, ¶mval); |
97 | 0 | if (code < 0) goto exit; |
98 | 0 | gs_c_param_list_read(&list); |
99 | 0 | code = gs_putdeviceparams(dev, (gs_param_list *)&list); |
100 | |
|
101 | 0 | exit: |
102 | 0 | gs_c_param_list_release(&list); |
103 | 0 | return code; |
104 | 0 | } |
105 | | |
106 | | int pdfi_device_set_param_float(gx_device *dev, const char *param, float value) |
107 | 0 | { |
108 | 0 | int code; |
109 | 0 | gs_c_param_list list; |
110 | 0 | float paramval = value; |
111 | |
|
112 | 0 | gs_c_param_list_write(&list, dev->memory); |
113 | |
|
114 | 0 | code = param_write_float((gs_param_list *)&list, param, ¶mval); |
115 | 0 | if (code < 0) goto exit; |
116 | 0 | gs_c_param_list_read(&list); |
117 | 0 | code = gs_putdeviceparams(dev, (gs_param_list *)&list); |
118 | |
|
119 | 0 | exit: |
120 | 0 | gs_c_param_list_release(&list); |
121 | 0 | return code; |
122 | 0 | } |
123 | | |
124 | | /* Checks whether a parameter exists for the device */ |
125 | | bool pdfi_device_check_param_exists(gx_device *dev, const char *param) |
126 | 86.0k | { |
127 | 86.0k | int code; |
128 | 86.0k | gs_c_param_list list; |
129 | | |
130 | 86.0k | code = pdfi_device_check_param(dev, param, &list); |
131 | 86.0k | if (code < 0) |
132 | 82.0k | return false; |
133 | 4.00k | gs_c_param_list_release(&list); |
134 | 4.00k | return true; |
135 | 86.0k | } |
136 | | |
137 | | /* Config some device-related variables */ |
138 | | void pdfi_device_set_flags(pdf_context *ctx) |
139 | 86.0k | { |
140 | 86.0k | bool has_pdfmark; |
141 | 86.0k | bool has_ForOPDFRead; |
142 | 86.0k | gx_device *dev = ctx->pgs->device; |
143 | | |
144 | 86.0k | has_pdfmark = pdfi_device_check_param_exists(dev, "pdfmark"); |
145 | 86.0k | has_ForOPDFRead = pdfi_device_check_param_bool(dev, "ForOPDFRead"); |
146 | | |
147 | | /* Cache these so they don't have to constantly be calculated */ |
148 | 86.0k | ctx->device_state.writepdfmarks = has_pdfmark || ctx->args.dopdfmarks; |
149 | 86.0k | ctx->device_state.annotations_preserved = ctx->device_state.writepdfmarks && !has_ForOPDFRead; |
150 | | |
151 | | /* PreserveTrMode is for pdfwrite device */ |
152 | 86.0k | ctx->device_state.preserve_tr_mode = pdfi_device_check_param_bool(dev, "PreserveTrMode"); |
153 | 86.0k | ctx->device_state.preserve_smask = pdfi_device_check_param_bool(dev, "PreserveSMask"); |
154 | 86.0k | ctx->device_state.HighLevelDevice = pdfi_device_check_param_bool(dev, "HighLevelDevice"); |
155 | 86.0k | ctx->device_state.ForOPDFRead = pdfi_device_check_param_bool(dev, "ForOPDFRead"); |
156 | 86.0k | ctx->device_state.WantsPageLabels = pdfi_device_check_param_bool(dev, "WantsPageLabels"); |
157 | 86.0k | ctx->device_state.WantsOptionalContent = pdfi_device_check_param_bool(dev, "WantsOptionalContent"); |
158 | 86.0k | ctx->device_state.PassUserUnit = pdfi_device_check_param_bool(dev, "PassUserUnit"); |
159 | | |
160 | | /* See if it is a DeviceN (spot capable) */ |
161 | 86.0k | ctx->device_state.spot_capable = dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0); |
162 | | |
163 | 86.0k | ctx->device_state.ModifiesPageSize = pdfi_device_check_param_bool(dev, "ModifiesPageSize"); |
164 | 86.0k | ctx->device_state.ModifiesPageOrder = pdfi_device_check_param_bool(dev, "ModifiesPageOrder"); |
165 | | |
166 | | /* If multi-page output, can't do certain pdfmarks */ |
167 | 86.0k | if (ctx->device_state.writepdfmarks) { |
168 | 4.00k | if (gx_outputfile_is_separate_pages(((gx_device_vector *)dev)->fname, dev->memory) || ctx->device_state.ModifiesPageOrder) { |
169 | 0 | ctx->args.no_pdfmark_outlines = true; |
170 | 0 | ctx->args.no_pdfmark_dests = true; |
171 | 0 | } |
172 | 4.00k | } |
173 | | |
174 | | #if DEBUG_DEVICE |
175 | | dbgmprintf2(ctx->memory, "Device writepdfmarks=%s, annotations_preserved=%s\n", |
176 | | ctx->writepdfmarks ? "TRUE" : "FALSE", |
177 | | ctx->annotations_preserved ? "TRUE" : "FALSE"); |
178 | | #endif |
179 | 86.0k | } |
180 | | |
181 | | /* Config the output device |
182 | | * This will configure any special device parameters. |
183 | | * Right now it just sets up some stuff for pdfwrite. |
184 | | */ |
185 | | int pdfi_device_misc_config(pdf_context *ctx) |
186 | 0 | { |
187 | 0 | bool has_pdfmark = false; |
188 | 0 | int code; |
189 | 0 | gx_device *dev = ctx->pgs->device; |
190 | |
|
191 | 0 | if (ctx->args.first_page != 0 || ctx->args.last_page != 0) { |
192 | 0 | code = pdfi_device_set_param_bool(dev, "DisablePageHandler", true); |
193 | 0 | if (code < 0) goto exit; |
194 | 0 | } |
195 | | |
196 | | /* I am using pdfmark to identify the pdfwrite device */ |
197 | 0 | has_pdfmark = pdfi_device_check_param_bool(dev, "pdfmark"); |
198 | | /* (only handling pdfwrite for now) */ |
199 | 0 | if (!has_pdfmark) |
200 | 0 | return 0; |
201 | | |
202 | | /* TODO: I think the pdfwrite device should have these automatically set to true, |
203 | | * but that doesn't seem to be the case now. |
204 | | * See pdf_document_metadata() |
205 | | */ |
206 | 0 | code = pdfi_device_set_param_string(dev, "AutoRotatePages", "PageByPage"); |
207 | 0 | if (code < 0) goto exit; |
208 | | |
209 | 0 | exit: |
210 | 0 | return code; |
211 | 0 | } |