1 /* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, 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 "gdevpsdf.h"
25 #include "gsparamx.h"
26 #include "gsicc_manage.h"
27
28 /*
29 * The pdfwrite device supports the following "real" parameters:
30 * OutputFile <string>
31 * all the Distiller parameters (also see gdevpsdp.c)
32 * Only some of the Distiller parameters actually have any effect.
33 *
34 * The device also supports the following write-only pseudo-parameters that
35 * serve only to communicate other information from the PostScript file.
36 * Their "value" is an array of strings, some of which may be the result
37 * of converting arbitrary PostScript objects to string form.
38 * pdfmark - see gdevpdfm.c
39 * DSC - processed in this file
40 */
41 static int pdf_dsc_process(gx_device_pdf * pdev,
42 const gs_param_string_array * pma);
43
44 static const int CoreDistVersion = 5000; /* Distiller 5.0 */
45 static const gs_param_item_t pdf_param_items[] = {
46 #define pi(key, type, memb) { key, type, offset_of(gx_device_pdf, memb) }
47
48 /* Acrobat Distiller 4 parameters */
49
50 /*
51 * EndPage and StartPage are renamed because EndPage collides with
52 * a page device parameter.
53 */
54 pi("PDFEndPage", gs_param_type_int, EndPage),
55 pi("PDFStartPage", gs_param_type_int, StartPage),
56 pi("Optimize", gs_param_type_bool, Optimize),
57 pi("ParseDSCCommentsForDocInfo", gs_param_type_bool,
58 ParseDSCCommentsForDocInfo),
59 pi("ParseDSCComments", gs_param_type_bool, ParseDSCComments),
60 pi("EmitDSCWarnings", gs_param_type_bool, EmitDSCWarnings),
61 pi("CreateJobTicket", gs_param_type_bool, CreateJobTicket),
62 pi("PreserveEPSInfo", gs_param_type_bool, PreserveEPSInfo),
63 pi("AutoPositionEPSFiles", gs_param_type_bool, AutoPositionEPSFiles),
64 pi("PreserveCopyPage", gs_param_type_bool, PreserveCopyPage),
65 pi("UsePrologue", gs_param_type_bool, UsePrologue),
66
67 /* Acrobat Distiller 5 parameters */
68
69 pi("OffOptimizations", gs_param_type_int, OffOptimizations),
70
71 /* Ghostscript-specific parameters */
72
73 pi("ReAssignCharacters", gs_param_type_bool, ReAssignCharacters),
74 pi("ReEncodeCharacters", gs_param_type_bool, ReEncodeCharacters),
75 pi("FirstObjectNumber", gs_param_type_long, FirstObjectNumber),
76 pi("CompressFonts", gs_param_type_bool, CompressFonts),
77 pi("CompressStreams", gs_param_type_bool, CompressStreams),
78 pi("PrintStatistics", gs_param_type_bool, PrintStatistics),
79 pi("MaxInlineImageSize", gs_param_type_long, MaxInlineImageSize),
80
81 /* PDF Encryption */
82 pi("OwnerPassword", gs_param_type_string, OwnerPassword),
83 pi("UserPassword", gs_param_type_string, UserPassword),
84 pi("KeyLength", gs_param_type_int, KeyLength),
85 pi("Permissions", gs_param_type_int, Permissions),
86 pi("EncryptionR", gs_param_type_int, EncryptionR),
87 pi("NoEncrypt", gs_param_type_string, NoEncrypt),
88
89 /* Target viewer capabilities (Ghostscript-specific) */
90 /* pi("ForOPDFRead", gs_param_type_bool, ForOPDFRead), pdfwrite-only */
91 pi("ProduceDSC", gs_param_type_bool, ProduceDSC),
92 pi("PatternImagemask", gs_param_type_bool, PatternImagemask),
93 pi("MaxClipPathSize", gs_param_type_int, MaxClipPathSize),
94 pi("MaxShadingBitmapSize", gs_param_type_int, MaxShadingBitmapSize),
95 pi("HaveTrueTypes", gs_param_type_bool, HaveTrueTypes),
96 pi("HaveCIDSystem", gs_param_type_bool, HaveCIDSystem),
97 pi("HaveTransparency", gs_param_type_bool, HaveTransparency),
98 pi("CompressEntireFile", gs_param_type_bool, CompressEntireFile),
99 pi("PDFX", gs_param_type_bool, PDFX),
100 pi("PDFA", gs_param_type_int, PDFA),
101 pi("DocumentUUID", gs_param_type_string, DocumentUUID),
102 pi("InstanceUUID", gs_param_type_string, InstanceUUID),
103 pi("DocumentTimeSeq", gs_param_type_int, DocumentTimeSeq),
104
105 /* PDF/X parameters */
106 pi("PDFXTrimBoxToMediaBoxOffset", gs_param_type_float_array, PDFXTrimBoxToMediaBoxOffset),
107 pi("PDFXSetBleedBoxToMediaBox", gs_param_type_bool, PDFXSetBleedBoxToMediaBox),
108 pi("PDFXBleedBoxToTrimBoxOffset", gs_param_type_float_array, PDFXBleedBoxToTrimBoxOffset),
109
110 /* media selection parameters */
111 pi("SetPageSize", gs_param_type_bool, SetPageSize),
112 pi("RotatePages", gs_param_type_bool, RotatePages),
113 pi("FitPages", gs_param_type_bool, FitPages),
114 pi("CenterPages", gs_param_type_bool, CenterPages),
115 pi("DoNumCopies", gs_param_type_bool, DoNumCopies),
116 pi("PreserveSeparation", gs_param_type_bool, PreserveSeparation),
117 pi("PreserveDeviceN", gs_param_type_bool, PreserveDeviceN),
118 pi("PDFACompatibilityPolicy", gs_param_type_int, PDFACompatibilityPolicy),
119 pi("DetectDuplicateImages", gs_param_type_bool, DetectDuplicateImages),
120 pi("AllowIncrementalCFF", gs_param_type_bool, AllowIncrementalCFF),
121 pi("WantsToUnicode", gs_param_type_bool, WantsToUnicode),
122 pi("AllowPSRepeatFunctions", gs_param_type_bool, AllowPSRepeatFunctions),
123 pi("IsDistiller", gs_param_type_bool, IsDistiller),
124 pi("PreserveSMask", gs_param_type_bool, PreserveSMask),
125 pi("PreserveTrMode", gs_param_type_bool, PreserveTrMode),
126 pi("NoT3CCITT", gs_param_type_bool, NoT3CCITT),
127 pi("FastWebView", gs_param_type_bool, Linearise),
128 pi("NoOutputFonts", gs_param_type_bool, FlattenFonts),
129 pi("WantsPageLabels", gs_param_type_bool, WantsPageLabels),
130 pi("UserUnit", gs_param_type_float, UserUnit),
131 #undef pi
132 gs_param_item_end
133 };
134
135 /*
136 Notes on implementing the remaining Distiller functionality
137 ===========================================================
138
139 Architectural issues
140 --------------------
141
142 Must optionally disable application of TR, BG, UCR similarly. Affects:
143 PreserveHalftoneInfo
144 PreserveOverprintSettings
145 TransferFunctionInfo
146 UCRandBGInfo
147
148 Current limitations
149 -------------------
150
151 Non-primary elements in HalftoneType 5 are not written correctly
152
153 Acrobat Distiller 3
154 -------------------
155
156 ---- Image parameters ----
157
158 AntiAlias{Color,Gray,Mono}Images
159
160 ---- Other parameters ----
161
162 CompressPages
163 Compress things other than page contents
164 * PreserveHalftoneInfo
165 PreserveOPIComments
166 ? see OPI spec?
167 * PreserveOverprintSettings
168 * TransferFunctionInfo
169 * UCRandBGInfo
170 ColorConversionStrategy
171 Select color space for drawing commands
172 ConvertImagesToIndexed
173 Postprocess image data *after* downsampling (requires an extra pass)
174
175 Acrobat Distiller 4
176 -------------------
177
178 ---- Other functionality ----
179
180 Document structure pdfmarks
181
182 ---- Parameters ----
183
184 xxxDownsampleType = /Bicubic
185 Add new filter (or use siscale?) & to setup (gdevpsdi.c)
186 DetectBlends
187 Idiom recognition? PatternType 2 patterns / shfill? (see AD4)
188 DoThumbnails
189 Also output to memory device -- resolution issue
190
191 ---- Job-level control ----
192
193 EmitDSCWarnings
194 Require DSC parser / interceptor
195 CreateJobTicket
196 ?
197 AutoPositionEPSFiles
198 Require DSC parsing
199 PreserveCopyPage
200 Concatenate Contents streams
201 UsePrologue
202 Needs hack in top-level control?
203
204 */
205
206 /* Transfer a collection of parameters. */
207 static const byte xfer_item_sizes[] = {
208 GS_PARAM_TYPE_SIZES(0)
209 };
210 int
gdev_pdf_get_param(gx_device * dev,char * Param,void * list)211 gdev_pdf_get_param(gx_device *dev, char *Param, void *list)
212 {
213 gx_device_pdf *pdev = (gx_device_pdf *)dev;
214 const gs_param_item_t *pi;
215 gs_param_list * plist = (gs_param_list *)list;
216 int code = 0;
217
218 for (pi = pdf_param_items; pi->key != 0; ++pi) {
219 if (strcmp(pi->key, Param) == 0) {
220 const char *key = pi->key;
221 const void *pvalue = (const void *)((const char *)pdev + pi->offset);
222 int size = xfer_item_sizes[pi->type];
223 gs_param_typed_value typed;
224
225 memcpy(&typed.value, pvalue, size);
226 typed.type = pi->type;
227 code = (*plist->procs->xmit_typed) (plist, key, &typed);
228 return code;
229 }
230 }
231 if (strcmp(Param, "CoreDistVersion") == 0) {
232 return(param_write_int(plist, "CoreDistVersion", &CoreDistVersion));
233 }
234 if (strcmp(Param, "CompatibilityLevel") == 0) {
235 float f = pdev->CompatibilityLevel;
236 return(param_write_float(plist, "CompatibilityLevel", &f));
237 }
238 if (strcmp(Param, "ForOPDFRead") == 0) {
239 return(param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead));
240 }
241 if (strcmp(Param, "PassUserUnit") == 0) {
242 bool dummy;
243 if (pdev->CompatibilityLevel > 1.5)
244 dummy = true;
245 else
246 dummy = false;
247 return(param_write_bool(plist, "PassUserUnit", &dummy));
248 }
249 if (!pdev->is_ps2write) {
250 if (strcmp(Param, "pdfmark") == 0){
251 return(param_write_null(plist, "pdfmark"));
252 }
253 if (strcmp(Param, "DSC") == 0){
254 return(param_write_null(plist, "DSC"));
255 }
256 }
257 return gdev_psdf_get_param(dev, Param, list);
258 }
259
260 /* ---------------- Get parameters ---------------- */
261
262 /* Get parameters. */
263 int
gdev_pdf_get_params(gx_device * dev,gs_param_list * plist)264 gdev_pdf_get_params(gx_device * dev, gs_param_list * plist)
265 {
266 gx_device_pdf *pdev = (gx_device_pdf *) dev;
267 float cl = (float)pdev->CompatibilityLevel;
268 int code;
269 int cdv = CoreDistVersion;
270
271 pdev->ParamCompatibilityLevel = cl;
272 code = gdev_psdf_get_params(dev, plist);
273 if (code < 0 ||
274 (code = param_write_int(plist, "CoreDistVersion", &cdv)) < 0 ||
275 (code = param_write_float(plist, "CompatibilityLevel", &cl)) < 0 ||
276 (!pdev->is_ps2write && (code = param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0) ||
277 /* Indicate that we can process pdfmark and DSC. */
278 (param_requested(plist, "pdfmark") > 0 &&
279 (code = param_write_null(plist, "pdfmark")) < 0) ||
280 (param_requested(plist, "DSC") > 0 &&
281 (code = param_write_null(plist, "DSC")) < 0) ||
282 (code = gs_param_write_items(plist, pdev, NULL, pdf_param_items)) < 0
283 )
284 {}
285 return code;
286 }
287
288 /* ---------------- Put parameters ---------------- */
289
290 /* Put parameters, implementation */
291 static int
gdev_pdf_put_params_impl(gx_device * dev,const gx_device_pdf * save_dev,gs_param_list * plist)292 gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_param_list * plist)
293 {
294 int ecode, code;
295 gx_device_pdf *pdev = (gx_device_pdf *) dev;
296 float cl = (float)pdev->CompatibilityLevel;
297 bool locked = pdev->params.LockDistillerParams, ForOPDFRead;
298 gs_param_name param_name;
299
300 pdev->pdf_memory = gs_memory_stable(pdev->memory);
301 /*
302 * If this is a pseudo-parameter (pdfmark or DSC),
303 * don't bother checking for any real ones.
304 */
305
306 {
307 gs_param_string_array ppa;
308 gs_param_string pps;
309
310 code = param_read_string_array(plist, (param_name = "pdfmark"), &ppa);
311 switch (code) {
312 case 0:
313 code = pdfwrite_pdf_open_document(pdev);
314 if (code < 0)
315 return code;
316 code = pdfmark_process(pdev, &ppa);
317 if (code >= 0)
318 return code;
319 /* falls through for errors */
320 default:
321 param_signal_error(plist, param_name, code);
322 return code;
323 case 1:
324 break;
325 }
326
327 code = param_read_string_array(plist, (param_name = "DSC"), &ppa);
328 switch (code) {
329 case 0:
330 code = pdfwrite_pdf_open_document(pdev);
331 if (code < 0)
332 return code;
333 code = pdf_dsc_process(pdev, &ppa);
334 if (code >= 0)
335 return code;
336 /* falls through for errors */
337 default:
338 param_signal_error(plist, param_name, code);
339 return code;
340 case 1:
341 break;
342 }
343
344 code = param_read_string(plist, (param_name = "pdfpagelabels"), &pps);
345 switch (code) {
346 case 0:
347 {
348 if (!pdev->ForOPDFRead) {
349 cos_dict_t *const pcd = pdev->Catalog;
350 code = pdfwrite_pdf_open_document(pdev);
351 if (code < 0)
352 return code;
353 code = cos_dict_put_string(pcd, (const byte *)"/PageLabels", 11,
354 pps.data, pps.size);
355 if (code >= 0)
356 return code;
357 } else
358 return 0;
359 }
360 /* falls through for errors */
361 default:
362 param_signal_error(plist, param_name, code);
363 return code;
364 case 1:
365 break;
366 }
367 }
368
369 /*
370 * Check for LockDistillerParams before doing anything else.
371 * If LockDistillerParams is true and is not being set to false,
372 * ignore all resettings of PDF-specific parameters. Note that
373 * LockDistillerParams is read again, and reset if necessary, in
374 * psdf_put_params.
375 */
376 ecode = param_read_bool(plist, (param_name = "LockDistillerParams"), &locked);
377 if (ecode < 0)
378 param_signal_error(plist, param_name, ecode);
379
380 /* General parameters. */
381
382 {
383 int efo = 1;
384
385 ecode = param_put_int(plist, (param_name = ".EmbedFontObjects"), &efo, ecode);
386 if (ecode < 0)
387 param_signal_error(plist, param_name, ecode);
388 if (efo != 1)
389 param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
390 }
391 {
392 int cdv = CoreDistVersion;
393
394 ecode = param_put_int(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
395 if (ecode < 0)
396 return gs_note_error(ecode);
397 if (cdv != CoreDistVersion)
398 param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
399 }
400
401 switch (code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl)) {
402 default:
403 ecode = code;
404 param_signal_error(plist, param_name, ecode);
405 break;
406 case 0:
407 if (!(locked && pdev->params.LockDistillerParams)) {
408 /*
409 * Must be 1.2, 1.3, 1.4, or 1.5. Per Adobe documentation, substitute
410 * the nearest achievable value.
411 */
412 if (cl < (float)1.15)
413 cl = (float)1.1;
414 else if (cl < (float)1.25)
415 cl = (float)1.2;
416 else if (cl < (float)1.35)
417 cl = (float)1.3;
418 else if (cl < (float)1.45)
419 cl = (float)1.4;
420 else if (cl < (float)1.55)
421 cl = (float)1.5;
422 else if (cl < (float)1.65)
423 cl = (float)1.6;
424 else if (cl < (float)1.75)
425 cl = (float)1.7;
426 else {
427 cl = (float)2.0;
428 if (pdev->params.TransferFunctionInfo == tfi_Preserve)
429 pdev->params.TransferFunctionInfo = tfi_Apply;
430 }
431 }
432 case 1:
433 break;
434 }
435 { /* HACK : gs_param_list_s::memory is documented in gsparam.h as
436 "for allocating coerced arrays". Not sure why zputdeviceparams
437 sets it to the current memory space, while the device
438 assumes to store them in the device's memory space.
439 As a hackish workaround we temporary replace it here.
440 Doing so because we don't want to change the global code now
441 because we're unable to test it with all devices.
442 Bug 688531 "Segmentation fault running pdfwrite from 219-01.ps".
443
444 This solution to be reconsidered after fixing
445 the bug 688533 "zputdeviceparams specifies a wrong memory space.".
446 */
447 gs_memory_t *mem = plist->memory;
448
449 plist->memory = pdev->pdf_memory;
450 code = gs_param_read_items(plist, pdev, pdf_param_items);
451 if (code < 0 || (code = param_read_bool(plist, "ForOPDFRead", &ForOPDFRead)) < 0)
452 {
453 }
454 if (code == 0 && !pdev->is_ps2write && !(locked && pdev->params.LockDistillerParams))
455 pdev->ForOPDFRead = ForOPDFRead;
456 plist->memory = mem;
457 }
458 if (code < 0)
459 ecode = code;
460 {
461 /*
462 * Setting FirstObjectNumber is only legal if the file
463 * has just been opened and nothing has been written,
464 * or if we are setting it to the same value.
465 */
466 long fon = pdev->FirstObjectNumber;
467
468 if (fon != save_dev->FirstObjectNumber) {
469 if (fon <= 0 || fon > 0x7fff0000 ||
470 (pdev->next_id != 0 &&
471 pdev->next_id !=
472 save_dev->FirstObjectNumber + pdf_num_initial_ids)
473 ) {
474 ecode = gs_error_rangecheck;
475 param_signal_error(plist, "FirstObjectNumber", ecode);
476 }
477 }
478 }
479 {
480 /*
481 * Set ProcessColorModel now, because gx_default_put_params checks
482 * it.
483 */
484 static const char *const pcm_names[] = {
485 "DeviceGray", "DeviceRGB", "DeviceCMYK", "DeviceN", 0
486 };
487 int pcm = -1;
488
489 ecode = param_put_enum(plist, "ProcessColorModel", &pcm,
490 pcm_names, ecode);
491 if (ecode < 0)
492 goto fail;
493 if (pcm >= 0) {
494 pdf_set_process_color_model(pdev, pcm);
495 rc_decrement(pdev->icc_struct, "gdev_pdf_put_params_impl, ProcessColorModel changed");
496 pdev->icc_struct = 0;
497 }
498 }
499
500 if (pdev->is_ps2write && (code = param_read_bool(plist, "ProduceDSC", &pdev->ProduceDSC)) < 0) {
501 param_signal_error(plist, param_name, code);
502 }
503
504 /* PDFA and PDFX are stored in the page device dictionary and therefore
505 * set on every setpagedevice. However, if we have encountered a file which
506 * can't be made this way, and the PDFACompatibilityPolicy is 1, we want to
507 * continue producing the file, but not as a PDF/A or PDF/X file. Its more
508 * or less impossible to alter the setting in the (potentially saved) page
509 * device dictionary, so we use this rather clunky method.
510 */
511 if (pdev->PDFA < 0 || pdev->PDFA > 3){
512 ecode = gs_note_error(gs_error_rangecheck);
513 param_signal_error(plist, "PDFA", ecode);
514 goto fail;
515 }
516 if(pdev->PDFA != 0 && pdev->AbortPDFAX)
517 pdev->PDFA = 0;
518 if(pdev->PDFX && pdev->AbortPDFAX)
519 pdev->PDFX = 0;
520 if (pdev->PDFX && pdev->PDFA != 0) {
521 ecode = gs_note_error(gs_error_rangecheck);
522 param_signal_error(plist, "PDFA", ecode);
523 goto fail;
524 }
525 if (pdev->PDFX && pdev->ForOPDFRead) {
526 ecode = gs_note_error(gs_error_rangecheck);
527 param_signal_error(plist, "PDFX", ecode);
528 goto fail;
529 }
530 if (pdev->PDFA != 0 && pdev->ForOPDFRead) {
531 ecode = gs_note_error(gs_error_rangecheck);
532 param_signal_error(plist, "PDFA", ecode);
533 goto fail;
534 }
535 if (pdev->PDFA == 1 || pdev->PDFX || pdev->CompatibilityLevel < 1.4) {
536 pdev->HaveTransparency = false;
537 pdev->PreserveSMask = false;
538 }
539
540 /*
541 * We have to set version to the new value, because the set of
542 * legal parameter values for psdf_put_params varies according to
543 * the version.
544 */
545 if (pdev->PDFX)
546 cl = (float)1.3; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
547 if (pdev->PDFA == 1 && cl != 1.4)
548 cl = (float)1.4;
549 if (pdev->PDFA == 2 && cl < 1.7)
550 cl = (float)1.7;
551 pdev->version = (cl < 1.2 ? psdf_version_level2 : psdf_version_ll3);
552 if (pdev->ForOPDFRead) {
553 pdev->ResourcesBeforeUsage = true;
554 pdev->HaveCFF = false;
555 pdev->HavePDFWidths = false;
556 pdev->HaveStrokeColor = false;
557 cl = (float)1.2; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
558 pdev->MaxInlineImageSize = max_long; /* Save printer's RAM from saving temporary image data.
559 Immediate images doen't need buffering. */
560 pdev->version = psdf_version_level2;
561 } else {
562 pdev->ResourcesBeforeUsage = false;
563 pdev->HaveCFF = true;
564 pdev->HavePDFWidths = true;
565 pdev->HaveStrokeColor = true;
566 }
567 pdev->ParamCompatibilityLevel = cl;
568 if (cl < 1.2) {
569 pdev->HaveCFF = false;
570 }
571
572 ecode = param_read_float(plist, "UserUnit", &pdev->UserUnit);
573 if (ecode < 0)
574 goto fail;
575 if (pdev->UserUnit == 0 || (pdev->UserUnit != 1 && pdev->CompatibilityLevel < 1.6)) {
576 ecode = gs_note_error(gs_error_rangecheck);
577 param_signal_error(plist, "UserUnit", ecode);
578 goto fail;
579 }
580
581 ecode = gdev_psdf_put_params(dev, plist);
582 if (ecode < 0)
583 goto fail;
584
585 if (pdev->CompatibilityLevel > 1.7 && pdev->params.TransferFunctionInfo == tfi_Preserve) {
586 pdev->params.TransferFunctionInfo = tfi_Apply;
587 emprintf(pdev->memory, "\nIt is not possible to preserve transfer functions in PDF 2.0\ntransfer functions will be applied instead\n");
588 }
589
590 if (pdev->params.ConvertCMYKImagesToRGB) {
591 if (pdev->params.ColorConversionStrategy == ccs_CMYK) {
592 emprintf(pdev->memory, "ConvertCMYKImagesToRGB is not compatible with ColorConversionStrategy of CMYK\n");
593 } else {
594 if (pdev->params.ColorConversionStrategy == ccs_Gray) {
595 emprintf(pdev->memory, "ConvertCMYKImagesToRGB is not compatible with ColorConversionStrategy of Gray\n");
596 } else {
597 if (pdev->icc_struct)
598 rc_decrement(pdev->icc_struct,
599 "reset default profile\n");
600 pdf_set_process_color_model(pdev,1);
601 ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
602 if (ecode < 0)
603 goto fail;
604 }
605 }
606 }
607 switch (pdev->params.ColorConversionStrategy) {
608 case ccs_ByObjectType:
609 case ccs_LeaveColorUnchanged:
610 break;
611 case ccs_UseDeviceIndependentColor:
612 case ccs_UseDeviceIndependentColorForImages:
613 pdev->params.TransferFunctionInfo = tfi_Apply;
614 break;
615 case ccs_CMYK:
616 if (pdev->icc_struct)
617 rc_decrement(pdev->icc_struct,
618 "reset default profile\n");
619 pdf_set_process_color_model(pdev, 2);
620 ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
621 if (ecode < 0)
622 goto fail;
623 break;
624 case ccs_Gray:
625 if (pdev->icc_struct)
626 rc_decrement(pdev->icc_struct,
627 "reset default profile\n");
628 pdf_set_process_color_model(pdev,0);
629 ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
630 if (ecode < 0)
631 goto fail;
632 break;
633 case ccs_sRGB:
634 case ccs_RGB:
635 /* Only bother to do this if we didn't handle it above */
636 if (!pdev->params.ConvertCMYKImagesToRGB) {
637 if (pdev->icc_struct)
638 rc_decrement(pdev->icc_struct,
639 "reset default profile\n");
640 pdf_set_process_color_model(pdev,1);
641 ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
642 if (ecode < 0)
643 goto fail;
644 }
645 break;
646 default:
647 break;
648 }
649 if (cl < 1.5f && pdev->params.ColorImage.Filter != NULL &&
650 !strcmp(pdev->params.ColorImage.Filter, "JPXEncode")) {
651 emprintf(pdev->memory,
652 "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
653 ecode = gs_note_error(gs_error_rangecheck);
654 }
655 if (cl < 1.5f && pdev->params.GrayImage.Filter != NULL &&
656 !strcmp(pdev->params.GrayImage.Filter, "JPXEncode")) {
657 emprintf(pdev->memory,
658 "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
659 ecode = gs_note_error(gs_error_rangecheck);
660 }
661 if (cl < 1.4f && pdev->params.MonoImage.Filter != NULL &&
662 !strcmp(pdev->params.MonoImage.Filter, "JBIG2Encode")) {
663 emprintf(pdev->memory,
664 "JBIG2Encode requires CompatibilityLevel >= 1.4 .\n");
665 ecode = gs_note_error(gs_error_rangecheck);
666 }
667 if (pdev->HaveTrueTypes && pdev->version == psdf_version_level2) {
668 pdev->version = psdf_version_level2_with_TT ;
669 }
670 if (ecode < 0)
671 goto fail;
672
673 if (pdev->FirstObjectNumber != save_dev->FirstObjectNumber) {
674 if (pdev->xref.file != 0) {
675 if (gp_fseek(pdev->xref.file, 0L, SEEK_SET) != 0) {
676 ecode = gs_error_ioerror;
677 goto fail;
678 }
679 pdf_initialize_ids(pdev);
680 }
681 }
682 /* Handle the float/double mismatch. */
683 pdev->CompatibilityLevel = (int)(cl * 10 + 0.5) / 10.0;
684
685 if (pdev->ForOPDFRead && pdev->OwnerPassword.size != 0) {
686 emprintf(pdev->memory, "\n\tSetting OwnerPassword for PostScript output would result in an encrypted\n\tunusable PostScript file, ignoring.\n");
687 pdev->OwnerPassword.size = 0;
688 }
689
690 if(pdev->OwnerPassword.size != save_dev->OwnerPassword.size ||
691 (pdev->OwnerPassword.size != 0 &&
692 memcmp(pdev->OwnerPassword.data, save_dev->OwnerPassword.data,
693 pdev->OwnerPassword.size) != 0)) {
694 if (pdev->is_open) {
695 if (pdev->PageCount == 0) {
696 gs_closedevice((gx_device *)save_dev);
697 return 0;
698 }
699 else
700 emprintf(pdev->memory, "Owner Password changed mid-job, ignoring.\n");
701 }
702 }
703
704 if (pdev->Linearise && pdev->is_ps2write) {
705 emprintf(pdev->memory, "Can't linearise PostScript output, ignoring\n");
706 pdev->Linearise = false;
707 }
708
709 if (pdev->Linearise && pdev->OwnerPassword.size != 0) {
710 emprintf(pdev->memory, "Can't linearise encrypted PDF, ignoring\n");
711 pdev->Linearise = false;
712 }
713
714 if (pdev->FlattenFonts)
715 pdev->PreserveTrMode = false;
716 return 0;
717 fail:
718 /* Restore all the parameters to their original state. */
719 pdev->version = save_dev->version;
720 pdf_set_process_color_model(pdev, save_dev->pcm_color_info_index);
721 pdev->saved_fill_color = save_dev->saved_fill_color;
722 pdev->saved_stroke_color = save_dev->saved_fill_color;
723 {
724 const gs_param_item_t *ppi = pdf_param_items;
725
726 for (; ppi->key; ++ppi)
727 memcpy((char *)pdev + ppi->offset,
728 (char *)save_dev + ppi->offset,
729 gs_param_type_sizes[ppi->type]);
730 pdev->ForOPDFRead = save_dev->ForOPDFRead;
731 }
732 return ecode;
733 }
734
735 /* Put parameters */
736 int
gdev_pdf_put_params(gx_device * dev,gs_param_list * plist)737 gdev_pdf_put_params(gx_device * dev, gs_param_list * plist)
738 {
739 int code;
740 gx_device_pdf *pdev = (gx_device_pdf *) dev;
741 gs_memory_t *mem = gs_memory_stable(pdev->memory);
742 gx_device_pdf *save_dev = gs_malloc(mem, sizeof(gx_device_pdf), 1,
743 "saved gx_device_pdf");
744
745 if (!save_dev)
746 return_error(gs_error_VMerror);
747 memcpy(save_dev, pdev, sizeof(gx_device_pdf));
748 code = gdev_pdf_put_params_impl(dev, save_dev, plist);
749 gs_free(mem, save_dev, sizeof(gx_device_pdf), 1, "saved gx_device_pdf");
750 return code;
751 }
752
753 /* ---------------- Process DSC comments ---------------- */
754
755 /* Bug #695850 DSC comments are not actually encoded, nor are they PostScript strings
756 * they are simply a sequence of bytes. SO it would seem we should just preserve that
757 * byte sequence. Bizarrely, Distiller treats the comment as 'almost' a PostScript
758 * string. In particular it converts octal codes into an equivalent binary byte. It
759 * also converts (eg) '\n' and '\r' into 'n' and 'r' and invalid octal escapes
760 * (eg \11) simply have the '\' turned into a '?'.
761 * We think this is nuts and have no intention of trying to mimic it precisely. This
762 * routine will find octal escapes and convert them into binary. The way this works is
763 * a little obscure. The DSC parser does convert the comment into a PostScript string
764 * and so has to escape any unusual characters. This means our octal escaped values in
765 * the original DSC comment have had the escape character ('\') escaped to become '\\'.
766 * All we need to do is remove the escape of the escape and we will end up with a
767 * properly escaped PostScript string.
768 */
unescape_octals(gx_device_pdf * pdev,char * src,int size)769 static int unescape_octals(gx_device_pdf * pdev, char *src, int size)
770 {
771 char *start, *dest;
772
773 start = src;
774 dest = src;
775
776 while(size) {
777 if (size > 4 && src[0] == '\\' && src[1] == '\\' &&
778 src[2] > 0x29 && src[2] < 0x35 &&
779 src[3] > 0x29 &&src[3] < 0x38 &&
780 src[4] > 0x29 && src[4] < 0x38) {
781 src++;
782 size--;
783 } else {
784 *dest++ = *src++;
785 size--;
786 }
787 }
788 return (dest - start);
789 }
790
791 static int
pdf_dsc_process(gx_device_pdf * pdev,const gs_param_string_array * pma)792 pdf_dsc_process(gx_device_pdf * pdev, const gs_param_string_array * pma)
793 {
794 /*
795 * The Adobe "Distiller Parameters" documentation says that Distiller
796 * looks at DSC comments, but it doesn't say which ones. We look at
797 * the ones that we see how to map directly to obvious PDF constructs.
798 */
799 int code = 0;
800 uint i;
801
802 /*
803 * If ParseDSCComments is false, all DSC comments are ignored, even if
804 * ParseDSCComentsForDocInfo or PreserveEPSInfo is true.
805 */
806 if (!pdev->ParseDSCComments)
807 return 0;
808
809 for (i = 0; i + 1 < pma->size && code >= 0; i += 2) {
810 const gs_param_string *pkey = &pma->data[i];
811 gs_param_string *pvalue = (gs_param_string *)&pma->data[i + 1];
812 const char *key;
813 int newsize;
814
815 /*
816 * %%For, %%Creator, and %%Title are recognized only if either
817 * ParseDSCCommentsForDocInfo or PreserveEPSInfo is true.
818 * The other DSC comments are always recognized.
819 *
820 * Acrobat Distiller sets CreationDate and ModDate to the current
821 * time, not the value of %%CreationDate. We think this is wrong,
822 * but we do the same -- we ignore %%CreationDate here.
823 */
824
825 if (pdf_key_eq(pkey, "Creator") && pdev->CompatibilityLevel <= 1.7) {
826 key = "/Creator";
827 newsize = unescape_octals(pdev, (char *)pvalue->data, pvalue->size);
828 code = cos_dict_put_c_key_string(pdev->Info, key,
829 pvalue->data, newsize);
830 continue;
831 } else if (pdf_key_eq(pkey, "Title") && pdev->CompatibilityLevel <= 1.7) {
832 key = "/Title";
833 newsize = unescape_octals(pdev, (char *)pvalue->data, pvalue->size);
834 code = cos_dict_put_c_key_string(pdev->Info, key,
835 pvalue->data, newsize);
836 continue;
837 } else if (pdf_key_eq(pkey, "For") && pdev->CompatibilityLevel <= 1.7) {
838 key = "/Author";
839 newsize = unescape_octals(pdev, (char *)pvalue->data, pvalue->size);
840 code = cos_dict_put_c_key_string(pdev->Info, key,
841 pvalue->data, newsize);
842 continue;
843 } else {
844 pdf_page_dsc_info_t *ppdi;
845 char scan_buf[200]; /* arbitrary */
846
847 if ((ppdi = &pdev->doc_dsc_info,
848 pdf_key_eq(pkey, "Orientation")) ||
849 (ppdi = &pdev->page_dsc_info,
850 pdf_key_eq(pkey, "PageOrientation"))
851 ) {
852 if (pvalue->size == 1 && pvalue->data[0] >= '0' &&
853 pvalue->data[0] <= '3'
854 )
855 ppdi->orientation = pvalue->data[0] - '0';
856 else
857 ppdi->orientation = -1;
858 } else if ((ppdi = &pdev->doc_dsc_info,
859 pdf_key_eq(pkey, "ViewingOrientation")) ||
860 (ppdi = &pdev->page_dsc_info,
861 pdf_key_eq(pkey, "PageViewingOrientation"))
862 ) {
863 gs_matrix mat;
864 int orient;
865
866 if(pvalue->size >= sizeof(scan_buf) - 1)
867 continue; /* error */
868 memcpy(scan_buf, pvalue->data, pvalue->size);
869 scan_buf[pvalue->size] = 0;
870 if (sscanf(scan_buf, "[%g %g %g %g]",
871 &mat.xx, &mat.xy, &mat.yx, &mat.yy) != 4
872 )
873 continue; /* error */
874 for (orient = 0; orient < 4; ++orient) {
875 if (mat.xx == 1 && mat.xy == 0 && mat.yx == 0 && mat.yy == 1)
876 break;
877 gs_matrix_rotate(&mat, -90.0, &mat);
878 }
879 if (orient == 4) /* error */
880 orient = -1;
881 ppdi->viewing_orientation = orient;
882 } else {
883 gs_rect box;
884
885 if (pdf_key_eq(pkey, "EPSF")) {
886 pdev->is_EPS = (pvalue->size >= 1 && pvalue->data[0] != '0');
887 continue;
888 }
889 /*
890 * We only parse the BoundingBox for the sake of
891 * AutoPositionEPSFiles.
892 */
893 if (pdf_key_eq(pkey, "BoundingBox"))
894 ppdi = &pdev->doc_dsc_info;
895 else if (pdf_key_eq(pkey, "PageBoundingBox"))
896 ppdi = &pdev->page_dsc_info;
897 else
898 continue;
899 if(pvalue->size >= sizeof(scan_buf) - 1)
900 continue; /* error */
901 memcpy(scan_buf, pvalue->data, pvalue->size);
902 scan_buf[pvalue->size] = 0;
903 if (sscanf(scan_buf, "[%lg %lg %lg %lg]",
904 &box.p.x, &box.p.y, &box.q.x, &box.q.y) != 4
905 )
906 continue; /* error */
907 ppdi->bounding_box = box;
908 }
909 continue;
910 }
911 }
912 return code;
913 }
914