/src/ghostpdl/devices/vector/gdevpsdu.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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 | | /* Common utilities for PostScript and PDF writers */ |
18 | | #include "stdio_.h" /* for FILE for jpeglib.h */ |
19 | | #include "jpeglib_.h" /* for sdct.h */ |
20 | | #include "memory_.h" |
21 | | #include "gx.h" |
22 | | #include "gserrors.h" |
23 | | #include "gdevpsdf.h" |
24 | | #include "strimpl.h" |
25 | | #include "sa85x.h" |
26 | | #include "scfx.h" |
27 | | #include "sdct.h" |
28 | | #include "sjpeg.h" |
29 | | #include "spprint.h" |
30 | | #include "gsovrc.h" |
31 | | #include "gsicc_cache.h" |
32 | | |
33 | | /* Structure descriptors */ |
34 | | public_st_device_psdf(); |
35 | | public_st_psdf_binary_writer(); |
36 | | |
37 | | /* Standard color command names. */ |
38 | | const psdf_set_color_commands_t psdf_set_fill_color_commands = { |
39 | | "g", "rg", "k", "cs", "sc", "scn" |
40 | | }; |
41 | | const psdf_set_color_commands_t psdf_set_stroke_color_commands = { |
42 | | "G", "RG", "K", "CS", "SC", "SCN" |
43 | | }; |
44 | | |
45 | | /* Define parameter-setting procedures. */ |
46 | | extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state); |
47 | | |
48 | | /* ---------------- Vector implementation procedures ---------------- */ |
49 | | |
50 | | int |
51 | | psdf_setlinewidth(gx_device_vector * vdev, double width) |
52 | 70.5k | { |
53 | 70.5k | pprintg1(gdev_vector_stream(vdev), "%g w\n", width); |
54 | 70.5k | return 0; |
55 | 70.5k | } |
56 | | |
57 | | int |
58 | | psdf_setlinecap(gx_device_vector * vdev, gs_line_cap cap) |
59 | 34.4k | { |
60 | 34.4k | switch (cap) { |
61 | 7.33k | case gs_cap_butt: |
62 | 33.1k | case gs_cap_round: |
63 | 34.4k | case gs_cap_square: |
64 | 34.4k | pprintd1(gdev_vector_stream(vdev), "%d J\n", cap); |
65 | 34.4k | break; |
66 | 9 | case gs_cap_triangle: |
67 | | /* If we get a PCL triangle cap, substitute with a round cap */ |
68 | 9 | pprintd1(gdev_vector_stream(vdev), "%d J\n", gs_cap_round); |
69 | 9 | break; |
70 | 0 | default: |
71 | | /* Ensure we don't write a broken file if we don't recognise the cap */ |
72 | 0 | emprintf1(vdev->memory, |
73 | 0 | "Unknown line cap enumerator %d, substituting butt\n", |
74 | 0 | cap); |
75 | 0 | pprintd1(gdev_vector_stream(vdev), "%d J\n", gs_cap_butt); |
76 | 0 | break; |
77 | 34.4k | } |
78 | 34.4k | return 0; |
79 | 34.4k | } |
80 | | |
81 | | int |
82 | | psdf_setlinejoin(gx_device_vector * vdev, gs_line_join join) |
83 | 26.6k | { |
84 | 26.6k | switch (join) { |
85 | 11.8k | case gs_join_miter: |
86 | 26.4k | case gs_join_round: |
87 | 26.5k | case gs_join_bevel: |
88 | 26.5k | pprintd1(gdev_vector_stream(vdev), "%d j\n", join); |
89 | 26.5k | break; |
90 | 5 | case gs_join_none: |
91 | | /* If we get a PCL triangle join, substitute with a bevel join */ |
92 | 5 | pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_bevel); |
93 | 5 | break; |
94 | 0 | case gs_join_triangle: |
95 | | /* If we get a PCL triangle join, substitute with a miter join */ |
96 | 0 | pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_miter); |
97 | 0 | break; |
98 | 0 | default: |
99 | | /* Ensure we don't write a broken file if we don't recognise the join */ |
100 | 0 | emprintf1(vdev->memory, |
101 | 0 | "Unknown line join enumerator %d, substituting miter\n", |
102 | 0 | join); |
103 | 0 | pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_miter); |
104 | 0 | break; |
105 | 26.6k | } |
106 | 26.6k | return 0; |
107 | 26.6k | } |
108 | | |
109 | | int |
110 | | psdf_setmiterlimit(gx_device_vector * vdev, double limit) |
111 | 2.16k | { |
112 | 2.16k | pprintg1(gdev_vector_stream(vdev), "%g M\n", limit); |
113 | 2.16k | return 0; |
114 | 2.16k | } |
115 | | |
116 | | int |
117 | | psdf_setdash(gx_device_vector * vdev, const float *pattern, uint count, |
118 | | double offset) |
119 | 7.52k | { |
120 | 7.52k | stream *s = gdev_vector_stream(vdev); |
121 | 7.52k | int i; |
122 | | |
123 | 7.52k | stream_puts(s, "[ "); |
124 | 15.1k | for (i = 0; i < count; ++i) |
125 | 7.58k | pprintg1(s, "%g ", pattern[i]); |
126 | 7.52k | pprintg1(s, "] %g d\n", offset); |
127 | 7.52k | return 0; |
128 | 7.52k | } |
129 | | |
130 | | int |
131 | | psdf_setflat(gx_device_vector * vdev, double flatness) |
132 | 14.2k | { |
133 | 14.2k | pprintg1(gdev_vector_stream(vdev), "%g i\n", flatness); |
134 | 14.2k | return 0; |
135 | 14.2k | } |
136 | | |
137 | | int |
138 | | psdf_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop, |
139 | | gs_logical_operation_t diff) |
140 | 0 | { |
141 | | /****** SHOULD AT LEAST DETECT SET-0 & SET-1 ******/ |
142 | 0 | return 0; |
143 | 0 | } |
144 | | |
145 | | int |
146 | | psdf_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1, |
147 | | gx_path_type_t type) |
148 | 500k | { |
149 | 500k | int code = (*vdev_proc(vdev, beginpath)) (vdev, type); |
150 | | |
151 | 500k | if (code < 0) |
152 | 0 | return code; |
153 | 500k | pprintg4(gdev_vector_stream(vdev), "%g %g %g %g re\n", |
154 | 500k | fixed2float(x0), fixed2float(y0), |
155 | 500k | fixed2float(x1 - x0), fixed2float(y1 - y0)); |
156 | 500k | return (*vdev_proc(vdev, endpath)) (vdev, type); |
157 | 500k | } |
158 | | |
159 | | int |
160 | | psdf_beginpath(gx_device_vector * vdev, gx_path_type_t type) |
161 | 500k | { |
162 | 500k | return 0; |
163 | 500k | } |
164 | | |
165 | | int |
166 | | psdf_moveto(gx_device_vector * vdev, double x0, double y0, double x, double y, |
167 | | gx_path_type_t type) |
168 | 1.17M | { |
169 | 1.17M | pprintg2(gdev_vector_stream(vdev), "%g %g m\n", x, y); |
170 | 1.17M | return 0; |
171 | 1.17M | } |
172 | | |
173 | | int |
174 | | psdf_lineto(gx_device_vector * vdev, double x0, double y0, double x, double y, |
175 | | gx_path_type_t type) |
176 | 2.78M | { |
177 | 2.78M | pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x, y); |
178 | 2.78M | return 0; |
179 | 2.78M | } |
180 | | |
181 | | int |
182 | | psdf_curveto(gx_device_vector * vdev, double x0, double y0, |
183 | | double x1, double y1, double x2, double y2, double x3, double y3, |
184 | | gx_path_type_t type) |
185 | 2.56M | { |
186 | 2.56M | if (x1 == x0 && y1 == y0 && x2 == x3 && y2 == y3) |
187 | 37.1k | pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x3, y3); |
188 | 2.52M | else if (x1 == x0 && y1 == y0) |
189 | 26.8k | pprintg4(gdev_vector_stream(vdev), "%g %g %g %g v\n", |
190 | 26.8k | x2, y2, x3, y3); |
191 | 2.49M | else if (x3 == x2 && y3 == y2) |
192 | 30.1k | pprintg4(gdev_vector_stream(vdev), "%g %g %g %g y\n", |
193 | 30.1k | x1, y1, x2, y2); |
194 | 2.46M | else |
195 | 2.46M | pprintg6(gdev_vector_stream(vdev), "%g %g %g %g %g %g c\n", |
196 | 2.46M | x1, y1, x2, y2, x3, y3); |
197 | 2.56M | return 0; |
198 | 2.56M | } |
199 | | |
200 | | int |
201 | | psdf_closepath(gx_device_vector * vdev, double x0, double y0, |
202 | | double x_start, double y_start, gx_path_type_t type) |
203 | 289k | { |
204 | 289k | stream_puts(gdev_vector_stream(vdev), "h\n"); |
205 | 289k | return 0; |
206 | 289k | } |
207 | | |
208 | | /* endpath is deliberately omitted. */ |
209 | | |
210 | | /* ---------------- Utilities ---------------- */ |
211 | | |
212 | | gx_color_index |
213 | | psdf_adjust_color_index(gx_device_vector *vdev, gx_color_index color) |
214 | 858k | { |
215 | | /* |
216 | | * Since gx_no_color_index is all 1's, we can't represent |
217 | | * a CMYK color consisting of full ink in all 4 components. |
218 | | * However, this color must be available for registration marks. |
219 | | * gxcmap.c fudges this by changing the K component to 254; |
220 | | * undo this fudge here. |
221 | | */ |
222 | 858k | return (color == (gx_no_color_index ^ 1) ? gx_no_color_index : color); |
223 | 858k | } |
224 | | |
225 | | /* Round a double value to a specified precision. */ |
226 | | double |
227 | | psdf_round(double v, int precision, int radix) |
228 | 4.07M | { |
229 | 4.07M | double mul = 1; |
230 | 4.07M | double w = v; |
231 | | |
232 | 4.07M | if (w <= 0) |
233 | 2.02M | return w; |
234 | 6.75M | while (w < precision) { |
235 | 4.70M | w *= radix; |
236 | 4.70M | mul *= radix; |
237 | 4.70M | } |
238 | 2.04M | return (int)(w + 0.5) / mul; |
239 | 4.07M | } |
240 | | |
241 | | /* |
242 | | * Since we only have 8 bits of color to start with, round the |
243 | | * values to 3 digits for more compact output. |
244 | | */ |
245 | | static inline double |
246 | | round_byte_color(gx_color_index cv) |
247 | 2.47M | { |
248 | 2.47M | return (int)((uint)cv * (1000.0 / 255.0) + 0.5) / 1000.0; |
249 | 2.47M | } |
250 | | int |
251 | | psdf_set_color(gx_device_vector * vdev, const gx_drawing_color * pdc, |
252 | | const psdf_set_color_commands_t *ppscc) |
253 | 869k | { |
254 | 869k | const char *setcolor; |
255 | 869k | int num_des_comps, code; |
256 | 869k | cmm_dev_profile_t *dev_profile; |
257 | | |
258 | 869k | code = dev_proc((gx_device *)vdev, get_profile)((gx_device *)vdev, &dev_profile); |
259 | 869k | if (code < 0) |
260 | 0 | return code; |
261 | 869k | num_des_comps = gsicc_get_device_profile_comps(dev_profile); |
262 | | |
263 | 869k | if (!gx_dc_is_pure(pdc)) |
264 | 10.8k | return_error(gs_error_rangecheck); |
265 | 858k | { |
266 | 858k | stream *s = gdev_vector_stream(vdev); |
267 | 858k | gx_color_index color = |
268 | 858k | psdf_adjust_color_index(vdev, gx_dc_pure_color(pdc)); |
269 | | /* |
270 | | * Normally we would precompute all of v0 .. v3, but gcc 2.7.2.3 |
271 | | * generates incorrect code for Intel CPUs if we do this. The code |
272 | | * below is longer, but does less computation in some cases. |
273 | | */ |
274 | 858k | double v3 = round_byte_color(color & 0xff); |
275 | | |
276 | 858k | switch (num_des_comps) { |
277 | 0 | case 4: |
278 | | /* if (v0 == 0 && v1 == 0 && v2 == 0 && ...) */ |
279 | 0 | if ((color & 0xffffff00) == 0 && ppscc->setgray != 0) { |
280 | 0 | v3 = 1.0 - v3; |
281 | 0 | goto g; |
282 | 0 | } |
283 | 0 | pprintg4(s, "%g %g %g %g", round_byte_color(color >> 24), |
284 | 0 | round_byte_color((color >> 16) & 0xff), |
285 | 0 | round_byte_color((color >> 8) & 0xff), v3); |
286 | 0 | setcolor = ppscc->setcmykcolor; |
287 | 0 | break; |
288 | 858k | case 3: |
289 | | /* if (v1 == v2 && v2 == v3 && ...) */ |
290 | 858k | if (!((color ^ (color >> 8)) & 0xffff) && ppscc->setgray != 0) |
291 | 49.5k | goto g; |
292 | 809k | pprintg3(s, "%g %g %g", round_byte_color((color >> 16) & 0xff), |
293 | 809k | round_byte_color((color >> 8) & 0xff), v3); |
294 | 809k | setcolor = ppscc->setrgbcolor; |
295 | 809k | break; |
296 | 0 | case 1: |
297 | 49.5k | g: |
298 | 49.5k | pprintg1(s, "%g", v3); |
299 | 49.5k | setcolor = ppscc->setgray; |
300 | 49.5k | break; |
301 | 0 | default: /* can't happen */ |
302 | 0 | return_error(gs_error_rangecheck); |
303 | 858k | } |
304 | 858k | if (setcolor) |
305 | 858k | pprints1(s, " %s\n", setcolor); |
306 | 858k | } |
307 | 0 | return 0; |
308 | 858k | } |
309 | | |
310 | | /* ---------------- Binary data writing ---------------- */ |
311 | | |
312 | | /* Begin writing binary data. */ |
313 | | int |
314 | | psdf_begin_binary(gx_device_psdf * pdev, psdf_binary_writer * pbw) |
315 | 376k | { |
316 | 376k | gs_memory_t *mem = pbw->memory = pdev->v_memory; |
317 | | |
318 | 376k | pbw->target = pdev->strm; |
319 | 376k | pbw->dev = pdev; |
320 | 376k | pbw->strm = 0; /* for GC in case of failure */ |
321 | | /* If not binary, set up the encoding stream. */ |
322 | 376k | if (!pdev->binary_ok) { |
323 | 252k | #define BUF_SIZE 100 /* arbitrary */ |
324 | 252k | byte *buf = gs_alloc_bytes(mem, BUF_SIZE, "psdf_begin_binary(buf)"); |
325 | 252k | stream_A85E_state *ss = (stream_A85E_state *) |
326 | 252k | s_alloc_state(mem, s_A85E_template.stype, |
327 | 252k | "psdf_begin_binary(stream_state)"); |
328 | 252k | stream *s = s_alloc(mem, "psdf_begin_binary(stream)"); |
329 | | |
330 | 252k | if (buf == 0 || ss == 0 || s == 0) { |
331 | 0 | gs_free_object(mem, s, "psdf_begin_binary(stream)"); |
332 | 0 | gs_free_object(mem, ss, "psdf_begin_binary(stream_state)"); |
333 | 0 | gs_free_object(mem, buf, "psdf_begin_binary(buf)"); |
334 | 0 | return_error(gs_error_VMerror); |
335 | 0 | } |
336 | 252k | ss->templat = &s_A85E_template; |
337 | 252k | s_init_filter(s, (stream_state *)ss, buf, BUF_SIZE, pdev->strm); |
338 | 252k | #undef BUF_SIZE |
339 | 252k | pbw->strm = s; |
340 | 252k | } else { |
341 | 124k | pbw->strm = pdev->strm; |
342 | 124k | } |
343 | 376k | return 0; |
344 | 376k | } |
345 | | |
346 | | /* Add an encoding filter. The client must have allocated the stream state, */ |
347 | | /* if any, using pdev->v_memory. */ |
348 | | int |
349 | | psdf_encode_binary(psdf_binary_writer * pbw, const stream_template * templat, |
350 | | stream_state * ss) |
351 | 349k | { |
352 | 349k | return (s_add_filter(&pbw->strm, templat, ss, pbw->memory) == 0 ? |
353 | 349k | gs_note_error(gs_error_VMerror) : 0); |
354 | 349k | } |
355 | | |
356 | | /* |
357 | | * Acquire parameters, and optionally set up the filter for, a DCTEncode |
358 | | * filter. This is a separate procedure so it can be used to validate |
359 | | * filter parameters when they are set, rather than waiting until they are |
360 | | * used. pbw = NULL means just set up the stream state. |
361 | | */ |
362 | | int |
363 | | psdf_DCT_filter(gs_param_list *plist /* may be NULL */, |
364 | | stream_state /*stream_DCTE_state*/ *st, |
365 | | int Columns, int Rows, int Colors, |
366 | | psdf_binary_writer *pbw /* may be NULL */) |
367 | 6.15k | { |
368 | 6.15k | stream_DCT_state *const ss = (stream_DCT_state *) st; |
369 | 6.15k | gs_memory_t *mem = st->memory; |
370 | 6.15k | jpeg_compress_data *jcdp; |
371 | 6.15k | gs_c_param_list rcc_list; |
372 | 6.15k | int code; |
373 | | |
374 | | /* |
375 | | * "Wrap" the actual Dict or ACSDict parameter list in one that |
376 | | * sets Rows, Columns, and Colors. |
377 | | */ |
378 | 6.15k | gs_c_param_list_write(&rcc_list, mem); |
379 | 6.15k | if ((code = param_write_int((gs_param_list *)&rcc_list, "Rows", |
380 | 6.15k | &Rows)) < 0 || |
381 | 6.15k | (code = param_write_int((gs_param_list *)&rcc_list, "Columns", |
382 | 6.15k | &Columns)) < 0 || |
383 | 6.15k | (code = param_write_int((gs_param_list *)&rcc_list, "Colors", |
384 | 6.15k | &Colors)) < 0 |
385 | 6.15k | ) { |
386 | 0 | goto rcc_fail; |
387 | 0 | } |
388 | 6.15k | gs_c_param_list_read(&rcc_list); |
389 | 6.15k | if (plist) |
390 | 6.15k | gs_c_param_list_set_target(&rcc_list, plist); |
391 | | /* Allocate space for IJG parameters. */ |
392 | 6.15k | jcdp = gs_alloc_struct_immovable(mem, jpeg_compress_data, |
393 | 6.15k | &st_jpeg_compress_data, "zDCTE"); |
394 | 6.15k | if (jcdp == 0) |
395 | 0 | return_error(gs_error_VMerror); |
396 | 6.15k | jcdp->cinfo.mem = NULL; |
397 | 6.15k | jcdp->cinfo.client_data = NULL; |
398 | 6.15k | ss->data.compress = jcdp; |
399 | 6.15k | jcdp->memory = ss->jpeg_memory = mem; /* set now for allocation */ |
400 | 6.15k | if ((code = gs_jpeg_create_compress(ss)) < 0) |
401 | 0 | goto dcte_fail; /* correct to do jpeg_destroy here */ |
402 | | /* Read parameters from dictionary */ |
403 | 6.15k | code = s_DCTE_put_params((gs_param_list *)&rcc_list, ss); |
404 | 6.15k | if (code < 0) |
405 | 0 | return code; |
406 | | /* Create the filter. */ |
407 | 6.15k | jcdp->templat = s_DCTE_template; |
408 | | /* Make sure we get at least a full scan line of input. */ |
409 | 6.15k | ss->scan_line_size = jcdp->cinfo.input_components * |
410 | 6.15k | jcdp->cinfo.image_width; |
411 | | /* Profile not used in pdfwrite output */ |
412 | 6.15k | ss->icc_profile = NULL; |
413 | 6.15k | jcdp->templat.min_in_size = |
414 | 6.15k | max(s_DCTE_template.min_in_size, ss->scan_line_size); |
415 | | /* Make sure we can write the user markers in a single go. */ |
416 | 6.15k | jcdp->templat.min_out_size = |
417 | 6.15k | max(s_DCTE_template.min_out_size, ss->Markers.size); |
418 | 6.15k | if (pbw) |
419 | 6.15k | code = psdf_encode_binary(pbw, &jcdp->templat, st); |
420 | 6.15k | if (code >= 0) { |
421 | 6.15k | gs_c_param_list_release(&rcc_list); |
422 | 6.15k | return 0; |
423 | 6.15k | } |
424 | 0 | dcte_fail: |
425 | 0 | gs_jpeg_destroy(ss); |
426 | 0 | gs_free_object(mem, jcdp, "setup_image_compression"); |
427 | 0 | ss->data.compress = NULL; /* Avoid problems with double frees later */ |
428 | 0 | rcc_fail: |
429 | 0 | gs_c_param_list_release(&rcc_list); |
430 | 0 | return code; |
431 | 0 | } |
432 | | |
433 | | /* Add a 2-D CCITTFax encoding filter. */ |
434 | | /* Set EndOfBlock iff the stream is not ASCII85 encoded. */ |
435 | | int |
436 | | psdf_CFE_binary(psdf_binary_writer * pbw, int w, int h, bool invert) |
437 | 134k | { |
438 | 134k | gs_memory_t *mem = pbw->memory; |
439 | 134k | const stream_template *templat = &s_CFE_template; |
440 | 134k | stream_CFE_state *st = |
441 | 134k | gs_alloc_struct(mem, stream_CFE_state, templat->stype, |
442 | 134k | "psdf_CFE_binary"); |
443 | 134k | int code; |
444 | | |
445 | 134k | if (st == 0) |
446 | 0 | return_error(gs_error_VMerror); |
447 | 134k | (*templat->set_defaults) ((stream_state *) st); |
448 | 134k | st->K = -1; |
449 | 134k | st->Columns = w; |
450 | 134k | st->Rows = 0; |
451 | 134k | st->BlackIs1 = !invert; |
452 | 134k | st->EndOfBlock = pbw->strm->state->templat != &s_A85E_template; |
453 | 134k | code = psdf_encode_binary(pbw, templat, (stream_state *) st); |
454 | 134k | if (code < 0) |
455 | 0 | gs_free_object(mem, st, "psdf_CFE_binary"); |
456 | 134k | return code; |
457 | 134k | } |
458 | | |
459 | | /* Finish writing binary data. */ |
460 | | int |
461 | | psdf_end_binary(psdf_binary_writer * pbw) |
462 | 226k | { |
463 | 226k | int status = s_close_filters(&pbw->strm, pbw->target); |
464 | | |
465 | 226k | return (status >= 0 ? 0 : gs_note_error(gs_error_ioerror)); |
466 | 226k | } |
467 | | |
468 | | /* ---------------- Overprint, Get Bits ---------------- */ |
469 | | |
470 | | /* |
471 | | * High level devices cannot perform get_bits_rectangle |
472 | | * operations, for obvious reasons. |
473 | | */ |
474 | | int |
475 | | psdf_get_bits_rectangle( |
476 | | gx_device * dev, |
477 | | const gs_int_rect * prect, |
478 | | gs_get_bits_params_t * params ) |
479 | 0 | { |
480 | 0 | emprintf(dev->memory, |
481 | 0 | "Can't set GraphicsAlphaBits or TextAlphaBits with a vector device.\n"); |
482 | 0 | return_error(gs_error_unregistered); |
483 | 0 | } |
484 | | |
485 | | /* |
486 | | * Create compositor procedure for PostScript/PDF writer. Since these |
487 | | * devices directly support overprint (and have access to the gs_gstate), |
488 | | * no compositor is required for overprint support. Hence, this |
489 | | * routine just recognizes and discards invocations of the overprint |
490 | | * compositor. |
491 | | */ |
492 | | int |
493 | | psdf_composite( |
494 | | gx_device * dev, |
495 | | gx_device ** pcdev, |
496 | | const gs_composite_t * pct, |
497 | | gs_gstate * pgs, |
498 | | gs_memory_t * mem, |
499 | | gx_device * cdev) |
500 | 146k | { |
501 | 146k | if (gs_is_overprint_compositor(pct)) { |
502 | 143k | *pcdev = dev; |
503 | 143k | return 0; |
504 | 143k | } |
505 | 3.14k | return gx_default_composite(dev, pcdev, pct, pgs, mem, cdev); |
506 | 146k | } |