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