2 |
- |
1 |
/* Copyright (C) 1999, 2000, 2001 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: gdevpdfg.c,v 1.68 2005/09/12 11:34:50 leonardo Exp $ */
|
|
|
18 |
/* Graphics state management for pdfwrite driver */
|
|
|
19 |
#include "math_.h"
|
|
|
20 |
#include "string_.h"
|
|
|
21 |
#include "memory_.h"
|
|
|
22 |
#include "gx.h"
|
|
|
23 |
#include "gserrors.h"
|
|
|
24 |
#include "gsfunc0.h"
|
|
|
25 |
#include "gsstate.h"
|
|
|
26 |
#include "gxbitmap.h" /* for gxhttile.h in gzht.h */
|
|
|
27 |
#include "gxdht.h"
|
|
|
28 |
#include "gxfarith.h" /* for gs_sin/cos_degrees */
|
|
|
29 |
#include "gxfmap.h"
|
|
|
30 |
#include "gxht.h"
|
|
|
31 |
#include "gxistate.h"
|
|
|
32 |
#include "gxdcolor.h"
|
|
|
33 |
#include "gxpcolor.h"
|
|
|
34 |
#include "gsptype2.h"
|
|
|
35 |
#include "gzht.h"
|
|
|
36 |
#include "gdevpdfx.h"
|
|
|
37 |
#include "gdevpdfg.h"
|
|
|
38 |
#include "gdevpdfo.h"
|
|
|
39 |
#include "szlibx.h"
|
|
|
40 |
|
|
|
41 |
/* ---------------- Miscellaneous ---------------- */
|
|
|
42 |
|
|
|
43 |
/* Save the viewer's graphic state. */
|
|
|
44 |
int
|
|
|
45 |
pdf_save_viewer_state(gx_device_pdf *pdev, stream *s)
|
|
|
46 |
{
|
|
|
47 |
const int i = pdev->vgstack_depth;
|
|
|
48 |
|
|
|
49 |
if (pdev->vgstack_depth >= count_of(pdev->vgstack))
|
|
|
50 |
return_error(gs_error_unregistered); /* Must not happen. */
|
|
|
51 |
pdev->vgstack[i].transfer_ids[0] = pdev->transfer_ids[0];
|
|
|
52 |
pdev->vgstack[i].transfer_ids[1] = pdev->transfer_ids[1];
|
|
|
53 |
pdev->vgstack[i].transfer_ids[2] = pdev->transfer_ids[2];
|
|
|
54 |
pdev->vgstack[i].transfer_ids[3] = pdev->transfer_ids[3];
|
|
|
55 |
pdev->vgstack[i].transfer_not_identity = pdev->transfer_not_identity;
|
|
|
56 |
pdev->vgstack[i].opacity_alpha = pdev->state.opacity.alpha;
|
|
|
57 |
pdev->vgstack[i].shape_alpha = pdev->state.shape.alpha;
|
|
|
58 |
pdev->vgstack[i].blend_mode = pdev->state.blend_mode;
|
|
|
59 |
pdev->vgstack[i].halftone_id = pdev->halftone_id;
|
|
|
60 |
pdev->vgstack[i].black_generation_id = pdev->black_generation_id;
|
|
|
61 |
pdev->vgstack[i].undercolor_removal_id = pdev->undercolor_removal_id;
|
|
|
62 |
pdev->vgstack[i].overprint_mode = pdev->overprint_mode;
|
|
|
63 |
pdev->vgstack[i].smoothness = pdev->state.smoothness;
|
|
|
64 |
pdev->vgstack[i].flatness = pdev->state.flatness;
|
|
|
65 |
pdev->vgstack[i].text_knockout = pdev->state.text_knockout;
|
|
|
66 |
pdev->vgstack[i].fill_overprint = pdev->fill_overprint;
|
|
|
67 |
pdev->vgstack[i].stroke_overprint = pdev->stroke_overprint;
|
|
|
68 |
pdev->vgstack[i].stroke_adjust = pdev->state.stroke_adjust;
|
|
|
69 |
pdev->vgstack[i].fill_used_process_color = pdev->fill_used_process_color;
|
|
|
70 |
pdev->vgstack[i].stroke_used_process_color = pdev->stroke_used_process_color;
|
|
|
71 |
pdev->vgstack[i].saved_fill_color = pdev->saved_fill_color;
|
|
|
72 |
pdev->vgstack[i].saved_stroke_color = pdev->saved_stroke_color;
|
|
|
73 |
pdev->vgstack[i].line_params = pdev->state.line_params;
|
|
|
74 |
pdev->vgstack[i].line_params.dash.pattern = 0; /* Use pdev->dash_pattern instead. */
|
|
|
75 |
memcpy(pdev->vgstack[i].dash_pattern, pdev->dash_pattern,
|
|
|
76 |
sizeof(pdev->vgstack[i].dash_pattern));
|
|
|
77 |
pdev->vgstack_depth++;
|
|
|
78 |
if (s)
|
|
|
79 |
stream_puts(s, "q\n");
|
|
|
80 |
return 0;
|
|
|
81 |
}
|
|
|
82 |
|
|
|
83 |
/* Load the viewer's graphic state. */
|
|
|
84 |
private void
|
|
|
85 |
pdf_load_viewer_state(gx_device_pdf *pdev, pdf_viewer_state *s)
|
|
|
86 |
{
|
|
|
87 |
pdev->transfer_ids[0] = s->transfer_ids[0];
|
|
|
88 |
pdev->transfer_ids[1] = s->transfer_ids[1];
|
|
|
89 |
pdev->transfer_ids[2] = s->transfer_ids[2];
|
|
|
90 |
pdev->transfer_ids[3] = s->transfer_ids[3];
|
|
|
91 |
pdev->transfer_not_identity = s->transfer_not_identity;
|
|
|
92 |
pdev->state.opacity.alpha = s->opacity_alpha;
|
|
|
93 |
pdev->state.shape.alpha = s->shape_alpha;
|
|
|
94 |
pdev->state.blend_mode = s->blend_mode;
|
|
|
95 |
pdev->halftone_id = s->halftone_id;
|
|
|
96 |
pdev->black_generation_id = s->black_generation_id;
|
|
|
97 |
pdev->undercolor_removal_id = s->undercolor_removal_id;
|
|
|
98 |
pdev->overprint_mode = s->overprint_mode;
|
|
|
99 |
pdev->state.smoothness = s->smoothness;
|
|
|
100 |
pdev->state.flatness = s->flatness;
|
|
|
101 |
pdev->state.text_knockout = s->text_knockout;
|
|
|
102 |
pdev->fill_overprint = s->fill_overprint;
|
|
|
103 |
pdev->stroke_overprint = s->stroke_overprint;
|
|
|
104 |
pdev->state.stroke_adjust = s->stroke_adjust;
|
|
|
105 |
pdev->fill_used_process_color = s->fill_used_process_color;
|
|
|
106 |
pdev->stroke_used_process_color = s->stroke_used_process_color;
|
|
|
107 |
pdev->saved_fill_color = s->saved_fill_color;
|
|
|
108 |
pdev->saved_stroke_color = s->saved_stroke_color;
|
|
|
109 |
pdev->state.line_params = s->line_params;
|
|
|
110 |
memcpy(pdev->dash_pattern, s->dash_pattern,
|
|
|
111 |
sizeof(s->dash_pattern));
|
|
|
112 |
}
|
|
|
113 |
|
|
|
114 |
|
|
|
115 |
/* Restore the viewer's graphic state. */
|
|
|
116 |
int
|
|
|
117 |
pdf_restore_viewer_state(gx_device_pdf *pdev, stream *s)
|
|
|
118 |
{ const int i = --pdev->vgstack_depth;
|
|
|
119 |
|
|
|
120 |
if (i < pdev->vgstack_bottom || i < 0)
|
|
|
121 |
return_error(gs_error_unregistered); /* Must not happen. */
|
|
|
122 |
if (s)
|
|
|
123 |
stream_puts(s, "Q\n");
|
|
|
124 |
pdf_load_viewer_state(pdev, pdev->vgstack + i);
|
|
|
125 |
return 0;
|
|
|
126 |
}
|
|
|
127 |
|
|
|
128 |
/* Set initial color. */
|
|
|
129 |
void
|
|
|
130 |
pdf_set_initial_color(gx_device_pdf * pdev, gx_hl_saved_color *saved_fill_color,
|
|
|
131 |
gx_hl_saved_color *saved_stroke_color,
|
|
|
132 |
bool *fill_used_process_color, bool *stroke_used_process_color)
|
|
|
133 |
{
|
|
|
134 |
gx_device_color black;
|
|
|
135 |
|
|
|
136 |
pdev->black = gx_device_black((gx_device *)pdev);
|
|
|
137 |
pdev->white = gx_device_white((gx_device *)pdev);
|
|
|
138 |
set_nonclient_dev_color(&black, pdev->black);
|
|
|
139 |
gx_hld_save_color(NULL, &black, saved_fill_color);
|
|
|
140 |
gx_hld_save_color(NULL, &black, saved_stroke_color);
|
|
|
141 |
*fill_used_process_color = true;
|
|
|
142 |
*stroke_used_process_color = true;
|
|
|
143 |
}
|
|
|
144 |
|
|
|
145 |
/* Prepare intitial values for viewer's graphics state parameters. */
|
|
|
146 |
private void
|
|
|
147 |
pdf_viewer_state_from_imager_state_aux(pdf_viewer_state *pvs, const gs_imager_state *pis)
|
|
|
148 |
{
|
|
|
149 |
pvs->transfer_not_identity =
|
|
|
150 |
(pis->set_transfer.red != NULL ? pis->set_transfer.red->proc != gs_identity_transfer : 0) * 1 +
|
|
|
151 |
(pis->set_transfer.green != NULL ? pis->set_transfer.green->proc != gs_identity_transfer : 0) * 2 +
|
|
|
152 |
(pis->set_transfer.blue != NULL ? pis->set_transfer.blue->proc != gs_identity_transfer : 0) * 4 +
|
|
|
153 |
(pis->set_transfer.gray != NULL ? pis->set_transfer.gray->proc != gs_identity_transfer : 0) * 8;
|
|
|
154 |
pvs->transfer_ids[0] = (pis->set_transfer.red != NULL ? pis->set_transfer.red->id : 0);
|
|
|
155 |
pvs->transfer_ids[1] = (pis->set_transfer.green != NULL ? pis->set_transfer.green->id : 0);
|
|
|
156 |
pvs->transfer_ids[2] = (pis->set_transfer.blue != NULL ? pis->set_transfer.blue->id : 0);
|
|
|
157 |
pvs->transfer_ids[3] = (pis->set_transfer.gray != NULL ? pis->set_transfer.gray->id : 0);
|
|
|
158 |
pvs->opacity_alpha = pis->opacity.alpha;
|
|
|
159 |
pvs->shape_alpha = pis->shape.alpha;
|
|
|
160 |
pvs->blend_mode = pis->blend_mode;
|
|
|
161 |
pvs->halftone_id = (pis->dev_ht != 0 ? pis->dev_ht->id : 0);
|
|
|
162 |
pvs->black_generation_id = (pis->black_generation != 0 ? pis->black_generation->id : 0);
|
|
|
163 |
pvs->undercolor_removal_id = (pis->undercolor_removal != 0 ? pis->undercolor_removal->id : 0);
|
|
|
164 |
pvs->overprint_mode = 0;
|
|
|
165 |
pvs->smoothness = pis->smoothness;
|
|
|
166 |
pvs->text_knockout = pis->text_knockout;
|
|
|
167 |
pvs->fill_overprint = false;
|
|
|
168 |
pvs->stroke_overprint = false;
|
|
|
169 |
pvs->stroke_adjust = false;
|
|
|
170 |
pvs->line_params.half_width = 0.5;
|
|
|
171 |
pvs->line_params.cap = 0;
|
|
|
172 |
pvs->line_params.join = 0;
|
|
|
173 |
pvs->line_params.curve_join = 0;
|
|
|
174 |
pvs->line_params.miter_limit = 10.0;
|
|
|
175 |
pvs->line_params.miter_check = 0;
|
|
|
176 |
pvs->line_params.dot_length = pis->line_params.dot_length;
|
|
|
177 |
pvs->line_params.dot_length_absolute = pis->line_params.dot_length_absolute;
|
|
|
178 |
pvs->line_params.dot_orientation = pis->line_params.dot_orientation;
|
|
|
179 |
memset(&pvs->line_params.dash, 0 , sizeof(pvs->line_params.dash));
|
|
|
180 |
memset(pvs->dash_pattern, 0, sizeof(pvs->dash_pattern));
|
|
|
181 |
}
|
|
|
182 |
|
|
|
183 |
/* Copy viewer state from images state. */
|
|
|
184 |
void
|
|
|
185 |
pdf_viewer_state_from_imager_state(gx_device_pdf * pdev,
|
|
|
186 |
const gs_imager_state *pis, const gx_device_color *pdevc)
|
|
|
187 |
{
|
|
|
188 |
pdf_viewer_state vs;
|
|
|
189 |
|
|
|
190 |
pdf_viewer_state_from_imager_state_aux(&vs, pis);
|
|
|
191 |
gx_hld_save_color(pis, pdevc, &vs.saved_fill_color);
|
|
|
192 |
gx_hld_save_color(pis, pdevc, &vs.saved_stroke_color);
|
|
|
193 |
pdf_load_viewer_state(pdev, &vs);
|
|
|
194 |
}
|
|
|
195 |
|
|
|
196 |
/* Prepare intitial values for viewer's graphics state parameters. */
|
|
|
197 |
void
|
|
|
198 |
pdf_prepare_initial_viewer_state(gx_device_pdf * pdev, const gs_imager_state *pis)
|
|
|
199 |
{
|
|
|
200 |
/* Parameter values, which are specified in PDF spec, are set here.
|
|
|
201 |
* Parameter values, which are specified in PDF spec as "installation dependent",
|
|
|
202 |
* are set here to intial values used with PS interpreter.
|
|
|
203 |
* This allows to write differences to the output file
|
|
|
204 |
* and skip initial values.
|
|
|
205 |
*/
|
|
|
206 |
|
|
|
207 |
pdf_set_initial_color(pdev, &pdev->vg_initial.saved_fill_color, &pdev->vg_initial.saved_stroke_color,
|
|
|
208 |
&pdev->vg_initial.fill_used_process_color, &pdev->vg_initial.stroke_used_process_color);
|
|
|
209 |
pdf_viewer_state_from_imager_state_aux(&pdev->vg_initial, pis);
|
|
|
210 |
pdev->vg_initial_set = true;
|
|
|
211 |
/*
|
|
|
212 |
* Some parameters listed in PDF spec are missed here :
|
|
|
213 |
* text state - it is initialized per page.
|
|
|
214 |
* rendering intent - not sure why, fixme.
|
|
|
215 |
*/
|
|
|
216 |
}
|
|
|
217 |
|
|
|
218 |
/* Reset the graphics state parameters to initial values. */
|
|
|
219 |
/* Used if pdf_prepare_initial_viewer_state was not callad. */
|
|
|
220 |
private void
|
|
|
221 |
pdf_reset_graphics_old(gx_device_pdf * pdev)
|
|
|
222 |
{
|
|
|
223 |
|
|
|
224 |
pdf_set_initial_color(pdev, &pdev->saved_fill_color, &pdev->saved_stroke_color,
|
|
|
225 |
&pdev->fill_used_process_color, &pdev->stroke_used_process_color);
|
|
|
226 |
pdev->state.flatness = -1;
|
|
|
227 |
{
|
|
|
228 |
static const gx_line_params lp_initial = {
|
|
|
229 |
gx_line_params_initial
|
|
|
230 |
};
|
|
|
231 |
|
|
|
232 |
pdev->state.line_params = lp_initial;
|
|
|
233 |
}
|
|
|
234 |
pdev->fill_overprint = false;
|
|
|
235 |
pdev->stroke_overprint = false;
|
|
|
236 |
pdf_reset_text(pdev);
|
|
|
237 |
}
|
|
|
238 |
|
|
|
239 |
/* Reset the graphics state parameters to initial values. */
|
|
|
240 |
void
|
|
|
241 |
pdf_reset_graphics(gx_device_pdf * pdev)
|
|
|
242 |
{
|
|
|
243 |
if (pdev->vg_initial_set)
|
|
|
244 |
pdf_load_viewer_state(pdev, &pdev->vg_initial);
|
|
|
245 |
else
|
|
|
246 |
pdf_reset_graphics_old(pdev);
|
|
|
247 |
pdf_reset_text(pdev);
|
|
|
248 |
}
|
|
|
249 |
|
|
|
250 |
/* Write client color. */
|
|
|
251 |
private int
|
|
|
252 |
pdf_write_ccolor(gx_device_pdf * pdev, const gs_imager_state * pis,
|
|
|
253 |
const gs_client_color *pcc)
|
|
|
254 |
{
|
|
|
255 |
int i, n = gx_hld_get_number_color_components(pis);
|
|
|
256 |
|
|
|
257 |
pprintg1(pdev->strm, "%g", psdf_round(pcc->paint.values[0], 255, 8));
|
|
|
258 |
for (i = 1; i < n; i++) {
|
|
|
259 |
pprintg1(pdev->strm, " %g", psdf_round(pcc->paint.values[i], 255, 8));
|
|
|
260 |
}
|
|
|
261 |
return 0;
|
|
|
262 |
}
|
|
|
263 |
|
|
|
264 |
|
|
|
265 |
/* Set the fill or stroke color. */
|
|
|
266 |
private int
|
|
|
267 |
pdf_reset_color(gx_device_pdf * pdev, const gs_imager_state * pis,
|
|
|
268 |
const gx_drawing_color *pdc, gx_hl_saved_color * psc,
|
|
|
269 |
bool *used_process_color,
|
|
|
270 |
const psdf_set_color_commands_t *ppscc)
|
|
|
271 |
{
|
|
|
272 |
int code;
|
|
|
273 |
gx_hl_saved_color temp;
|
|
|
274 |
bool process_color;
|
|
|
275 |
const gs_color_space *pcs, *pcs2;
|
|
|
276 |
const gs_client_color *pcc; /* fixme: not needed due to gx_hld_get_color_component. */
|
|
|
277 |
cos_value_t cs_value;
|
|
|
278 |
const char *command;
|
|
|
279 |
int code1 = 0;
|
|
|
280 |
gs_color_space_index csi;
|
|
|
281 |
|
|
|
282 |
if (pdev->skip_colors)
|
|
|
283 |
return 0;
|
|
|
284 |
process_color = !gx_hld_save_color(pis, pdc, &temp);
|
|
|
285 |
/* Since pdfwrite never applies halftones and patterns, but monitors
|
|
|
286 |
* halftone/pattern IDs separately, we don't need to compare
|
|
|
287 |
* halftone/pattern bodies here.
|
|
|
288 |
*/
|
|
|
289 |
if (gx_hld_saved_color_equal(&temp, psc))
|
|
|
290 |
return 0;
|
|
|
291 |
/*
|
|
|
292 |
* In principle, we can set colors in either stream or text
|
|
|
293 |
* context. However, since we currently enclose all text
|
|
|
294 |
* strings inside a gsave/grestore, this causes us to lose
|
|
|
295 |
* track of the color when we leave text context. Therefore,
|
|
|
296 |
* we require stream context for setting colors.
|
|
|
297 |
*/
|
|
|
298 |
code = pdf_open_page(pdev, PDF_IN_STREAM);
|
|
|
299 |
if (code < 0)
|
|
|
300 |
return code;
|
|
|
301 |
switch (gx_hld_get_color_space_and_ccolor(pis, pdc, &pcs, &pcc)) {
|
|
|
302 |
case non_pattern_color_space:
|
|
|
303 |
switch (gs_color_space_get_index(pcs)) {
|
|
|
304 |
case gs_color_space_index_DeviceGray:
|
|
|
305 |
command = ppscc->setgray;
|
|
|
306 |
break;
|
|
|
307 |
case gs_color_space_index_DeviceRGB:
|
|
|
308 |
command = ppscc->setrgbcolor;
|
|
|
309 |
break;
|
|
|
310 |
case gs_color_space_index_DeviceCMYK:
|
|
|
311 |
command = ppscc->setcmykcolor;
|
|
|
312 |
break;
|
|
|
313 |
case gs_color_space_index_Indexed:
|
|
|
314 |
if (pdev->CompatibilityLevel <= 1.2) {
|
|
|
315 |
pcs2 = (const gs_color_space *)&pcs->params.indexed.base_space;
|
|
|
316 |
csi = gs_color_space_get_index(pcs2);
|
|
|
317 |
if (csi == gs_color_space_index_Separation) {
|
|
|
318 |
pcs2 = (const gs_color_space *)&pcs2->params.separation.alt_space;
|
|
|
319 |
goto check_pcs2;
|
|
|
320 |
}
|
|
|
321 |
goto check_pcs2;
|
|
|
322 |
}
|
|
|
323 |
goto scn;
|
|
|
324 |
case gs_color_space_index_Separation:
|
|
|
325 |
if (pdev->CompatibilityLevel <= 1.2) {
|
|
|
326 |
pcs2 = (const gs_color_space *)&pcs->params.separation.alt_space;
|
|
|
327 |
check_pcs2:
|
|
|
328 |
csi = gs_color_space_get_index(pcs2);
|
|
|
329 |
switch(gs_color_space_get_index(pcs2)) {
|
|
|
330 |
case gs_color_space_index_DevicePixel :
|
|
|
331 |
case gs_color_space_index_DeviceN:
|
|
|
332 |
case gs_color_space_index_CIEICC:
|
|
|
333 |
goto write_process_color;
|
|
|
334 |
default:
|
|
|
335 |
DO_NOTHING;
|
|
|
336 |
}
|
|
|
337 |
}
|
|
|
338 |
goto scn;
|
|
|
339 |
case gs_color_space_index_CIEICC:
|
|
|
340 |
case gs_color_space_index_DevicePixel:
|
|
|
341 |
case gs_color_space_index_DeviceN:
|
|
|
342 |
if (pdev->CompatibilityLevel <= 1.2)
|
|
|
343 |
goto write_process_color;
|
|
|
344 |
goto scn;
|
|
|
345 |
default :
|
|
|
346 |
scn:
|
|
|
347 |
command = ppscc->setcolorn;
|
|
|
348 |
if (!gx_hld_saved_color_same_cspace(&temp, psc)) {
|
|
|
349 |
code = pdf_color_space(pdev, &cs_value, NULL, pcs,
|
|
|
350 |
&pdf_color_space_names, true);
|
|
|
351 |
/* fixme : creates redundant PDF objects. */
|
|
|
352 |
if (code == gs_error_rangecheck) {
|
|
|
353 |
/* The color space can't write to PDF. */
|
|
|
354 |
goto write_process_color;
|
|
|
355 |
}
|
|
|
356 |
if (code < 0)
|
|
|
357 |
return code;
|
|
|
358 |
code = cos_value_write(&cs_value, pdev);
|
|
|
359 |
if (code < 0)
|
|
|
360 |
return code;
|
|
|
361 |
pprints1(pdev->strm, " %s\n", ppscc->setcolorspace);
|
|
|
362 |
} else if (*used_process_color)
|
|
|
363 |
goto write_process_color;
|
|
|
364 |
break;
|
|
|
365 |
}
|
|
|
366 |
*used_process_color = false;
|
|
|
367 |
code = pdf_write_ccolor(pdev, pis, pcc);
|
|
|
368 |
if (code < 0)
|
|
|
369 |
return code;
|
|
|
370 |
pprints1(pdev->strm, " %s\n", command);
|
|
|
371 |
break;
|
|
|
372 |
case pattern_color_sapce:
|
|
|
373 |
{ pdf_resource_t *pres;
|
|
|
374 |
|
|
|
375 |
if (pdc->type == gx_dc_type_pattern)
|
|
|
376 |
code = pdf_put_colored_pattern(pdev, pdc, pcs,
|
|
|
377 |
ppscc, pis->have_pattern_streams, &pres);
|
|
|
378 |
else if (pdc->type == &gx_dc_pure_masked) {
|
|
|
379 |
code = pdf_put_uncolored_pattern(pdev, pdc, pcs,
|
|
|
380 |
ppscc, pis->have_pattern_streams, &pres);
|
|
|
381 |
if (code < 0 || pres == 0)
|
|
|
382 |
return code;
|
|
|
383 |
if (pis->have_pattern_streams)
|
|
|
384 |
code = pdf_write_ccolor(pdev, pis, pcc);
|
|
|
385 |
} else if (pdc->type == &gx_dc_pattern2) {
|
|
|
386 |
if (pdev->CompatibilityLevel <= 1.2)
|
|
|
387 |
return_error(gs_error_rangecheck);
|
|
|
388 |
code1 = pdf_put_pattern2(pdev, pdc, ppscc, &pres);
|
|
|
389 |
} else
|
|
|
390 |
return_error(gs_error_rangecheck);
|
|
|
391 |
if (code < 0)
|
|
|
392 |
return code;
|
|
|
393 |
cos_value_write(cos_resource_value(&cs_value, pres->object), pdev);
|
|
|
394 |
pprints1(pdev->strm, " %s\n", ppscc->setcolorn);
|
|
|
395 |
code = pdf_add_resource(pdev, pdev->substream_Resources, "/Pattern", pres);
|
|
|
396 |
if (code < 0)
|
|
|
397 |
return code;
|
|
|
398 |
}
|
|
|
399 |
*used_process_color = false;
|
|
|
400 |
break;
|
|
|
401 |
default: /* must not happen. */
|
|
|
402 |
case use_process_color:
|
|
|
403 |
write_process_color:
|
|
|
404 |
code = psdf_set_color((gx_device_vector *)pdev, pdc, ppscc);
|
|
|
405 |
if (code < 0)
|
|
|
406 |
return code;
|
|
|
407 |
*used_process_color = true;
|
|
|
408 |
}
|
|
|
409 |
*psc = temp;
|
|
|
410 |
return code1;
|
|
|
411 |
}
|
|
|
412 |
int
|
|
|
413 |
pdf_set_drawing_color(gx_device_pdf * pdev, const gs_imager_state * pis,
|
|
|
414 |
const gx_drawing_color *pdc,
|
|
|
415 |
gx_hl_saved_color * psc,
|
|
|
416 |
bool *used_process_color,
|
|
|
417 |
const psdf_set_color_commands_t *ppscc)
|
|
|
418 |
{
|
|
|
419 |
return pdf_reset_color(pdev, pis, pdc, psc, used_process_color, ppscc);
|
|
|
420 |
}
|
|
|
421 |
int
|
|
|
422 |
pdf_set_pure_color(gx_device_pdf * pdev, gx_color_index color,
|
|
|
423 |
gx_hl_saved_color * psc,
|
|
|
424 |
bool *used_process_color,
|
|
|
425 |
const psdf_set_color_commands_t *ppscc)
|
|
|
426 |
{
|
|
|
427 |
gx_drawing_color dcolor;
|
|
|
428 |
|
|
|
429 |
set_nonclient_dev_color(&dcolor, color);
|
|
|
430 |
return pdf_reset_color(pdev, NULL, &dcolor, psc, used_process_color, ppscc);
|
|
|
431 |
}
|
|
|
432 |
|
|
|
433 |
/*
|
|
|
434 |
* Convert a string into cos name.
|
|
|
435 |
*/
|
|
|
436 |
int
|
|
|
437 |
pdf_string_to_cos_name(gx_device_pdf *pdev, const byte *str, uint len,
|
|
|
438 |
cos_value_t *pvalue)
|
|
|
439 |
{
|
|
|
440 |
byte *chars = gs_alloc_string(pdev->pdf_memory, len + 1,
|
|
|
441 |
"pdf_string_to_cos_name");
|
|
|
442 |
|
|
|
443 |
if (chars == 0)
|
|
|
444 |
return_error(gs_error_VMerror);
|
|
|
445 |
chars[0] = '/';
|
|
|
446 |
memcpy(chars + 1, str, len);
|
|
|
447 |
cos_string_value(pvalue, chars, len + 1);
|
|
|
448 |
return 0;
|
|
|
449 |
}
|
|
|
450 |
|
|
|
451 |
/* ---------------- Graphics state updating ---------------- */
|
|
|
452 |
|
|
|
453 |
/* ------ Functions ------ */
|
|
|
454 |
|
|
|
455 |
/* Define the maximum size of a Function reference. */
|
|
|
456 |
#define MAX_FN_NAME_CHARS 9 /* /Default, /Identity */
|
|
|
457 |
#define MAX_FN_CHARS max(MAX_REF_CHARS + 4, MAX_FN_NAME_CHARS)
|
|
|
458 |
|
|
|
459 |
/*
|
|
|
460 |
* Create and write a Function for a gx_transfer_map. We use this for
|
|
|
461 |
* transfer, BG, and UCR functions. If check_identity is true, check for
|
|
|
462 |
* an identity map. Return 1 if the map is the identity map, otherwise
|
|
|
463 |
* return 0.
|
|
|
464 |
*/
|
|
|
465 |
private data_source_proc_access(transfer_map_access); /* check prototype */
|
|
|
466 |
private int
|
|
|
467 |
transfer_map_access(const gs_data_source_t *psrc, ulong start, uint length,
|
|
|
468 |
byte *buf, const byte **ptr)
|
|
|
469 |
{
|
|
|
470 |
const gx_transfer_map *map = (const gx_transfer_map *)psrc->data.str.data;
|
|
|
471 |
uint i;
|
|
|
472 |
|
|
|
473 |
if (ptr)
|
|
|
474 |
*ptr = buf;
|
|
|
475 |
for (i = 0; i < length; ++i)
|
|
|
476 |
buf[i] = frac2byte(map->values[(uint)start + i]);
|
|
|
477 |
return 0;
|
|
|
478 |
}
|
|
|
479 |
private int
|
|
|
480 |
transfer_map_access_signed(const gs_data_source_t *psrc,
|
|
|
481 |
ulong start, uint length,
|
|
|
482 |
byte *buf, const byte **ptr)
|
|
|
483 |
{
|
|
|
484 |
/* To prevent numeric errors, we need to map 0 to an integer.
|
|
|
485 |
* We can't apply a general expression, because Decode isn't accessible here.
|
|
|
486 |
* Assuming this works for UCR only.
|
|
|
487 |
* Assuming the range of UCR is always [-1, 1].
|
|
|
488 |
* Assuming BitsPerSample = 8.
|
|
|
489 |
*/
|
|
|
490 |
const gx_transfer_map *map = (const gx_transfer_map *)psrc->data.str.data;
|
|
|
491 |
uint i;
|
|
|
492 |
|
|
|
493 |
*ptr = buf;
|
|
|
494 |
for (i = 0; i < length; ++i)
|
|
|
495 |
buf[i] = (byte)
|
|
|
496 |
((frac2float(map->values[(uint)start + i]) + 1) * 127);
|
|
|
497 |
return 0;
|
|
|
498 |
}
|
|
|
499 |
private int
|
|
|
500 |
pdf_write_transfer_map(gx_device_pdf *pdev, const gx_transfer_map *map,
|
|
|
501 |
int range0, bool check_identity,
|
|
|
502 |
const char *key, char *ids)
|
|
|
503 |
{
|
|
|
504 |
gs_memory_t *mem = pdev->pdf_memory;
|
|
|
505 |
gs_function_Sd_params_t params;
|
|
|
506 |
static const float domain01[2] = { 0, 1 };
|
|
|
507 |
static const int size = transfer_map_size;
|
|
|
508 |
float range01[2], decode[2];
|
|
|
509 |
gs_function_t *pfn;
|
|
|
510 |
long id;
|
|
|
511 |
int code;
|
|
|
512 |
|
|
|
513 |
if (map == 0) {
|
|
|
514 |
*ids = 0; /* no map */
|
|
|
515 |
return 1;
|
|
|
516 |
}
|
|
|
517 |
if (check_identity) {
|
|
|
518 |
/* Check for an identity map. */
|
|
|
519 |
int i;
|
|
|
520 |
|
|
|
521 |
if (map->proc == gs_identity_transfer)
|
|
|
522 |
i = transfer_map_size;
|
|
|
523 |
else
|
|
|
524 |
for (i = 0; i < transfer_map_size; ++i) {
|
|
|
525 |
fixed d = map->values[i] - bits2frac(i, log2_transfer_map_size);
|
|
|
526 |
if (any_abs(d) > fixed_epsilon) /* ignore small noise */
|
|
|
527 |
break;
|
|
|
528 |
}
|
|
|
529 |
if (i == transfer_map_size) {
|
|
|
530 |
strcpy(ids, key);
|
|
|
531 |
strcat(ids, "/Identity");
|
|
|
532 |
return 1;
|
|
|
533 |
}
|
|
|
534 |
}
|
|
|
535 |
params.m = 1;
|
|
|
536 |
params.Domain = domain01;
|
|
|
537 |
params.n = 1;
|
|
|
538 |
range01[0] = (float)range0, range01[1] = 1.0;
|
|
|
539 |
params.Range = range01;
|
|
|
540 |
params.Order = 1;
|
|
|
541 |
params.DataSource.access =
|
|
|
542 |
(range0 < 0 ? transfer_map_access_signed : transfer_map_access);
|
|
|
543 |
params.DataSource.data.str.data = (const byte *)map; /* bogus */
|
|
|
544 |
/* DataSource */
|
|
|
545 |
params.BitsPerSample = 8; /* could be 16 */
|
|
|
546 |
params.Encode = 0;
|
|
|
547 |
if (range01[0] < 0 && range01[1] > 0) {
|
|
|
548 |
/* This works for UCR only.
|
|
|
549 |
* Map 0 to an integer.
|
|
|
550 |
* Rather the range of UCR is always [-1, 1],
|
|
|
551 |
* we prefer a general expression.
|
|
|
552 |
*/
|
|
|
553 |
int r0 = (int)( -range01[0] * ((1 << params.BitsPerSample) - 1)
|
|
|
554 |
/ (range01[1] - range01[0]) ); /* Round down. */
|
|
|
555 |
float r1 = r0 * range01[1] / -range01[0]; /* r0 + r1 <= (1 << params.BitsPerSample) - 1 */
|
|
|
556 |
|
|
|
557 |
decode[0] = range01[0];
|
|
|
558 |
decode[1] = range01[0] + (range01[1] - range01[0]) * ((1 << params.BitsPerSample) - 1)
|
|
|
559 |
/ (r0 + r1);
|
|
|
560 |
params.Decode = decode;
|
|
|
561 |
} else
|
|
|
562 |
params.Decode = 0;
|
|
|
563 |
params.Size = &size;
|
|
|
564 |
code = gs_function_Sd_init(&pfn, ¶ms, mem);
|
|
|
565 |
if (code < 0)
|
|
|
566 |
return code;
|
|
|
567 |
code = pdf_write_function(pdev, pfn, &id);
|
|
|
568 |
gs_function_free(pfn, false, mem);
|
|
|
569 |
if (code < 0)
|
|
|
570 |
return code;
|
|
|
571 |
sprintf(ids, "%s%s%ld 0 R", key, (key[0] && key[0] != ' ' ? " " : ""), id);
|
|
|
572 |
return 0;
|
|
|
573 |
}
|
|
|
574 |
private int
|
|
|
575 |
pdf_write_transfer(gx_device_pdf *pdev, const gx_transfer_map *map,
|
|
|
576 |
const char *key, char *ids)
|
|
|
577 |
{
|
|
|
578 |
return pdf_write_transfer_map(pdev, map, 0, true, key, ids);
|
|
|
579 |
}
|
|
|
580 |
|
|
|
581 |
/* ------ Halftones ------ */
|
|
|
582 |
|
|
|
583 |
/*
|
|
|
584 |
* Recognize the predefined PDF halftone functions. Note that because the
|
|
|
585 |
* corresponding PostScript functions use single-precision floats, the
|
|
|
586 |
* functions used for testing must do the same in order to get identical
|
|
|
587 |
* results. Currently we only do this for a few of the functions.
|
|
|
588 |
*/
|
|
|
589 |
#define HT_FUNC(name, expr)\
|
|
|
590 |
private floatp name(floatp xd, floatp yd) {\
|
|
|
591 |
float x = (float)xd, y = (float)yd;\
|
|
|
592 |
return d2f(expr);\
|
|
|
593 |
}
|
|
|
594 |
|
|
|
595 |
/*
|
|
|
596 |
* In most versions of gcc (e.g., 2.7.2.3, 2.95.4), return (float)xxx
|
|
|
597 |
* doesn't actually do the coercion. Force this here. Note that if we
|
|
|
598 |
* use 'inline', it doesn't work.
|
|
|
599 |
*/
|
|
|
600 |
private float
|
|
|
601 |
d2f(floatp d)
|
|
|
602 |
{
|
|
|
603 |
float f = (float)d;
|
|
|
604 |
return f;
|
|
|
605 |
}
|
|
|
606 |
private floatp
|
|
|
607 |
ht_Round(floatp xf, floatp yf)
|
|
|
608 |
{
|
|
|
609 |
float x = (float)xf, y = (float)yf;
|
|
|
610 |
float xabs = fabs(x), yabs = fabs(y);
|
|
|
611 |
|
|
|
612 |
if (d2f(xabs + yabs) <= 1)
|
|
|
613 |
return d2f(1 - d2f(d2f(x * x) + d2f(y * y)));
|
|
|
614 |
xabs -= 1, yabs -= 1;
|
|
|
615 |
return d2f(d2f(d2f(xabs * xabs) + d2f(yabs * yabs)) - 1);
|
|
|
616 |
}
|
|
|
617 |
private floatp
|
|
|
618 |
ht_Diamond(floatp xf, floatp yf)
|
|
|
619 |
{
|
|
|
620 |
float x = (float)xf, y = (float)yf;
|
|
|
621 |
float xabs = fabs(x), yabs = fabs(y);
|
|
|
622 |
|
|
|
623 |
if (d2f(xabs + yabs) <= 0.75)
|
|
|
624 |
return d2f(1 - d2f(d2f(x * x) + d2f(y * y)));
|
|
|
625 |
if (d2f(xabs + yabs) <= d2f(1.23))
|
|
|
626 |
return d2f(1 - d2f(d2f(d2f(0.85) * xabs) + yabs));
|
|
|
627 |
xabs -= 1, yabs -= 1;
|
|
|
628 |
return d2f(d2f(d2f(xabs * xabs) + d2f(yabs * yabs)) - 1);
|
|
|
629 |
}
|
|
|
630 |
private floatp
|
|
|
631 |
ht_Ellipse(floatp xf, floatp yf)
|
|
|
632 |
{
|
|
|
633 |
float x = (float)xf, y = (float)yf;
|
|
|
634 |
float xabs = fabs(x), yabs = fabs(y);
|
|
|
635 |
/*
|
|
|
636 |
* The PDF Reference, 2nd edition, incorrectly specifies the
|
|
|
637 |
* computation w = 4 * |x| + 3 * |y| - 3. The PostScript code in the
|
|
|
638 |
* same book correctly implements w = 3 * |x| + 4 * |y| - 3.
|
|
|
639 |
*/
|
|
|
640 |
float w = (float)(d2f(d2f(3 * xabs) + d2f(4 * yabs)) - 3);
|
|
|
641 |
|
|
|
642 |
if (w < 0) {
|
|
|
643 |
yabs /= 0.75;
|
|
|
644 |
return d2f(1 - d2f((d2f(x * x) + d2f(yabs * yabs)) / 4));
|
|
|
645 |
}
|
|
|
646 |
if (w > 1) {
|
|
|
647 |
xabs = 1 - xabs, yabs = d2f(1 - yabs) / 0.75;
|
|
|
648 |
return d2f(d2f((d2f(xabs * xabs) + d2f(yabs * yabs)) / 4) - 1);
|
|
|
649 |
}
|
|
|
650 |
return d2f(0.5 - w);
|
|
|
651 |
}
|
|
|
652 |
/*
|
|
|
653 |
* Most of these are recognized properly even without d2f. We've only
|
|
|
654 |
* added d2f where it apparently makes a difference.
|
|
|
655 |
*/
|
|
|
656 |
private float
|
|
|
657 |
d2fsin_d(double x) {
|
|
|
658 |
return d2f(gs_sin_degrees(d2f(x)));
|
|
|
659 |
}
|
|
|
660 |
private float
|
|
|
661 |
d2fcos_d(double x) {
|
|
|
662 |
return d2f(gs_cos_degrees(d2f(x)));
|
|
|
663 |
}
|
|
|
664 |
HT_FUNC(ht_EllipseA, 1 - (x * x + 0.9 * y * y))
|
|
|
665 |
HT_FUNC(ht_InvertedEllipseA, x * x + 0.9 * y * y - 1)
|
|
|
666 |
HT_FUNC(ht_EllipseB, 1 - sqrt(x * x + 0.625 * y * y))
|
|
|
667 |
HT_FUNC(ht_EllipseC, 1 - (0.9 * x * x + y * y))
|
|
|
668 |
HT_FUNC(ht_InvertedEllipseC, 0.9 * x * x + y * y - 1)
|
|
|
669 |
HT_FUNC(ht_Line, -fabs((x - x) + y)) /* quiet compiler (unused variable x) */
|
|
|
670 |
HT_FUNC(ht_LineX, (y - y) + x) /* quiet compiler (unused variable y) */
|
|
|
671 |
HT_FUNC(ht_LineY, (x - x) + y) /* quiet compiler (unused variable x) */
|
|
|
672 |
HT_FUNC(ht_Square, -max(fabs(x), fabs(y)))
|
|
|
673 |
HT_FUNC(ht_Cross, -min(fabs(x), fabs(y)))
|
|
|
674 |
HT_FUNC(ht_Rhomboid, (0.9 * fabs(x) + fabs(y)) / 2)
|
|
|
675 |
HT_FUNC(ht_DoubleDot, (d2fsin_d(x * 360) + d2fsin_d(y * 360)) / 2)
|
|
|
676 |
HT_FUNC(ht_InvertedDoubleDot, -(d2fsin_d(x * 360) + d2fsin_d(y * 360)) / 2)
|
|
|
677 |
HT_FUNC(ht_SimpleDot, 1 - d2f(d2f(x * x) + d2f(y * y)))
|
|
|
678 |
HT_FUNC(ht_InvertedSimpleDot, d2f(d2f(x * x) + d2f(y * y)) - 1)
|
|
|
679 |
HT_FUNC(ht_CosineDot, (d2fcos_d(x * 180) + d2fcos_d(y * 180)) / 2)
|
|
|
680 |
HT_FUNC(ht_Double, (d2fsin_d(x * 180) + d2fsin_d(y * 360)) / 2)
|
|
|
681 |
HT_FUNC(ht_InvertedDouble, -(d2fsin_d(x * 180) + d2fsin_d(y * 360)) / 2)
|
|
|
682 |
typedef struct ht_function_s {
|
|
|
683 |
const char *fname;
|
|
|
684 |
floatp (*proc)(floatp, floatp);
|
|
|
685 |
} ht_function_t;
|
|
|
686 |
private const ht_function_t ht_functions[] = {
|
|
|
687 |
{"Round", ht_Round},
|
|
|
688 |
{"Diamond", ht_Diamond},
|
|
|
689 |
{"Ellipse", ht_Ellipse},
|
|
|
690 |
{"EllipseA", ht_EllipseA},
|
|
|
691 |
{"InvertedEllipseA", ht_InvertedEllipseA},
|
|
|
692 |
{"EllipseB", ht_EllipseB},
|
|
|
693 |
{"EllipseC", ht_EllipseC},
|
|
|
694 |
{"InvertedEllipseC", ht_InvertedEllipseC},
|
|
|
695 |
{"Line", ht_Line},
|
|
|
696 |
{"LineX", ht_LineX},
|
|
|
697 |
{"LineY", ht_LineY},
|
|
|
698 |
{"Square", ht_Square},
|
|
|
699 |
{"Cross", ht_Cross},
|
|
|
700 |
{"Rhomboid", ht_Rhomboid},
|
|
|
701 |
{"DoubleDot", ht_DoubleDot},
|
|
|
702 |
{"InvertedDoubleDot", ht_InvertedDoubleDot},
|
|
|
703 |
{"SimpleDot", ht_SimpleDot},
|
|
|
704 |
{"InvertedSimpleDot", ht_InvertedSimpleDot},
|
|
|
705 |
{"CosineDot", ht_CosineDot},
|
|
|
706 |
{"Double", ht_Double},
|
|
|
707 |
{"InvertedDouble", ht_InvertedDouble}
|
|
|
708 |
};
|
|
|
709 |
|
|
|
710 |
/* Write each kind of halftone. */
|
|
|
711 |
private int
|
|
|
712 |
pdf_write_spot_function(gx_device_pdf *pdev, const gx_ht_order *porder,
|
|
|
713 |
long *pid)
|
|
|
714 |
{
|
|
|
715 |
/****** DOESN'T HANDLE STRIP HALFTONES ******/
|
|
|
716 |
int w = porder->width, h = porder->height;
|
|
|
717 |
uint num_bits = porder->num_bits;
|
|
|
718 |
gs_function_Sd_params_t params;
|
|
|
719 |
static const float domain_spot[4] = { -1, 1, -1, 1 };
|
|
|
720 |
static const float range_spot[4] = { -1, 1 };
|
|
|
721 |
int size[2];
|
|
|
722 |
gs_memory_t *mem = pdev->pdf_memory;
|
|
|
723 |
/*
|
|
|
724 |
* Even though the values are logically ushort, we must always store
|
|
|
725 |
* them in big-endian order, so we access them as bytes.
|
|
|
726 |
*/
|
|
|
727 |
byte *values;
|
|
|
728 |
gs_function_t *pfn;
|
|
|
729 |
uint i;
|
|
|
730 |
int code = 0;
|
|
|
731 |
|
|
|
732 |
params.m = 2;
|
|
|
733 |
params.Domain = domain_spot;
|
|
|
734 |
params.n = 1;
|
|
|
735 |
params.Range = range_spot;
|
|
|
736 |
params.Order = 0; /* default */
|
|
|
737 |
/*
|
|
|
738 |
* We could use 8, 16, or 32 bits per sample to save space, but for
|
|
|
739 |
* simplicity, we always use 16.
|
|
|
740 |
*/
|
|
|
741 |
if (num_bits > 0x10000)
|
|
|
742 |
return_error(gs_error_rangecheck);
|
|
|
743 |
params.BitsPerSample = 16;
|
|
|
744 |
params.Encode = 0;
|
|
|
745 |
/*
|
|
|
746 |
* The default Decode array maps the actual data values [1 .. w*h] to a
|
|
|
747 |
* sub-interval of the Range, but that's OK, since all that matters is
|
|
|
748 |
* the relative values, not the absolute values.
|
|
|
749 |
*/
|
|
|
750 |
params.Decode = 0;
|
|
|
751 |
size[0] = w;
|
|
|
752 |
size[1] = h;
|
|
|
753 |
params.Size = size;
|
|
|
754 |
/* Create the (temporary) threshold array. */
|
|
|
755 |
values = gs_alloc_byte_array(mem, num_bits, 2, "pdf_write_spot_function");
|
|
|
756 |
if (values == 0)
|
|
|
757 |
return_error(gs_error_VMerror);
|
|
|
758 |
for (i = 0; i < num_bits; ++i) {
|
|
|
759 |
gs_int_point pt;
|
|
|
760 |
int value;
|
|
|
761 |
|
|
|
762 |
if ((code = porder->procs->bit_index(porder, i, &pt)) < 0)
|
|
|
763 |
break;
|
|
|
764 |
value = pt.y * w + pt.x;
|
|
|
765 |
/* Always store the values in big-endian order. */
|
|
|
766 |
values[i * 2] = (byte)(value >> 8);
|
|
|
767 |
values[i * 2 + 1] = (byte)value;
|
|
|
768 |
}
|
|
|
769 |
data_source_init_bytes(¶ms.DataSource, (const byte *)values,
|
|
|
770 |
sizeof(*values) * num_bits);
|
|
|
771 |
if (code >= 0 &&
|
|
|
772 |
(code = gs_function_Sd_init(&pfn, ¶ms, mem)) >= 0
|
|
|
773 |
) {
|
|
|
774 |
code = pdf_write_function(pdev, pfn, pid);
|
|
|
775 |
gs_function_free(pfn, false, mem);
|
|
|
776 |
}
|
|
|
777 |
gs_free_object(mem, values, "pdf_write_spot_function");
|
|
|
778 |
return code;
|
|
|
779 |
}
|
|
|
780 |
private int
|
|
|
781 |
pdf_write_spot_halftone(gx_device_pdf *pdev, const gs_spot_halftone *psht,
|
|
|
782 |
const gx_ht_order *porder, long *pid)
|
|
|
783 |
{
|
|
|
784 |
char trs[17 + MAX_FN_CHARS + 1];
|
|
|
785 |
int code = pdf_write_transfer(pdev, porder->transfer, "/TransferFunction",
|
|
|
786 |
trs);
|
|
|
787 |
long id, spot_id;
|
|
|
788 |
stream *s;
|
|
|
789 |
int i = countof(ht_functions);
|
|
|
790 |
gs_memory_t *mem = pdev->pdf_memory;
|
|
|
791 |
|
|
|
792 |
if (code < 0)
|
|
|
793 |
return code;
|
|
|
794 |
/*
|
|
|
795 |
* See if we can recognize the spot function, by comparing its sampled
|
|
|
796 |
* values against those in the order.
|
|
|
797 |
*/
|
|
|
798 |
{ gs_screen_enum senum;
|
|
|
799 |
gx_ht_order order;
|
|
|
800 |
int code;
|
|
|
801 |
|
|
|
802 |
order = *porder;
|
|
|
803 |
code = gs_screen_order_alloc(&order, mem);
|
|
|
804 |
if (code < 0)
|
|
|
805 |
goto notrec;
|
|
|
806 |
for (i = 0; i < countof(ht_functions); ++i) {
|
|
|
807 |
floatp (*spot_proc)(floatp, floatp) = ht_functions[i].proc;
|
|
|
808 |
gs_point pt;
|
|
|
809 |
|
|
|
810 |
gs_screen_enum_init_memory(&senum, &order, NULL, &psht->screen,
|
|
|
811 |
mem);
|
|
|
812 |
while ((code = gs_screen_currentpoint(&senum, &pt)) == 0 &&
|
|
|
813 |
gs_screen_next(&senum, spot_proc(pt.x, pt.y)) >= 0)
|
|
|
814 |
DO_NOTHING;
|
|
|
815 |
if (code < 0)
|
|
|
816 |
continue;
|
|
|
817 |
/* Compare the bits and levels arrays. */
|
|
|
818 |
if (memcmp(order.levels, porder->levels,
|
|
|
819 |
order.num_levels * sizeof(*order.levels)))
|
|
|
820 |
continue;
|
|
|
821 |
if (memcmp(order.bit_data, porder->bit_data,
|
|
|
822 |
order.num_bits * porder->procs->bit_data_elt_size))
|
|
|
823 |
continue;
|
|
|
824 |
/* We have a match. */
|
|
|
825 |
break;
|
|
|
826 |
}
|
|
|
827 |
gx_ht_order_release(&order, mem, false);
|
|
|
828 |
}
|
|
|
829 |
notrec:
|
|
|
830 |
if (i == countof(ht_functions)) {
|
|
|
831 |
/* Create and write a Function for the spot function. */
|
|
|
832 |
pdf_write_spot_function(pdev, porder, &spot_id);
|
|
|
833 |
}
|
|
|
834 |
*pid = id = pdf_begin_separate(pdev);
|
|
|
835 |
s = pdev->strm;
|
|
|
836 |
/* Use the original, requested frequency and angle. */
|
|
|
837 |
pprintg2(s, "<</Type/Halftone/HalftoneType 1/Frequency %g/Angle %g",
|
|
|
838 |
psht->screen.frequency, psht->screen.angle);
|
|
|
839 |
if (i < countof(ht_functions))
|
|
|
840 |
pprints1(s, "/SpotFunction/%s", ht_functions[i].fname);
|
|
|
841 |
else
|
|
|
842 |
pprintld1(s, "/SpotFunction %ld 0 R", spot_id);
|
|
|
843 |
stream_puts(s, trs);
|
|
|
844 |
if (psht->accurate_screens)
|
|
|
845 |
stream_puts(s, "/AccurateScreens true");
|
|
|
846 |
stream_puts(s, ">>\n");
|
|
|
847 |
return pdf_end_separate(pdev);
|
|
|
848 |
}
|
|
|
849 |
private int
|
|
|
850 |
pdf_write_screen_halftone(gx_device_pdf *pdev, const gs_screen_halftone *psht,
|
|
|
851 |
const gx_ht_order *porder, long *pid)
|
|
|
852 |
{
|
|
|
853 |
gs_spot_halftone spot;
|
|
|
854 |
|
|
|
855 |
spot.screen = *psht;
|
|
|
856 |
spot.accurate_screens = false;
|
|
|
857 |
spot.transfer = 0;
|
|
|
858 |
spot.transfer_closure.proc = 0;
|
|
|
859 |
return pdf_write_spot_halftone(pdev, &spot, porder, pid);
|
|
|
860 |
}
|
|
|
861 |
private int
|
|
|
862 |
pdf_write_colorscreen_halftone(gx_device_pdf *pdev,
|
|
|
863 |
const gs_colorscreen_halftone *pcsht,
|
|
|
864 |
const gx_device_halftone *pdht, long *pid)
|
|
|
865 |
{
|
|
|
866 |
int i;
|
|
|
867 |
stream *s;
|
|
|
868 |
long ht_ids[4];
|
|
|
869 |
|
|
|
870 |
for (i = 0; i < pdht->num_comp ; ++i) {
|
|
|
871 |
int code = pdf_write_screen_halftone(pdev, &pcsht->screens.indexed[i],
|
|
|
872 |
&pdht->components[i].corder,
|
|
|
873 |
&ht_ids[i]);
|
|
|
874 |
if (code < 0)
|
|
|
875 |
return code;
|
|
|
876 |
}
|
|
|
877 |
*pid = pdf_begin_separate(pdev);
|
|
|
878 |
s = pdev->strm;
|
|
|
879 |
/* Use Black, Gray as the Default unless we are in RGB colormodel */
|
|
|
880 |
/* (num_comp < 4) in which case we use Green (arbitrarily) */
|
|
|
881 |
pprintld1(s, "<</Type/Halftone/HalftoneType 5/Default %ld 0 R\n",
|
|
|
882 |
pdht->num_comp > 3 ? ht_ids[3] : ht_ids[1]);
|
|
|
883 |
pprintld2(s, "/Red %ld 0 R/Cyan %ld 0 R", ht_ids[0], ht_ids[0]);
|
|
|
884 |
pprintld2(s, "/Green %ld 0 R/Magenta %ld 0 R", ht_ids[1], ht_ids[1]);
|
|
|
885 |
pprintld2(s, "/Blue %ld 0 R/Yellow %ld 0 R", ht_ids[2], ht_ids[2]);
|
|
|
886 |
if (pdht->num_comp > 3)
|
|
|
887 |
pprintld2(s, "/Gray %ld 0 R/Black %ld 0 R", ht_ids[3], ht_ids[3]);
|
|
|
888 |
stream_puts(s, ">>\n");
|
|
|
889 |
return pdf_end_separate(pdev);
|
|
|
890 |
}
|
|
|
891 |
|
|
|
892 |
#define CHECK(expr)\
|
|
|
893 |
BEGIN if ((code = (expr)) < 0) return code; END
|
|
|
894 |
|
|
|
895 |
private int
|
|
|
896 |
pdf_write_threshold_halftone(gx_device_pdf *pdev,
|
|
|
897 |
const gs_threshold_halftone *ptht,
|
|
|
898 |
const gx_ht_order *porder, long *pid)
|
|
|
899 |
{
|
|
|
900 |
char trs[17 + MAX_FN_CHARS + 1];
|
|
|
901 |
stream *s;
|
|
|
902 |
pdf_data_writer_t writer;
|
|
|
903 |
int code = pdf_write_transfer(pdev, porder->transfer, "",
|
|
|
904 |
trs);
|
|
|
905 |
|
|
|
906 |
if (code < 0)
|
|
|
907 |
return code;
|
|
|
908 |
CHECK(pdf_begin_data(pdev, &writer));
|
|
|
909 |
s = pdev->strm;
|
|
|
910 |
*pid = writer.pres->object->id;
|
|
|
911 |
CHECK(cos_dict_put_c_strings((cos_dict_t *)writer.pres->object,
|
|
|
912 |
"/Type", "/Halftone"));
|
|
|
913 |
CHECK(cos_dict_put_c_strings((cos_dict_t *)writer.pres->object,
|
|
|
914 |
"/HalftoneType", "6"));
|
|
|
915 |
CHECK(cos_dict_put_c_key_int((cos_dict_t *)writer.pres->object,
|
|
|
916 |
"/Width", ptht->width));
|
|
|
917 |
CHECK(cos_dict_put_c_key_int((cos_dict_t *)writer.pres->object,
|
|
|
918 |
"/Height", ptht->height));
|
|
|
919 |
if (*trs != 0)
|
|
|
920 |
CHECK(cos_dict_put_c_strings((cos_dict_t *)writer.pres->object,
|
|
|
921 |
"/TransferFunction", trs));
|
|
|
922 |
stream_write(writer.binary.strm, ptht->thresholds.data, ptht->thresholds.size);
|
|
|
923 |
return pdf_end_data(&writer);
|
|
|
924 |
}
|
|
|
925 |
private int
|
|
|
926 |
pdf_write_threshold2_halftone(gx_device_pdf *pdev,
|
|
|
927 |
const gs_threshold2_halftone *ptht,
|
|
|
928 |
const gx_ht_order *porder, long *pid)
|
|
|
929 |
{
|
|
|
930 |
char trs[17 + MAX_FN_CHARS + 1];
|
|
|
931 |
stream *s;
|
|
|
932 |
pdf_data_writer_t writer;
|
|
|
933 |
int code = pdf_write_transfer(pdev, porder->transfer, "/TransferFunction",
|
|
|
934 |
trs);
|
|
|
935 |
|
|
|
936 |
if (code < 0)
|
|
|
937 |
return code;
|
|
|
938 |
CHECK(pdf_begin_data(pdev, &writer));
|
|
|
939 |
s = pdev->strm;
|
|
|
940 |
*pid = writer.pres->object->id;
|
|
|
941 |
CHECK(cos_dict_put_c_strings((cos_dict_t *)writer.pres->object,
|
|
|
942 |
"/Type", "/Halftone"));
|
|
|
943 |
CHECK(cos_dict_put_c_strings((cos_dict_t *)writer.pres->object,
|
|
|
944 |
"/HalftoneType", "16"));
|
|
|
945 |
CHECK(cos_dict_put_c_key_int((cos_dict_t *)writer.pres->object,
|
|
|
946 |
"/Width", ptht->width));
|
|
|
947 |
CHECK(cos_dict_put_c_key_int((cos_dict_t *)writer.pres->object,
|
|
|
948 |
"/Height", ptht->height));
|
|
|
949 |
if (ptht->width2 && ptht->height2) {
|
|
|
950 |
CHECK(cos_dict_put_c_key_int((cos_dict_t *)writer.pres->object,
|
|
|
951 |
"/Width2", ptht->width2));
|
|
|
952 |
CHECK(cos_dict_put_c_key_int((cos_dict_t *)writer.pres->object,
|
|
|
953 |
"/Height2", ptht->height2));
|
|
|
954 |
}
|
|
|
955 |
if (*trs != 0)
|
|
|
956 |
CHECK(cos_dict_put_c_strings((cos_dict_t *)writer.pres->object,
|
|
|
957 |
"/TransferFunction", trs));
|
|
|
958 |
s = writer.binary.strm;
|
|
|
959 |
if (ptht->bytes_per_sample == 2)
|
|
|
960 |
stream_write(s, ptht->thresholds.data, ptht->thresholds.size);
|
|
|
961 |
else {
|
|
|
962 |
/* Expand 1-byte to 2-byte samples. */
|
|
|
963 |
int i;
|
|
|
964 |
|
|
|
965 |
for (i = 0; i < ptht->thresholds.size; ++i) {
|
|
|
966 |
byte b = ptht->thresholds.data[i];
|
|
|
967 |
|
|
|
968 |
stream_putc(s, b);
|
|
|
969 |
stream_putc(s, b);
|
|
|
970 |
}
|
|
|
971 |
}
|
|
|
972 |
return pdf_end_data(&writer);
|
|
|
973 |
}
|
|
|
974 |
private int
|
|
|
975 |
pdf_get_halftone_component_index(const gs_multiple_halftone *pmht,
|
|
|
976 |
const gx_device_halftone *pdht,
|
|
|
977 |
int dht_index)
|
|
|
978 |
{
|
|
|
979 |
int j;
|
|
|
980 |
|
|
|
981 |
for (j = 0; j < pmht->num_comp; j++)
|
|
|
982 |
if (pmht->components[j].comp_number == dht_index)
|
|
|
983 |
break;
|
|
|
984 |
if (j == pmht->num_comp) {
|
|
|
985 |
/* Look for Default. */
|
|
|
986 |
for (j = 0; j < pmht->num_comp; j++)
|
|
|
987 |
if (pmht->components[j].comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS)
|
|
|
988 |
break;
|
|
|
989 |
if (j == pmht->num_comp)
|
|
|
990 |
return_error(gs_error_undefined);
|
|
|
991 |
}
|
|
|
992 |
return j;
|
|
|
993 |
}
|
|
|
994 |
private int
|
|
|
995 |
pdf_write_multiple_halftone(gx_device_pdf *pdev,
|
|
|
996 |
const gs_multiple_halftone *pmht,
|
|
|
997 |
const gx_device_halftone *pdht, long *pid)
|
|
|
998 |
{
|
|
|
999 |
stream *s;
|
|
|
1000 |
int i, code, last_comp = 0;
|
|
|
1001 |
gs_memory_t *mem = pdev->pdf_memory;
|
|
|
1002 |
long *ids;
|
|
|
1003 |
bool done_Default = false;
|
|
|
1004 |
|
|
|
1005 |
ids = (long *)gs_alloc_byte_array(mem, pmht->num_comp, sizeof(long),
|
|
|
1006 |
"pdf_write_multiple_halftone");
|
|
|
1007 |
if (ids == 0)
|
|
|
1008 |
return_error(gs_error_VMerror);
|
|
|
1009 |
for (i = 0; i < pdht->num_comp; ++i) {
|
|
|
1010 |
const gs_halftone_component *phtc;
|
|
|
1011 |
const gx_ht_order *porder;
|
|
|
1012 |
|
|
|
1013 |
code = pdf_get_halftone_component_index(pmht, pdht, i);
|
|
|
1014 |
if (code < 0)
|
|
|
1015 |
return code;
|
|
|
1016 |
if (pmht->components[code].comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
|
|
|
1017 |
if (done_Default)
|
|
|
1018 |
continue;
|
|
|
1019 |
done_Default = true;
|
|
|
1020 |
}
|
|
|
1021 |
phtc = &pmht->components[code];
|
|
|
1022 |
porder = (pdht->components == 0 ? &pdht->order :
|
|
|
1023 |
&pdht->components[i].corder);
|
|
|
1024 |
switch (phtc->type) {
|
|
|
1025 |
case ht_type_spot:
|
|
|
1026 |
code = pdf_write_spot_halftone(pdev, &phtc->params.spot,
|
|
|
1027 |
porder, &ids[i]);
|
|
|
1028 |
break;
|
|
|
1029 |
case ht_type_threshold:
|
|
|
1030 |
code = pdf_write_threshold_halftone(pdev, &phtc->params.threshold,
|
|
|
1031 |
porder, &ids[i]);
|
|
|
1032 |
break;
|
|
|
1033 |
case ht_type_threshold2:
|
|
|
1034 |
code = pdf_write_threshold2_halftone(pdev,
|
|
|
1035 |
&phtc->params.threshold2,
|
|
|
1036 |
porder, &ids[i]);
|
|
|
1037 |
break;
|
|
|
1038 |
default:
|
|
|
1039 |
code = gs_note_error(gs_error_rangecheck);
|
|
|
1040 |
}
|
|
|
1041 |
if (code < 0) {
|
|
|
1042 |
gs_free_object(mem, ids, "pdf_write_multiple_halftone");
|
|
|
1043 |
return code;
|
|
|
1044 |
}
|
|
|
1045 |
}
|
|
|
1046 |
*pid = pdf_begin_separate(pdev);
|
|
|
1047 |
s = pdev->strm;
|
|
|
1048 |
stream_puts(s, "<</Type/Halftone/HalftoneType 5\n");
|
|
|
1049 |
done_Default = false;
|
|
|
1050 |
for (i = 0; i < pdht->num_comp; ++i) {
|
|
|
1051 |
const gs_halftone_component *phtc;
|
|
|
1052 |
byte *str;
|
|
|
1053 |
uint len;
|
|
|
1054 |
cos_value_t value;
|
|
|
1055 |
|
|
|
1056 |
code = pdf_get_halftone_component_index(pmht, pdht, i);
|
|
|
1057 |
if (code < 0)
|
|
|
1058 |
return code;
|
|
|
1059 |
if (pmht->components[code].comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
|
|
|
1060 |
if (done_Default)
|
|
|
1061 |
continue;
|
|
|
1062 |
done_Default = true;
|
|
|
1063 |
}
|
|
|
1064 |
phtc = &pmht->components[code];
|
|
|
1065 |
if ((code = pmht->get_colorname_string(pdev->memory, phtc->cname, &str, &len)) < 0 ||
|
|
|
1066 |
(code = pdf_string_to_cos_name(pdev, str, len, &value)) < 0)
|
|
|
1067 |
return code;
|
|
|
1068 |
cos_value_write(&value, pdev);
|
|
|
1069 |
gs_free_string(mem, value.contents.chars.data,
|
|
|
1070 |
value.contents.chars.size,
|
|
|
1071 |
"pdf_write_multiple_halftone");
|
|
|
1072 |
pprintld1(s, " %ld 0 R\n", ids[i]);
|
|
|
1073 |
last_comp = i;
|
|
|
1074 |
}
|
|
|
1075 |
if (!done_Default) {
|
|
|
1076 |
/*
|
|
|
1077 |
* BOGUS: Type 5 halftones must contain Default component.
|
|
|
1078 |
* Perhaps we have no way to obtain it,
|
|
|
1079 |
* because pdht contains ProcessColorModel components only.
|
|
|
1080 |
* We copy the last component as Default one.
|
|
|
1081 |
*/
|
|
|
1082 |
pprintld1(s, " /Default %ld 0 R\n", ids[last_comp]);
|
|
|
1083 |
}
|
|
|
1084 |
stream_puts(s, ">>\n");
|
|
|
1085 |
gs_free_object(mem, ids, "pdf_write_multiple_halftone");
|
|
|
1086 |
return pdf_end_separate(pdev);
|
|
|
1087 |
}
|
|
|
1088 |
|
|
|
1089 |
/*
|
|
|
1090 |
* Update the halftone. This is a separate procedure only for
|
|
|
1091 |
* readability.
|
|
|
1092 |
*/
|
|
|
1093 |
private int
|
|
|
1094 |
pdf_update_halftone(gx_device_pdf *pdev, const gs_imager_state *pis,
|
|
|
1095 |
char *hts)
|
|
|
1096 |
{
|
|
|
1097 |
const gs_halftone *pht = pis->halftone;
|
|
|
1098 |
const gx_device_halftone *pdht = pis->dev_ht;
|
|
|
1099 |
int code;
|
|
|
1100 |
long id;
|
|
|
1101 |
|
|
|
1102 |
switch (pht->type) {
|
|
|
1103 |
case ht_type_screen:
|
|
|
1104 |
code = pdf_write_screen_halftone(pdev, &pht->params.screen,
|
|
|
1105 |
&pdht->components[0].corder, &id);
|
|
|
1106 |
break;
|
|
|
1107 |
case ht_type_colorscreen:
|
|
|
1108 |
code = pdf_write_colorscreen_halftone(pdev, &pht->params.colorscreen,
|
|
|
1109 |
pdht, &id);
|
|
|
1110 |
break;
|
|
|
1111 |
case ht_type_spot:
|
|
|
1112 |
code = pdf_write_spot_halftone(pdev, &pht->params.spot,
|
|
|
1113 |
&pdht->components[0].corder, &id);
|
|
|
1114 |
break;
|
|
|
1115 |
case ht_type_threshold:
|
|
|
1116 |
code = pdf_write_threshold_halftone(pdev, &pht->params.threshold,
|
|
|
1117 |
&pdht->components[0].corder, &id);
|
|
|
1118 |
break;
|
|
|
1119 |
case ht_type_threshold2:
|
|
|
1120 |
code = pdf_write_threshold2_halftone(pdev, &pht->params.threshold2,
|
|
|
1121 |
&pdht->components[0].corder, &id);
|
|
|
1122 |
break;
|
|
|
1123 |
case ht_type_multiple:
|
|
|
1124 |
case ht_type_multiple_colorscreen:
|
|
|
1125 |
code = pdf_write_multiple_halftone(pdev, &pht->params.multiple,
|
|
|
1126 |
pdht, &id);
|
|
|
1127 |
break;
|
|
|
1128 |
default:
|
|
|
1129 |
return_error(gs_error_rangecheck);
|
|
|
1130 |
}
|
|
|
1131 |
if (code < 0)
|
|
|
1132 |
return code;
|
|
|
1133 |
sprintf(hts, "%ld 0 R", id);
|
|
|
1134 |
pdev->halftone_id = pis->dev_ht->id;
|
|
|
1135 |
return code;
|
|
|
1136 |
}
|
|
|
1137 |
|
|
|
1138 |
/* ------ Graphics state updating ------ */
|
|
|
1139 |
|
|
|
1140 |
private inline cos_dict_t *
|
|
|
1141 |
resource_dict(pdf_resource_t *pres)
|
|
|
1142 |
{
|
|
|
1143 |
return (cos_dict_t *)pres->object;
|
|
|
1144 |
}
|
|
|
1145 |
|
|
|
1146 |
/* Open an ExtGState. */
|
|
|
1147 |
private int
|
|
|
1148 |
pdf_open_gstate(gx_device_pdf *pdev, pdf_resource_t **ppres)
|
|
|
1149 |
{
|
|
|
1150 |
int code;
|
|
|
1151 |
|
|
|
1152 |
if (*ppres)
|
|
|
1153 |
return 0;
|
|
|
1154 |
/*
|
|
|
1155 |
* We write gs command only in stream context.
|
|
|
1156 |
* If we are clipped, and the clip path is about to change,
|
|
|
1157 |
* the old clipping must be undone before writing gs.
|
|
|
1158 |
*/
|
|
|
1159 |
if (pdev->context != PDF_IN_STREAM) {
|
|
|
1160 |
/* We apparently use gs_error_interrupt as a request to change context. */
|
|
|
1161 |
return gs_error_interrupt;
|
|
|
1162 |
}
|
|
|
1163 |
code = pdf_alloc_resource(pdev, resourceExtGState, gs_no_id, ppres, -1L);
|
|
|
1164 |
if (code < 0)
|
|
|
1165 |
return code;
|
|
|
1166 |
cos_become((*ppres)->object, cos_type_dict);
|
|
|
1167 |
code = cos_dict_put_c_key_string(resource_dict(*ppres), "/Type", (const byte *)"/ExtGState", 10);
|
|
|
1168 |
if (code < 0)
|
|
|
1169 |
return code;
|
|
|
1170 |
return 0;
|
|
|
1171 |
}
|
|
|
1172 |
|
|
|
1173 |
/* Finish writing an ExtGState. */
|
|
|
1174 |
int
|
|
|
1175 |
pdf_end_gstate(gx_device_pdf *pdev, pdf_resource_t *pres)
|
|
|
1176 |
{
|
|
|
1177 |
if (pres) {
|
|
|
1178 |
int code = pdf_substitute_resource(pdev, &pres, resourceExtGState, NULL, true);
|
|
|
1179 |
|
|
|
1180 |
if (code < 0)
|
|
|
1181 |
return code;
|
|
|
1182 |
code = pdf_open_page(pdev, PDF_IN_STREAM);
|
|
|
1183 |
if (code < 0)
|
|
|
1184 |
return code;
|
|
|
1185 |
code = pdf_add_resource(pdev, pdev->substream_Resources, "/ExtGState", pres);
|
|
|
1186 |
if (code < 0)
|
|
|
1187 |
return code;
|
|
|
1188 |
pprintld1(pdev->strm, "/R%ld gs\n", pdf_resource_id(pres));
|
|
|
1189 |
pres->where_used |= pdev->used_mask;
|
|
|
1190 |
}
|
|
|
1191 |
return 0;
|
|
|
1192 |
}
|
|
|
1193 |
|
|
|
1194 |
/*
|
|
|
1195 |
* Update the transfer functions(s). This is a separate procedure only
|
|
|
1196 |
* for readability.
|
|
|
1197 |
*/
|
|
|
1198 |
private int
|
|
|
1199 |
pdf_update_transfer(gx_device_pdf *pdev, const gs_imager_state *pis,
|
|
|
1200 |
char *trs)
|
|
|
1201 |
{
|
|
|
1202 |
int i, pi = -1;
|
|
|
1203 |
bool multiple = false, update = false;
|
|
|
1204 |
gs_id transfer_ids[4];
|
|
|
1205 |
int code = 0;
|
|
|
1206 |
const gx_transfer_map *tm[4];
|
|
|
1207 |
|
|
|
1208 |
tm[0] = pis->set_transfer.red;
|
|
|
1209 |
tm[1] = pis->set_transfer.green;
|
|
|
1210 |
tm[2] = pis->set_transfer.blue;
|
|
|
1211 |
tm[3] = pis->set_transfer.gray;
|
|
|
1212 |
for (i = 0; i < 4; ++i)
|
|
|
1213 |
if (tm[i] != NULL) {
|
|
|
1214 |
transfer_ids[i] = tm[i]->id;
|
|
|
1215 |
if (pdev->transfer_ids[i] != tm[i]->id)
|
|
|
1216 |
update = true;
|
|
|
1217 |
if (pi != -1 && transfer_ids[i] != transfer_ids[pi])
|
|
|
1218 |
multiple = true;
|
|
|
1219 |
pi = i;
|
|
|
1220 |
} else
|
|
|
1221 |
transfer_ids[i] = -1;
|
|
|
1222 |
if (update) {
|
|
|
1223 |
int mask;
|
|
|
1224 |
|
|
|
1225 |
if (!multiple) {
|
|
|
1226 |
code = pdf_write_transfer(pdev, tm[pi], "", trs);
|
|
|
1227 |
if (code < 0)
|
|
|
1228 |
return code;
|
|
|
1229 |
mask = code == 0;
|
|
|
1230 |
} else {
|
|
|
1231 |
strcpy(trs, "[");
|
|
|
1232 |
mask = 0;
|
|
|
1233 |
for (i = 0; i < 4; ++i)
|
|
|
1234 |
if (tm[i] != NULL) {
|
|
|
1235 |
code = pdf_write_transfer_map(pdev,
|
|
|
1236 |
tm[i],
|
|
|
1237 |
0, true, " ", trs + strlen(trs));
|
|
|
1238 |
if (code < 0)
|
|
|
1239 |
return code;
|
|
|
1240 |
mask |= (code == 0) << i;
|
|
|
1241 |
}
|
|
|
1242 |
strcat(trs, "]");
|
|
|
1243 |
}
|
|
|
1244 |
memcpy(pdev->transfer_ids, transfer_ids, sizeof(pdev->transfer_ids));
|
|
|
1245 |
pdev->transfer_not_identity = mask;
|
|
|
1246 |
}
|
|
|
1247 |
return code;
|
|
|
1248 |
}
|
|
|
1249 |
|
|
|
1250 |
/*
|
|
|
1251 |
* Update the current alpha if necessary. Note that because Ghostscript
|
|
|
1252 |
* stores separate opacity and shape alpha, a rangecheck will occur if
|
|
|
1253 |
* both are different from the current setting.
|
|
|
1254 |
*/
|
|
|
1255 |
private int
|
|
|
1256 |
pdf_update_alpha(gx_device_pdf *pdev, const gs_imager_state *pis,
|
|
|
1257 |
pdf_resource_t **ppres)
|
|
|
1258 |
{
|
|
|
1259 |
bool ais;
|
|
|
1260 |
floatp alpha;
|
|
|
1261 |
int code;
|
|
|
1262 |
|
|
|
1263 |
if (pdev->state.soft_mask_id != pis->soft_mask_id) {
|
|
|
1264 |
char buf[20];
|
|
|
1265 |
|
|
|
1266 |
sprintf(buf, "%ld 0 R", pis->soft_mask_id);
|
|
|
1267 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1268 |
if (code < 0)
|
|
|
1269 |
return code;
|
|
|
1270 |
code = cos_dict_put_c_key_string(resource_dict(*ppres),
|
|
|
1271 |
"/SMask", (byte *)buf, strlen(buf));
|
|
|
1272 |
if (code < 0)
|
|
|
1273 |
return code;
|
|
|
1274 |
pdev->state.soft_mask_id = pis->soft_mask_id;
|
|
|
1275 |
}
|
|
|
1276 |
if (pdev->state.opacity.alpha != pis->opacity.alpha) {
|
|
|
1277 |
if (pdev->state.shape.alpha != pis->shape.alpha)
|
|
|
1278 |
return_error(gs_error_rangecheck);
|
|
|
1279 |
ais = false;
|
|
|
1280 |
alpha = pdev->state.opacity.alpha = pis->opacity.alpha;
|
|
|
1281 |
} else if (pdev->state.shape.alpha != pis->shape.alpha) {
|
|
|
1282 |
ais = true;
|
|
|
1283 |
alpha = pdev->state.shape.alpha = pis->shape.alpha;
|
|
|
1284 |
} else
|
|
|
1285 |
return 0;
|
|
|
1286 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1287 |
if (code < 0)
|
|
|
1288 |
return code;
|
|
|
1289 |
code = cos_dict_put_c_key_bool(resource_dict(*ppres), "/AIS", ais);
|
|
|
1290 |
if (code < 0)
|
|
|
1291 |
return code;
|
|
|
1292 |
/* we never do the 'both' operations (b, B, b*, B*) so we set both */
|
|
|
1293 |
/* CA and ca the same so that we stay in sync with state.*.alpha */
|
|
|
1294 |
code = cos_dict_put_c_key_real(resource_dict(*ppres), "/CA", alpha);
|
|
|
1295 |
if (code < 0)
|
|
|
1296 |
return code;
|
|
|
1297 |
return cos_dict_put_c_key_real(resource_dict(*ppres), "/ca", alpha);
|
|
|
1298 |
}
|
|
|
1299 |
|
|
|
1300 |
/*
|
|
|
1301 |
* Update the graphics subset common to all high-level drawing operations.
|
|
|
1302 |
*/
|
|
|
1303 |
int
|
|
|
1304 |
pdf_prepare_drawing(gx_device_pdf *pdev, const gs_imager_state *pis,
|
|
|
1305 |
pdf_resource_t **ppres)
|
|
|
1306 |
{
|
|
|
1307 |
int code = 0;
|
|
|
1308 |
int bottom;
|
|
|
1309 |
|
|
|
1310 |
if (pdev->CompatibilityLevel >= 1.4) {
|
|
|
1311 |
if (pdev->state.blend_mode != pis->blend_mode) {
|
|
|
1312 |
static const char *const bm_names[] = { GS_BLEND_MODE_NAMES };
|
|
|
1313 |
char buf[20];
|
|
|
1314 |
|
|
|
1315 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1316 |
if (code < 0)
|
|
|
1317 |
return code;
|
|
|
1318 |
buf[0] = '/';
|
|
|
1319 |
strncpy(buf + 1, bm_names[pis->blend_mode], sizeof(buf) - 2);
|
|
|
1320 |
code = cos_dict_put_string_copy(resource_dict(*ppres), "/BM", buf);
|
|
|
1321 |
if (code < 0)
|
|
|
1322 |
return code;
|
|
|
1323 |
pdev->state.blend_mode = pis->blend_mode;
|
|
|
1324 |
}
|
|
|
1325 |
code = pdf_update_alpha(pdev, pis, ppres);
|
|
|
1326 |
if (code < 0)
|
|
|
1327 |
return code;
|
|
|
1328 |
} else {
|
|
|
1329 |
/*
|
|
|
1330 |
* If the graphics state calls for any transparency functions,
|
|
|
1331 |
* we can't represent them, so return a rangecheck.
|
|
|
1332 |
*/
|
|
|
1333 |
if (pis->opacity.alpha != 1 || pis->opacity.mask != 0 ||
|
|
|
1334 |
pis->shape.alpha != 1 || pis->shape.mask != 0 ||
|
|
|
1335 |
pis->transparency_stack != 0
|
|
|
1336 |
)
|
|
|
1337 |
return_error(gs_error_rangecheck);
|
|
|
1338 |
}
|
|
|
1339 |
/*
|
|
|
1340 |
* We originally thought the remaining items were only needed for
|
|
|
1341 |
* fill and stroke, but in fact they are needed for images as well.
|
|
|
1342 |
*/
|
|
|
1343 |
/*
|
|
|
1344 |
* Update halftone, transfer function, black generation, undercolor
|
|
|
1345 |
* removal, halftone phase, overprint mode, smoothness, blend mode, text
|
|
|
1346 |
* knockout.
|
|
|
1347 |
*/
|
|
|
1348 |
bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
|
|
|
1349 |
/* When ResourcesBeforeUsage != 0, one sbstack element
|
|
|
1350 |
appears from the page contents stream. */
|
|
|
1351 |
if (pdev->sbstack_depth == bottom) {
|
|
|
1352 |
gs_int_point phase, dev_phase;
|
|
|
1353 |
char hts[5 + MAX_FN_CHARS + 1],
|
|
|
1354 |
trs[5 + MAX_FN_CHARS * 4 + 6 + 1],
|
|
|
1355 |
bgs[5 + MAX_FN_CHARS + 1],
|
|
|
1356 |
ucrs[6 + MAX_FN_CHARS + 1];
|
|
|
1357 |
|
|
|
1358 |
hts[0] = trs[0] = bgs[0] = ucrs[0] = 0;
|
|
|
1359 |
if (pdev->params.PreserveHalftoneInfo &&
|
|
|
1360 |
pdev->halftone_id != pis->dev_ht->id &&
|
|
|
1361 |
!pdev->PDFX
|
|
|
1362 |
) {
|
|
|
1363 |
code = pdf_update_halftone(pdev, pis, hts);
|
|
|
1364 |
if (code < 0)
|
|
|
1365 |
return code;
|
|
|
1366 |
}
|
|
|
1367 |
if (pdev->params.TransferFunctionInfo == tfi_Preserve &&
|
|
|
1368 |
!pdev->PDFX
|
|
|
1369 |
) {
|
|
|
1370 |
code = pdf_update_transfer(pdev, pis, trs);
|
|
|
1371 |
if (code < 0)
|
|
|
1372 |
return code;
|
|
|
1373 |
}
|
|
|
1374 |
if (pdev->params.UCRandBGInfo == ucrbg_Preserve) {
|
|
|
1375 |
if (pdev->black_generation_id != pis->black_generation->id) {
|
|
|
1376 |
code = pdf_write_transfer_map(pdev, pis->black_generation,
|
|
|
1377 |
0, false, "", bgs);
|
|
|
1378 |
if (code < 0)
|
|
|
1379 |
return code;
|
|
|
1380 |
pdev->black_generation_id = pis->black_generation->id;
|
|
|
1381 |
}
|
|
|
1382 |
if (pdev->undercolor_removal_id != pis->undercolor_removal->id) {
|
|
|
1383 |
code = pdf_write_transfer_map(pdev, pis->undercolor_removal,
|
|
|
1384 |
-1, false, "", ucrs);
|
|
|
1385 |
if (code < 0)
|
|
|
1386 |
return code;
|
|
|
1387 |
pdev->undercolor_removal_id = pis->undercolor_removal->id;
|
|
|
1388 |
}
|
|
|
1389 |
}
|
|
|
1390 |
if (hts[0] || trs[0] || bgs[0] || ucrs[0]) {
|
|
|
1391 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1392 |
if (code < 0)
|
|
|
1393 |
return code;
|
|
|
1394 |
}
|
|
|
1395 |
if (hts[0]) {
|
|
|
1396 |
code = cos_dict_put_string_copy(resource_dict(*ppres), "/HT", hts);
|
|
|
1397 |
if (code < 0)
|
|
|
1398 |
return code;
|
|
|
1399 |
}
|
|
|
1400 |
if (trs[0]) {
|
|
|
1401 |
code = cos_dict_put_string_copy(resource_dict(*ppres), "/TR", trs);
|
|
|
1402 |
if (code < 0)
|
|
|
1403 |
return code;
|
|
|
1404 |
}
|
|
|
1405 |
if (bgs[0]) {
|
|
|
1406 |
code = cos_dict_put_string_copy(resource_dict(*ppres), "/BG", bgs);
|
|
|
1407 |
if (code < 0)
|
|
|
1408 |
return code;
|
|
|
1409 |
}
|
|
|
1410 |
if (ucrs[0]) {
|
|
|
1411 |
code = cos_dict_put_string_copy(resource_dict(*ppres), "/UCR", ucrs);
|
|
|
1412 |
if (code < 0)
|
|
|
1413 |
return code;
|
|
|
1414 |
}
|
|
|
1415 |
if (!pdev->PDFX) {
|
|
|
1416 |
gs_currentscreenphase_pis(pis, &phase, 0);
|
|
|
1417 |
gs_currentscreenphase_pis(&pdev->state, &dev_phase, 0);
|
|
|
1418 |
if (dev_phase.x != phase.x || dev_phase.y != phase.y) {
|
|
|
1419 |
char buf[sizeof(int) * 3 + 5];
|
|
|
1420 |
|
|
|
1421 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1422 |
if (code < 0)
|
|
|
1423 |
return code;
|
|
|
1424 |
sprintf(buf, "[%d %d]", phase.x, phase.y);
|
|
|
1425 |
code = cos_dict_put_string_copy(resource_dict(*ppres), "/HTP", buf);
|
|
|
1426 |
if (code < 0)
|
|
|
1427 |
return code;
|
|
|
1428 |
gx_imager_setscreenphase(&pdev->state, phase.x, phase.y,
|
|
|
1429 |
gs_color_select_all);
|
|
|
1430 |
}
|
|
|
1431 |
}
|
|
|
1432 |
}
|
|
|
1433 |
if (pdev->CompatibilityLevel >= 1.3 && pdev->sbstack_depth == bottom) {
|
|
|
1434 |
if (pdev->overprint_mode != pdev->params.OPM) {
|
|
|
1435 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1436 |
if (code < 0)
|
|
|
1437 |
return code;
|
|
|
1438 |
code = cos_dict_put_c_key_int(resource_dict(*ppres), "/OPM", pdev->params.OPM);
|
|
|
1439 |
if (code < 0)
|
|
|
1440 |
return code;
|
|
|
1441 |
pdev->overprint_mode = pdev->params.OPM;
|
|
|
1442 |
}
|
|
|
1443 |
if (pdev->state.smoothness != pis->smoothness) {
|
|
|
1444 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1445 |
if (code < 0)
|
|
|
1446 |
return code;
|
|
|
1447 |
code = cos_dict_put_c_key_real(resource_dict(*ppres), "/SM", pis->smoothness);
|
|
|
1448 |
if (code < 0)
|
|
|
1449 |
return code;
|
|
|
1450 |
pdev->state.smoothness = pis->smoothness;
|
|
|
1451 |
}
|
|
|
1452 |
if (pdev->CompatibilityLevel >= 1.4) {
|
|
|
1453 |
if (pdev->state.text_knockout != pis->text_knockout) {
|
|
|
1454 |
code = pdf_open_gstate(pdev, ppres);
|
|
|
1455 |
if (code < 0)
|
|
|
1456 |
return code;
|
|
|
1457 |
code = cos_dict_put_c_key_bool(resource_dict(*ppres), "/TK", pis->text_knockout);
|
|
|
1458 |
if (code < 0)
|
|
|
1459 |
return code;
|
|
|
1460 |
pdev->state.text_knockout = pis->text_knockout;
|
|
|
1461 |
}
|
|
|
1462 |
}
|
|
|
1463 |
}
|
|
|
1464 |
return code;
|
|
|
1465 |
}
|
|
|
1466 |
|
|
|
1467 |
/* Update the graphics state for filling. */
|
|
|
1468 |
int
|
|
|
1469 |
pdf_try_prepare_fill(gx_device_pdf *pdev, const gs_imager_state *pis)
|
|
|
1470 |
{
|
|
|
1471 |
pdf_resource_t *pres = 0;
|
|
|
1472 |
int code = pdf_prepare_drawing(pdev, pis, &pres);
|
|
|
1473 |
|
|
|
1474 |
if (code < 0)
|
|
|
1475 |
return code;
|
|
|
1476 |
/* Update overprint. */
|
|
|
1477 |
if (pdev->params.PreserveOverprintSettings &&
|
|
|
1478 |
pdev->fill_overprint != pis->overprint &&
|
|
|
1479 |
!pdev->skip_colors
|
|
|
1480 |
) {
|
|
|
1481 |
code = pdf_open_gstate(pdev, &pres);
|
|
|
1482 |
if (code < 0)
|
|
|
1483 |
return code;
|
|
|
1484 |
/* PDF 1.2 only has a single overprint setting. */
|
|
|
1485 |
if (pdev->CompatibilityLevel < 1.3) {
|
|
|
1486 |
code = cos_dict_put_c_key_bool(resource_dict(pres), "/OP", pis->overprint);
|
|
|
1487 |
if (code < 0)
|
|
|
1488 |
return code;
|
|
|
1489 |
pdev->stroke_overprint = pis->overprint;
|
|
|
1490 |
} else {
|
|
|
1491 |
code = cos_dict_put_c_key_bool(resource_dict(pres), "/op", pis->overprint);
|
|
|
1492 |
if (code < 0)
|
|
|
1493 |
return code;
|
|
|
1494 |
}
|
|
|
1495 |
pdev->fill_overprint = pis->overprint;
|
|
|
1496 |
}
|
|
|
1497 |
return pdf_end_gstate(pdev, pres);
|
|
|
1498 |
}
|
|
|
1499 |
int
|
|
|
1500 |
pdf_prepare_fill(gx_device_pdf *pdev, const gs_imager_state *pis)
|
|
|
1501 |
{
|
|
|
1502 |
int code;
|
|
|
1503 |
|
|
|
1504 |
if (pdev->context != PDF_IN_STREAM) {
|
|
|
1505 |
code = pdf_try_prepare_fill(pdev, pis);
|
|
|
1506 |
if (code != gs_error_interrupt) /* See pdf_open_gstate */
|
|
|
1507 |
return code;
|
|
|
1508 |
code = pdf_open_contents(pdev, PDF_IN_STREAM);
|
|
|
1509 |
if (code < 0)
|
|
|
1510 |
return code;
|
|
|
1511 |
}
|
|
|
1512 |
return pdf_try_prepare_fill(pdev, pis);
|
|
|
1513 |
}
|
|
|
1514 |
|
|
|
1515 |
/* Update the graphics state for stroking. */
|
|
|
1516 |
private int
|
|
|
1517 |
pdf_try_prepare_stroke(gx_device_pdf *pdev, const gs_imager_state *pis)
|
|
|
1518 |
{
|
|
|
1519 |
pdf_resource_t *pres = 0;
|
|
|
1520 |
int code = pdf_prepare_drawing(pdev, pis, &pres);
|
|
|
1521 |
|
|
|
1522 |
if (code < 0)
|
|
|
1523 |
return code;
|
|
|
1524 |
/* Update overprint, stroke adjustment. */
|
|
|
1525 |
if (pdev->params.PreserveOverprintSettings &&
|
|
|
1526 |
pdev->stroke_overprint != pis->overprint &&
|
|
|
1527 |
!pdev->skip_colors
|
|
|
1528 |
) {
|
|
|
1529 |
code = pdf_open_gstate(pdev, &pres);
|
|
|
1530 |
if (code < 0)
|
|
|
1531 |
return code;
|
|
|
1532 |
code = cos_dict_put_c_key_bool(resource_dict(pres), "/OP", pis->overprint);
|
|
|
1533 |
if (code < 0)
|
|
|
1534 |
return code;
|
|
|
1535 |
pdev->stroke_overprint = pis->overprint;
|
|
|
1536 |
if (pdev->CompatibilityLevel < 1.3) {
|
|
|
1537 |
/* PDF 1.2 only has a single overprint setting. */
|
|
|
1538 |
pdev->fill_overprint = pis->overprint;
|
|
|
1539 |
} else {
|
|
|
1540 |
/* According to PDF>=1.3 spec, OP also sets op,
|
|
|
1541 |
if there is no /op in same garphic state object.
|
|
|
1542 |
We don't write /op, so monitor the viewer's state here : */
|
|
|
1543 |
pdev->fill_overprint = pis->overprint;
|
|
|
1544 |
}
|
|
|
1545 |
}
|
|
|
1546 |
if (pdev->state.stroke_adjust != pis->stroke_adjust) {
|
|
|
1547 |
code = pdf_open_gstate(pdev, &pres);
|
|
|
1548 |
if (code < 0)
|
|
|
1549 |
return code;
|
|
|
1550 |
code = cos_dict_put_c_key_bool(resource_dict(pres), "/SA", pis->stroke_adjust);
|
|
|
1551 |
if (code < 0)
|
|
|
1552 |
return code;
|
|
|
1553 |
pdev->state.stroke_adjust = pis->stroke_adjust;
|
|
|
1554 |
}
|
|
|
1555 |
return pdf_end_gstate(pdev, pres);
|
|
|
1556 |
}
|
|
|
1557 |
int
|
|
|
1558 |
pdf_prepare_stroke(gx_device_pdf *pdev, const gs_imager_state *pis)
|
|
|
1559 |
{
|
|
|
1560 |
int code;
|
|
|
1561 |
|
|
|
1562 |
if (pdev->context != PDF_IN_STREAM) {
|
|
|
1563 |
code = pdf_try_prepare_stroke(pdev, pis);
|
|
|
1564 |
if (code != gs_error_interrupt) /* See pdf_open_gstate */
|
|
|
1565 |
return code;
|
|
|
1566 |
code = pdf_open_contents(pdev, PDF_IN_STREAM);
|
|
|
1567 |
if (code < 0)
|
|
|
1568 |
return code;
|
|
|
1569 |
}
|
|
|
1570 |
return pdf_try_prepare_stroke(pdev, pis);
|
|
|
1571 |
}
|
|
|
1572 |
|
|
|
1573 |
/* Update the graphics state for an image other than an ImageType 1 mask. */
|
|
|
1574 |
int
|
|
|
1575 |
pdf_prepare_image(gx_device_pdf *pdev, const gs_imager_state *pis)
|
|
|
1576 |
{
|
|
|
1577 |
/*
|
|
|
1578 |
* As it turns out, this requires updating the same parameters as for
|
|
|
1579 |
* filling.
|
|
|
1580 |
*/
|
|
|
1581 |
return pdf_prepare_fill(pdev, pis);
|
|
|
1582 |
}
|
|
|
1583 |
|
|
|
1584 |
/* Update the graphics state for an ImageType 1 mask. */
|
|
|
1585 |
int
|
|
|
1586 |
pdf_prepare_imagemask(gx_device_pdf *pdev, const gs_imager_state *pis,
|
|
|
1587 |
const gx_drawing_color *pdcolor)
|
|
|
1588 |
{
|
|
|
1589 |
int code = pdf_prepare_image(pdev, pis);
|
|
|
1590 |
|
|
|
1591 |
if (code < 0)
|
|
|
1592 |
return code;
|
|
|
1593 |
return pdf_set_drawing_color(pdev, pis, pdcolor, &pdev->saved_fill_color,
|
|
|
1594 |
&pdev->fill_used_process_color,
|
|
|
1595 |
&psdf_set_fill_color_commands);
|
|
|
1596 |
}
|
|
|
1597 |
|