1 /* Copyright (C) 2001-2006 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, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: gdevpdfp.c 10141 2009-10-06 07:33:33Z ken $ */
15 /* Get/put parameters for PDF-writing driver */
16 #include "memory_.h"
17 #include "gx.h"
18 #include "gserrors.h"
19 #include "gdevpdfx.h"
20 #include "gdevpdfo.h"
21 #include "gdevpdfg.h"
22 #include "gsparamx.h"
23
24 /*
25 * The pdfwrite device supports the following "real" parameters:
26 * OutputFile <string>
27 * all the Distiller parameters (also see gdevpsdp.c)
28 * Only some of the Distiller parameters actually have any effect.
29 *
30 * The device also supports the following write-only pseudo-parameters that
31 * serve only to communicate other information from the PostScript file.
32 * Their "value" is an array of strings, some of which may be the result
33 * of converting arbitrary PostScript objects to string form.
34 * pdfmark - see gdevpdfm.c
35 * DSC - processed in this file
36 */
37 static int pdf_dsc_process(gx_device_pdf * pdev,
38 const gs_param_string_array * pma);
39
40 static const int CoreDistVersion = 5000; /* Distiller 5.0 */
41 static const gs_param_item_t pdf_param_items[] = {
42 #define pi(key, type, memb) { key, type, offset_of(gx_device_pdf, memb) }
43
44 /* Acrobat Distiller 4 parameters */
45
46 /*
47 * EndPage and StartPage are renamed because EndPage collides with
48 * a page device parameter.
49 */
50 pi("PDFEndPage", gs_param_type_int, EndPage),
51 pi("PDFStartPage", gs_param_type_int, StartPage),
52 pi("Optimize", gs_param_type_bool, Optimize),
53 pi("ParseDSCCommentsForDocInfo", gs_param_type_bool,
54 ParseDSCCommentsForDocInfo),
55 pi("ParseDSCComments", gs_param_type_bool, ParseDSCComments),
56 pi("EmitDSCWarnings", gs_param_type_bool, EmitDSCWarnings),
57 pi("CreateJobTicket", gs_param_type_bool, CreateJobTicket),
58 pi("PreserveEPSInfo", gs_param_type_bool, PreserveEPSInfo),
59 pi("AutoPositionEPSFiles", gs_param_type_bool, AutoPositionEPSFiles),
60 pi("PreserveCopyPage", gs_param_type_bool, PreserveCopyPage),
61 pi("UsePrologue", gs_param_type_bool, UsePrologue),
62
63 /* Acrobat Distiller 5 parameters */
64
65 pi("OffOptimizations", gs_param_type_int, OffOptimizations),
66
67 /* Ghostscript-specific parameters */
68
69 pi("ReAssignCharacters", gs_param_type_bool, ReAssignCharacters),
70 pi("ReEncodeCharacters", gs_param_type_bool, ReEncodeCharacters),
71 pi("FirstObjectNumber", gs_param_type_long, FirstObjectNumber),
72 pi("CompressFonts", gs_param_type_bool, CompressFonts),
73 pi("PrintStatistics", gs_param_type_bool, PrintStatistics),
74 pi("MaxInlineImageSize", gs_param_type_long, MaxInlineImageSize),
75 pi("DSCEncodingToUnicode", gs_param_type_int_array, DSCEncodingToUnicode),
76
77 /* PDF Encryption */
78 pi("OwnerPassword", gs_param_type_string, OwnerPassword),
79 pi("UserPassword", gs_param_type_string, UserPassword),
80 pi("KeyLength", gs_param_type_int, KeyLength),
81 pi("Permissions", gs_param_type_int, Permissions),
82 pi("EncryptionR", gs_param_type_int, EncryptionR),
83 pi("NoEncrypt", gs_param_type_string, NoEncrypt),
84
85 /* Target viewer capabilities (Ghostscript-specific) */
86 /* pi("ForOPDFRead", gs_param_type_bool, ForOPDFRead), pdfwrite-only */
87 pi("PatternImagemask", gs_param_type_bool, PatternImagemask),
88 pi("MaxClipPathSize", gs_param_type_int, MaxClipPathSize),
89 pi("MaxShadingBitmapSize", gs_param_type_int, MaxShadingBitmapSize),
90 pi("MaxViewerMemorySize", gs_param_type_int, MaxViewerMemorySize),
91 pi("HaveTrueTypes", gs_param_type_bool, HaveTrueTypes),
92 pi("HaveCIDSystem", gs_param_type_bool, HaveCIDSystem),
93 pi("HaveTransparency", gs_param_type_bool, HaveTransparency),
94 /* pi("OPDFReadProcsetPath", gs_param_type_string, OPDFReadProcsetPath), ps2write-only */
95 pi("CompressEntireFile", gs_param_type_bool, CompressEntireFile),
96 pi("PDFX", gs_param_type_bool, PDFX),
97 pi("PDFA", gs_param_type_bool, PDFA),
98 pi("DocumentUUID", gs_param_type_string, DocumentUUID),
99 pi("InstanceUUID", gs_param_type_string, InstanceUUID),
100 pi("DocumentTimeSeq", gs_param_type_int, DocumentTimeSeq),
101
102 /* PDF/X parameters */
103 pi("PDFXTrimBoxToMediaBoxOffset", gs_param_type_float_array, PDFXTrimBoxToMediaBoxOffset),
104 pi("PDFXSetBleedBoxToMediaBox", gs_param_type_bool, PDFXSetBleedBoxToMediaBox),
105 pi("PDFXBleedBoxToTrimBoxOffset", gs_param_type_float_array, PDFXBleedBoxToTrimBoxOffset),
106
107 /* media selection parameters */
108 pi("SetPageSize", gs_param_type_bool, SetPageSize),
109 pi("RotatePages", gs_param_type_bool, RotatePages),
110 pi("FitPages", gs_param_type_bool, FitPages),
111 pi("CenterPages", gs_param_type_bool, CenterPages),
112 pi("DoNumCopies", gs_param_type_bool, DoNumCopies),
113 pi("PreserveSeparation", gs_param_type_bool, PreserveSeparation),
114 pi("PreserveDeviceN", gs_param_type_bool, PreserveDeviceN),
115 pi("PDFACompatibilityPolicy", gs_param_type_int, PDFACompatibilityPolicy),
116 #undef pi
117 gs_param_item_end
118 };
119
120 /*
121 Notes on implementing the remaining Distiller functionality
122 ===========================================================
123
124 Architectural issues
125 --------------------
126
127 Must optionally disable application of TR, BG, UCR similarly. Affects:
128 PreserveHalftoneInfo
129 PreserveOverprintSettings
130 TransferFunctionInfo
131 UCRandBGInfo
132
133 Current limitations
134 -------------------
135
136 Non-primary elements in HalftoneType 5 are not written correctly
137
138 Acrobat Distiller 3
139 -------------------
140
141 ---- Image parameters ----
142
143 AntiAlias{Color,Gray,Mono}Images
144
145 ---- Other parameters ----
146
147 CompressPages
148 Compress things other than page contents
149 * PreserveHalftoneInfo
150 PreserveOPIComments
151 ? see OPI spec?
152 * PreserveOverprintSettings
153 * TransferFunctionInfo
154 * UCRandBGInfo
155 ColorConversionStrategy
156 Select color space for drawing commands
157 ConvertImagesToIndexed
158 Postprocess image data *after* downsampling (requires an extra pass)
159
160 Acrobat Distiller 4
161 -------------------
162
163 ---- Other functionality ----
164
165 Document structure pdfmarks
166
167 ---- Parameters ----
168
169 xxxDownsampleType = /Bicubic
170 Add new filter (or use siscale?) & to setup (gdevpsdi.c)
171 DetectBlends
172 Idiom recognition? PatternType 2 patterns / shfill? (see AD4)
173 DoThumbnails
174 Also output to memory device -- resolution issue
175
176 ---- Job-level control ----
177
178 EmitDSCWarnings
179 Require DSC parser / interceptor
180 CreateJobTicket
181 ?
182 AutoPositionEPSFiles
183 Require DSC parsing
184 PreserveCopyPage
185 Concatenate Contents streams
186 UsePrologue
187 Needs hack in top-level control?
188
189 */
190
191 /* ---------------- Get parameters ---------------- */
192
193 /* Get parameters. */
194 int
gdev_pdf_get_params(gx_device * dev,gs_param_list * plist)195 gdev_pdf_get_params(gx_device * dev, gs_param_list * plist)
196 {
197 gx_device_pdf *pdev = (gx_device_pdf *) dev;
198 float cl = (float)pdev->CompatibilityLevel;
199 int code;
200 int cdv = CoreDistVersion;
201
202 pdev->ParamCompatibilityLevel = cl;
203 code = gdev_psdf_get_params(dev, plist);
204 if (code < 0 ||
205 (code = param_write_int(plist, "CoreDistVersion", &cdv)) < 0 ||
206 (code = param_write_float(plist, "CompatibilityLevel", &cl)) < 0 ||
207 (pdev->is_ps2write && (code = param_write_string(plist, "OPDFReadProcsetPath", &pdev->OPDFReadProcsetPath)) < 0) ||
208 (!pdev->is_ps2write && (code = param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0) ||
209 /* Indicate that we can process pdfmark and DSC. */
210 (param_requested(plist, "pdfmark") > 0 &&
211 (code = param_write_null(plist, "pdfmark")) < 0) ||
212 (param_requested(plist, "DSC") > 0 &&
213 (code = param_write_null(plist, "DSC")) < 0) ||
214 (code = gs_param_write_items(plist, pdev, NULL, pdf_param_items)) < 0
215 );
216 return code;
217 }
218
219 /* ---------------- Put parameters ---------------- */
220
221 /* Put parameters, implementation */
222 static int
gdev_pdf_put_params_impl(gx_device * dev,const gx_device_pdf * save_dev,gs_param_list * plist)223 gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_param_list * plist)
224 {
225 int ecode, code;
226 gx_device_pdf *pdev = (gx_device_pdf *) dev;
227 float cl = (float)pdev->CompatibilityLevel;
228 bool locked = pdev->params.LockDistillerParams;
229 gs_param_name param_name;
230 enum psdf_color_conversion_strategy save_ccs = pdev->params.ColorConversionStrategy;
231
232 pdev->pdf_memory = gs_memory_stable(pdev->memory);
233 /*
234 * If this is a pseudo-parameter (pdfmark or DSC),
235 * don't bother checking for any real ones.
236 */
237
238 {
239 gs_param_string_array ppa;
240
241 code = param_read_string_array(plist, (param_name = "pdfmark"), &ppa);
242 switch (code) {
243 case 0:
244 code = pdf_open_document(pdev);
245 if (code < 0)
246 return code;
247 code = pdfmark_process(pdev, &ppa);
248 if (code >= 0)
249 return code;
250 /* falls through for errors */
251 default:
252 param_signal_error(plist, param_name, code);
253 return code;
254 case 1:
255 break;
256 }
257
258 code = param_read_string_array(plist, (param_name = "DSC"), &ppa);
259 switch (code) {
260 case 0:
261 code = pdf_open_document(pdev);
262 if (code < 0)
263 return code;
264 code = pdf_dsc_process(pdev, &ppa);
265 if (code >= 0)
266 return code;
267 /* falls through for errors */
268 default:
269 param_signal_error(plist, param_name, code);
270 return code;
271 case 1:
272 break;
273 }
274 }
275
276 /*
277 * Check for LockDistillerParams before doing anything else.
278 * If LockDistillerParams is true and is not being set to false,
279 * ignore all resettings of PDF-specific parameters. Note that
280 * LockDistillerParams is read again, and reset if necessary, in
281 * psdf_put_params.
282 */
283 ecode = code = param_read_bool(plist, "LockDistillerParams", &locked);
284
285 if (!(locked && pdev->params.LockDistillerParams)) {
286 /* General parameters. */
287
288 {
289 int efo = 1;
290
291 ecode = param_put_int(plist, (param_name = ".EmbedFontObjects"), &efo, ecode);
292 if (efo != 1)
293 param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
294 }
295 {
296 int cdv = CoreDistVersion;
297
298 ecode = param_put_int(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
299 if (cdv != CoreDistVersion)
300 param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
301 }
302
303 switch (code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl)) {
304 default:
305 ecode = code;
306 param_signal_error(plist, param_name, ecode);
307 case 0:
308 /*
309 * Must be 1.2, 1.3, 1.4, or 1.5. Per Adobe documentation, substitute
310 * the nearest achievable value.
311 */
312 if (cl < (float)1.15)
313 cl = (float)1.1;
314 else if (cl < (float)1.25)
315 cl = (float)1.2;
316 else if (cl < (float)1.35)
317 cl = (float)1.3;
318 else if (cl < (float)1.45)
319 cl = (float)1.4;
320 else
321 cl = (float)1.5;
322 case 1:
323 break;
324 }
325 { /* HACK : gs_param_list_s::memory is documented in gsparam.h as
326 "for allocating coerced arrays". Not sure why zputdeviceparams
327 sets it to the current memory space, while the device
328 assumes to store them in the device's memory space.
329 As a hackish workaround we temporary replace it here.
330 Doing so because we don't want to change the global code now
331 because we're unable to test it with all devices.
332 Bug 688531 "Segmentation fault running pdfwrite from 219-01.ps".
333
334 This solution to be reconsidered after fixing
335 the bug 688533 "zputdeviceparams specifies a wrong memory space.".
336 */
337 gs_memory_t *mem = plist->memory;
338
339 plist->memory = pdev->pdf_memory;
340 code = gs_param_read_items(plist, pdev, pdf_param_items);
341 if (code < 0 ||
342 (pdev->is_ps2write && (code = param_read_string(plist, "OPDFReadProcsetPath", &pdev->OPDFReadProcsetPath)) < 0) ||
343 (!pdev->is_ps2write && (code = param_read_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0)
344 );
345 plist->memory = mem;
346 }
347 if (code < 0)
348 ecode = code;
349 {
350 /*
351 * Setting FirstObjectNumber is only legal if the file
352 * has just been opened and nothing has been written,
353 * or if we are setting it to the same value.
354 */
355 long fon = pdev->FirstObjectNumber;
356
357 if (fon != save_dev->FirstObjectNumber) {
358 if (fon <= 0 || fon > 0x7fff0000 ||
359 (pdev->next_id != 0 &&
360 pdev->next_id !=
361 save_dev->FirstObjectNumber + pdf_num_initial_ids)
362 ) {
363 ecode = gs_error_rangecheck;
364 param_signal_error(plist, "FirstObjectNumber", ecode);
365 }
366 }
367 }
368 {
369 /*
370 * Set ProcessColorModel now, because gx_default_put_params checks
371 * it.
372 */
373 static const char *const pcm_names[] = {
374 "DeviceGray", "DeviceRGB", "DeviceCMYK", "DeviceN", 0
375 };
376 int pcm = -1;
377
378 ecode = param_put_enum(plist, "ProcessColorModel", &pcm,
379 pcm_names, ecode);
380 if (pcm >= 0) {
381 pdf_set_process_color_model(pdev, pcm);
382 pdf_set_initial_color(pdev, &pdev->saved_fill_color, &pdev->saved_stroke_color,
383 &pdev->fill_used_process_color, &pdev->stroke_used_process_color);
384 }
385 }
386 }
387 if (ecode < 0)
388 goto fail;
389 /* PDFA and PDFX are stored in the page device dictionary and therefore
390 * set on every setpagedevice. However, if we have encountered a file which
391 * can't be made this way, and the PDFACompatibilityPolicy is 1, we want to
392 * continue producing the file, but not as a PDF/A or PDF/X file. Its more
393 * or less impossible to alter the setting in the (potentially saved) page
394 * device dictionary, so we use this rather clunky method.
395 */
396 if(pdev->PDFA && pdev->AbortPDFAX)
397 pdev->PDFA = false;
398 if(pdev->PDFX && pdev->AbortPDFAX)
399 pdev->PDFX = false;
400 if (pdev->PDFX && pdev->PDFA) {
401 ecode = gs_note_error(gs_error_rangecheck);
402 param_signal_error(plist, "PDFA", ecode);
403 goto fail;
404 }
405 if (pdev->PDFX && pdev->ForOPDFRead) {
406 ecode = gs_note_error(gs_error_rangecheck);
407 param_signal_error(plist, "PDFX", ecode);
408 goto fail;
409 }
410 if (pdev->PDFA && pdev->ForOPDFRead) {
411 ecode = gs_note_error(gs_error_rangecheck);
412 param_signal_error(plist, "PDFA", ecode);
413 goto fail;
414 }
415 if (pdev->PDFA)
416 pdev->HaveTransparency = false;
417 /*
418 * We have to set version to the new value, because the set of
419 * legal parameter values for psdf_put_params varies according to
420 * the version.
421 */
422 if (pdev->PDFX)
423 cl = (float)1.3; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
424 if (pdev->PDFA && cl < 1.4)
425 cl = (float)1.4;
426 pdev->version = (cl < 1.2 ? psdf_version_level2 : psdf_version_ll3);
427 if (pdev->ForOPDFRead) {
428 pdev->ResourcesBeforeUsage = true;
429 pdev->HaveCFF = false;
430 pdev->HavePDFWidths = false;
431 pdev->HaveStrokeColor = false;
432 cl = (float)1.2; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
433 pdev->MaxInlineImageSize = max_long; /* Save printer's RAM from saving temporary image data.
434 Immediate images doen't need buffering. */
435 pdev->version = psdf_version_level2;
436 } else {
437 pdev->ResourcesBeforeUsage = false;
438 pdev->HaveCFF = true;
439 pdev->HavePDFWidths = true;
440 pdev->HaveStrokeColor = true;
441 }
442 pdev->ParamCompatibilityLevel = cl;
443 ecode = gdev_psdf_put_params(dev, plist);
444 if (ecode < 0)
445 goto fail;
446 if ((pdev->params.ColorConversionStrategy == ccs_CMYK &&
447 strcmp(pdev->color_info.cm_name, "DeviceCMYK")) ||
448 (pdev->params.ColorConversionStrategy == ccs_sRGB &&
449 strcmp(pdev->color_info.cm_name, "DeviceRGB")) ||
450 (pdev->params.ColorConversionStrategy == ccs_Gray &&
451 strcmp(pdev->color_info.cm_name, "DeviceGray"))) {
452 eprintf("ColorConversionStrategy is incompatible to ProcessColorModel.\n");
453 ecode = gs_note_error(gs_error_rangecheck);
454 pdev->params.ColorConversionStrategy = save_ccs;
455 }
456 if (pdev->params.ColorConversionStrategy == ccs_UseDeviceIndependentColor) {
457 if (!pdev->UseCIEColor) {
458 eprintf("Set UseCIEColor for UseDeviceIndependentColor to work properly.\n");
459 ecode = gs_note_error(gs_error_rangecheck);
460 pdev->UseCIEColor = true;
461 }
462 }
463 if (pdev->params.ColorConversionStrategy == ccs_UseDeviceIndependentColorForImages) {
464 if (!pdev->UseCIEColor) {
465 eprintf("UseDeviceDependentColorForImages is not supported. Use UseDeviceIndependentColor.\n");
466 pdev->params.ColorConversionStrategy = ccs_UseDeviceIndependentColor;
467 if (!pdev->UseCIEColor) {
468 eprintf("Set UseCIEColor for UseDeviceIndependentColor to work properly.\n");
469 ecode = gs_note_error(gs_error_rangecheck);
470 pdev->UseCIEColor = true;
471 }
472 }
473 }
474 if (pdev->params.ColorConversionStrategy == ccs_UseDeviceDependentColor) {
475 if (!strcmp(pdev->color_info.cm_name, "DeviceCMYK")) {
476 eprintf("Replacing the deprecated device parameter value UseDeviceDependentColor with CMYK.\n");
477 pdev->params.ColorConversionStrategy = ccs_CMYK;
478 } else if (!strcmp(pdev->color_info.cm_name, "DeviceRGB")) {
479 eprintf("Replacing the deprecated device parameter value UseDeviceDependentColor with sRGB.\n");
480 pdev->params.ColorConversionStrategy = ccs_sRGB;
481 } else {
482 eprintf("Replacing the deprecated device parameter value UseDeviceDependentColor with Gray.\n");
483 pdev->params.ColorConversionStrategy = ccs_Gray;
484 }
485 }
486 if (cl < 1.5 && pdev->params.ColorImage.Filter != NULL &&
487 !strcmp(pdev->params.ColorImage.Filter, "JPXEncode")) {
488 eprintf("JPXEncode requires CompatibilityLevel >= 1.5 .\n");
489 ecode = gs_note_error(gs_error_rangecheck);
490 }
491 if (cl < 1.5 && pdev->params.GrayImage.Filter != NULL &&
492 !strcmp(pdev->params.GrayImage.Filter, "JPXEncode")) {
493 eprintf("JPXEncode requires CompatibilityLevel >= 1.5 .\n");
494 ecode = gs_note_error(gs_error_rangecheck);
495 }
496 if (cl < 1.4 && pdev->params.MonoImage.Filter != NULL &&
497 !strcmp(pdev->params.MonoImage.Filter, "JBIG2Encode")) {
498 eprintf("JBIG2Encode requires CompatibilityLevel >= 1.4 .\n");
499 ecode = gs_note_error(gs_error_rangecheck);
500 }
501 if (pdev->HaveTrueTypes && pdev->version == psdf_version_level2) {
502 pdev->version = psdf_version_level2_with_TT ;
503 }
504 /*
505 * Acrobat Reader doesn't handle user-space coordinates larger than
506 * MAX_USER_COORD. To compensate for this, reduce the resolution so
507 * that the page size in device space (which we equate to user space) is
508 * significantly less than MAX_USER_COORD. Note that this still does
509 * not protect us against input files that use coordinates far outside
510 * the page boundaries.
511 */
512 #define MAX_EXTENT ((int)(MAX_USER_COORD * 0.9))
513 /* Changing resolution or page size requires closing the device, */
514 if (dev->height > MAX_EXTENT || dev->width > MAX_EXTENT) {
515 double factor =
516 max(dev->height / (double)MAX_EXTENT,
517 dev->width / (double)MAX_EXTENT);
518
519 gx_device_set_resolution(dev, dev->HWResolution[0] / factor,
520 dev->HWResolution[1] / factor);
521 }
522 #undef MAX_EXTENT
523 if (pdev->FirstObjectNumber != save_dev->FirstObjectNumber) {
524 if (pdev->xref.file != 0) {
525 fseek(pdev->xref.file, 0L, SEEK_SET);
526 pdf_initialize_ids(pdev);
527 }
528 }
529 /* Handle the float/double mismatch. */
530 pdev->CompatibilityLevel = (int)(cl * 10 + 0.5) / 10.0;
531 return 0;
532 fail:
533 /* Restore all the parameters to their original state. */
534 pdev->version = save_dev->version;
535 pdf_set_process_color_model(pdev, save_dev->pcm_color_info_index);
536 pdev->saved_fill_color = save_dev->saved_fill_color;
537 pdev->saved_stroke_color = save_dev->saved_fill_color;
538 {
539 const gs_param_item_t *ppi = pdf_param_items;
540
541 for (; ppi->key; ++ppi)
542 memcpy((char *)pdev + ppi->offset,
543 (char *)save_dev + ppi->offset,
544 gs_param_type_sizes[ppi->type]);
545 pdev->ForOPDFRead = save_dev->ForOPDFRead;
546 pdev->OPDFReadProcsetPath = save_dev->OPDFReadProcsetPath;
547 }
548 return ecode;
549 }
550
551 /* Put parameters */
552 int
gdev_pdf_put_params(gx_device * dev,gs_param_list * plist)553 gdev_pdf_put_params(gx_device * dev, gs_param_list * plist)
554 {
555 int code;
556 gx_device_pdf *pdev = (gx_device_pdf *) dev;
557 gs_memory_t *mem = gs_memory_stable(pdev->memory);
558 gx_device_pdf *save_dev = gs_malloc(mem, sizeof(gx_device_pdf), 1,
559 "saved gx_device_pdf");
560
561 if (!save_dev)
562 return_error(gs_error_VMerror);
563 memcpy(save_dev, pdev, sizeof(gx_device_pdf));
564 code = gdev_pdf_put_params_impl(dev, save_dev, plist);
565 gs_free(mem, save_dev, sizeof(gx_device_pdf), 1, "saved gx_device_pdf");
566 return code;
567 }
568
569 /* ---------------- Process DSC comments ---------------- */
570
571 static int
pdf_dsc_process(gx_device_pdf * pdev,const gs_param_string_array * pma)572 pdf_dsc_process(gx_device_pdf * pdev, const gs_param_string_array * pma)
573 {
574 /*
575 * The Adobe "Distiller Parameters" documentation says that Distiller
576 * looks at DSC comments, but it doesn't say which ones. We look at
577 * the ones that we see how to map directly to obvious PDF constructs.
578 */
579 int code = 0;
580 uint i;
581
582 /*
583 * If ParseDSCComments is false, all DSC comments are ignored, even if
584 * ParseDSCComentsForDocInfo or PreserveEPSInfo is true.
585 */
586 if (!pdev->ParseDSCComments)
587 return 0;
588
589 for (i = 0; i + 1 < pma->size && code >= 0; i += 2) {
590 const gs_param_string *pkey = &pma->data[i];
591 const gs_param_string *pvalue = &pma->data[i + 1];
592 const char *key;
593 int code;
594
595 /*
596 * %%For, %%Creator, and %%Title are recognized only if either
597 * ParseDSCCommentsForDocInfo or PreserveEPSInfo is true.
598 * The other DSC comments are always recognized.
599 *
600 * Acrobat Distiller sets CreationDate and ModDate to the current
601 * time, not the value of %%CreationDate. We think this is wrong,
602 * but we do the same -- we ignore %%CreationDate here.
603 */
604
605 if (pdf_key_eq(pkey, "Creator"))
606 key = "/Creator";
607 else if (pdf_key_eq(pkey, "Title"))
608 key = "/Title";
609 else if (pdf_key_eq(pkey, "For"))
610 key = "/Author";
611 else {
612 pdf_page_dsc_info_t *ppdi;
613 char scan_buf[200]; /* arbitrary */
614
615 if ((ppdi = &pdev->doc_dsc_info,
616 pdf_key_eq(pkey, "Orientation")) ||
617 (ppdi = &pdev->page_dsc_info,
618 pdf_key_eq(pkey, "PageOrientation"))
619 ) {
620 if (pvalue->size == 1 && pvalue->data[0] >= '0' &&
621 pvalue->data[0] <= '3'
622 )
623 ppdi->orientation = pvalue->data[0] - '0';
624 else
625 ppdi->orientation = -1;
626 } else if ((ppdi = &pdev->doc_dsc_info,
627 pdf_key_eq(pkey, "ViewingOrientation")) ||
628 (ppdi = &pdev->page_dsc_info,
629 pdf_key_eq(pkey, "PageViewingOrientation"))
630 ) {
631 gs_matrix mat;
632 int orient;
633
634 if(pvalue->size >= sizeof(scan_buf) - 1)
635 continue; /* error */
636 memcpy(scan_buf, pvalue->data, pvalue->size);
637 scan_buf[pvalue->size] = 0;
638 if (sscanf(scan_buf, "[%g %g %g %g]",
639 &mat.xx, &mat.xy, &mat.yx, &mat.yy) != 4
640 )
641 continue; /* error */
642 for (orient = 0; orient < 4; ++orient) {
643 if (mat.xx == 1 && mat.xy == 0 && mat.yx == 0 && mat.yy == 1)
644 break;
645 gs_matrix_rotate(&mat, -90.0, &mat);
646 }
647 if (orient == 4) /* error */
648 orient = -1;
649 ppdi->viewing_orientation = orient;
650 } else {
651 gs_rect box;
652
653 if (pdf_key_eq(pkey, "EPSF")) {
654 pdev->is_EPS = (pvalue->size >= 1 && pvalue->data[0] != '0');
655 continue;
656 }
657 /*
658 * We only parse the BoundingBox for the sake of
659 * AutoPositionEPSFiles.
660 */
661 if (pdf_key_eq(pkey, "BoundingBox"))
662 ppdi = &pdev->doc_dsc_info;
663 else if (pdf_key_eq(pkey, "PageBoundingBox"))
664 ppdi = &pdev->page_dsc_info;
665 else
666 continue;
667 if(pvalue->size >= sizeof(scan_buf) - 1)
668 continue; /* error */
669 memcpy(scan_buf, pvalue->data, pvalue->size);
670 scan_buf[pvalue->size] = 0;
671 if (sscanf(scan_buf, "[%lg %lg %lg %lg]",
672 &box.p.x, &box.p.y, &box.q.x, &box.q.y) != 4
673 )
674 continue; /* error */
675 ppdi->bounding_box = box;
676 }
677 continue;
678 }
679
680 if (pdev->ParseDSCCommentsForDocInfo || pdev->PreserveEPSInfo)
681 code = cos_dict_put_c_key_string(pdev->Info, key,
682 pvalue->data, pvalue->size);
683 }
684 return code;
685 }
686