1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
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.
14
/* $Id: gdevpdfp.c 8250 2007-09-25 13:31:24Z giles $ */
15
/* Get/put parameters for PDF-writing driver */
26
* The pdfwrite device supports the following "real" parameters:
28
* all the Distiller parameters (also see gdevpsdp.c)
29
* Only some of the Distiller parameters actually have any effect.
31
* The device also supports the following write-only pseudo-parameters that
32
* serve only to communicate other information from the PostScript file.
33
* Their "value" is an array of strings, some of which may be the result
34
* of converting arbitrary PostScript objects to string form.
35
* pdfmark - see gdevpdfm.c
36
* DSC - processed in this file
38
static int pdf_dsc_process(gx_device_pdf * pdev,
39
const gs_param_string_array * pma);
41
static const int CoreDistVersion = 5000; /* Distiller 5.0 */
42
static const gs_param_item_t pdf_param_items[] = {
43
#define pi(key, type, memb) { key, type, offset_of(gx_device_pdf, memb) }
45
/* Acrobat Distiller 4 parameters */
48
* EndPage and StartPage are renamed because EndPage collides with
49
* a page device parameter.
51
pi("PDFEndPage", gs_param_type_int, EndPage),
52
pi("PDFStartPage", gs_param_type_int, StartPage),
53
pi("Optimize", gs_param_type_bool, Optimize),
54
pi("ParseDSCCommentsForDocInfo", gs_param_type_bool,
55
ParseDSCCommentsForDocInfo),
56
pi("ParseDSCComments", gs_param_type_bool, ParseDSCComments),
57
pi("EmitDSCWarnings", gs_param_type_bool, EmitDSCWarnings),
58
pi("CreateJobTicket", gs_param_type_bool, CreateJobTicket),
59
pi("PreserveEPSInfo", gs_param_type_bool, PreserveEPSInfo),
60
pi("AutoPositionEPSFiles", gs_param_type_bool, AutoPositionEPSFiles),
61
pi("PreserveCopyPage", gs_param_type_bool, PreserveCopyPage),
62
pi("UsePrologue", gs_param_type_bool, UsePrologue),
64
/* Acrobat Distiller 5 parameters */
66
pi("OffOptimizations", gs_param_type_int, OffOptimizations),
68
/* Ghostscript-specific parameters */
70
pi("ReAssignCharacters", gs_param_type_bool, ReAssignCharacters),
71
pi("ReEncodeCharacters", gs_param_type_bool, ReEncodeCharacters),
72
pi("FirstObjectNumber", gs_param_type_long, FirstObjectNumber),
73
pi("CompressFonts", gs_param_type_bool, CompressFonts),
74
pi("PrintStatistics", gs_param_type_bool, PrintStatistics),
75
pi("MaxInlineImageSize", gs_param_type_long, MaxInlineImageSize),
76
pi("DSCEncodingToUnicode", gs_param_type_int_array, DSCEncodingToUnicode),
79
pi("OwnerPassword", gs_param_type_string, OwnerPassword),
80
pi("UserPassword", gs_param_type_string, UserPassword),
81
pi("KeyLength", gs_param_type_int, KeyLength),
82
pi("Permissions", gs_param_type_int, Permissions),
83
pi("EncryptionR", gs_param_type_int, EncryptionR),
84
pi("NoEncrypt", gs_param_type_string, NoEncrypt),
86
/* Target viewer capabilities (Ghostscript-specific) */
87
/* pi("ForOPDFRead", gs_param_type_bool, ForOPDFRead), pdfwrite-only */
88
pi("PatternImagemask", gs_param_type_bool, PatternImagemask),
89
pi("MaxClipPathSize", gs_param_type_int, MaxClipPathSize),
90
pi("MaxShadingBitmapSize", gs_param_type_int, MaxShadingBitmapSize),
91
pi("MaxViewerMemorySize", gs_param_type_int, MaxViewerMemorySize),
92
pi("HaveTrueTypes", gs_param_type_bool, HaveTrueTypes),
93
pi("HaveCIDSystem", gs_param_type_bool, HaveCIDSystem),
94
pi("HaveTransparency", gs_param_type_bool, HaveTransparency),
95
/* pi("OPDFReadProcsetPath", gs_param_type_string, OPDFReadProcsetPath), ps2write-only */
96
pi("CompressEntireFile", gs_param_type_bool, CompressEntireFile),
97
pi("PDFX", gs_param_type_bool, PDFX),
98
pi("PDFA", gs_param_type_bool, PDFA),
99
pi("DocumentUUID", gs_param_type_string, DocumentUUID),
100
pi("InstanceUUID", gs_param_type_string, InstanceUUID),
101
pi("DocumentTimeSeq", gs_param_type_int, DocumentTimeSeq),
103
/* PDF/X parameters */
104
pi("PDFXTrimBoxToMediaBoxOffset", gs_param_type_float_array, PDFXTrimBoxToMediaBoxOffset),
105
pi("PDFXSetBleedBoxToMediaBox", gs_param_type_bool, PDFXSetBleedBoxToMediaBox),
106
pi("PDFXBleedBoxToTrimBoxOffset", gs_param_type_float_array, PDFXBleedBoxToTrimBoxOffset),
112
Notes on implementing the remaining Distiller functionality
113
===========================================================
118
Must optionally disable application of TR, BG, UCR similarly. Affects:
120
PreserveOverprintSettings
127
Non-primary elements in HalftoneType 5 are not written correctly
132
---- Image parameters ----
134
AntiAlias{Color,Gray,Mono}Images
136
---- Other parameters ----
139
Compress things other than page contents
140
* PreserveHalftoneInfo
143
* PreserveOverprintSettings
144
* TransferFunctionInfo
146
ColorConversionStrategy
147
Select color space for drawing commands
148
ConvertImagesToIndexed
149
Postprocess image data *after* downsampling (requires an extra pass)
154
---- Other functionality ----
156
Document structure pdfmarks
160
xxxDownsampleType = /Bicubic
161
Add new filter (or use siscale?) & to setup (gdevpsdi.c)
163
Idiom recognition? PatternType 2 patterns / shfill? (see AD4)
165
Also output to memory device -- resolution issue
167
---- Job-level control ----
170
Require DSC parser / interceptor
176
Concatenate Contents streams
178
Needs hack in top-level control?
182
/* ---------------- Get parameters ---------------- */
184
/* Get parameters. */
186
gdev_pdf_get_params(gx_device * dev, gs_param_list * plist)
188
gx_device_pdf *pdev = (gx_device_pdf *) dev;
189
float cl = (float)pdev->CompatibilityLevel;
191
int cdv = CoreDistVersion;
192
int EmbedFontObjects = 1;
194
pdev->ParamCompatibilityLevel = cl;
195
code = gdev_psdf_get_params(dev, plist);
197
(code = param_write_int(plist, ".EmbedFontObjects", &EmbedFontObjects)) < 0 ||
198
(code = param_write_int(plist, "CoreDistVersion", &cdv)) < 0 ||
199
(code = param_write_float(plist, "CompatibilityLevel", &cl)) < 0 ||
200
(pdev->is_ps2write && (code = param_write_string(plist, "OPDFReadProcsetPath", &pdev->OPDFReadProcsetPath)) < 0) ||
201
(!pdev->is_ps2write && (code = param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0) ||
202
/* Indicate that we can process pdfmark and DSC. */
203
(param_requested(plist, "pdfmark") > 0 &&
204
(code = param_write_null(plist, "pdfmark")) < 0) ||
205
(param_requested(plist, "DSC") > 0 &&
206
(code = param_write_null(plist, "DSC")) < 0) ||
207
(code = gs_param_write_items(plist, pdev, NULL, pdf_param_items)) < 0
212
/* ---------------- Put parameters ---------------- */
214
/* Put parameters, implementation */
216
gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_param_list * plist)
219
gx_device_pdf *pdev = (gx_device_pdf *) dev;
220
float cl = (float)pdev->CompatibilityLevel;
221
bool locked = pdev->params.LockDistillerParams;
222
gs_param_name param_name;
223
enum psdf_color_conversion_strategy save_ccs = pdev->params.ColorConversionStrategy;
225
pdev->pdf_memory = gs_memory_stable(pdev->memory);
227
* If this is a pseudo-parameter (pdfmark or DSC),
228
* don't bother checking for any real ones.
232
gs_param_string_array ppa;
234
code = param_read_string_array(plist, (param_name = "pdfmark"), &ppa);
237
code = pdf_open_document(pdev);
240
code = pdfmark_process(pdev, &ppa);
243
/* falls through for errors */
245
param_signal_error(plist, param_name, code);
251
code = param_read_string_array(plist, (param_name = "DSC"), &ppa);
254
code = pdf_open_document(pdev);
257
code = pdf_dsc_process(pdev, &ppa);
260
/* falls through for errors */
262
param_signal_error(plist, param_name, code);
270
* Check for LockDistillerParams before doing anything else.
271
* If LockDistillerParams is true and is not being set to false,
272
* ignore all resettings of PDF-specific parameters. Note that
273
* LockDistillerParams is read again, and reset if necessary, in
276
ecode = code = param_read_bool(plist, "LockDistillerParams", &locked);
278
if (!(locked && pdev->params.LockDistillerParams)) {
279
/* General parameters. */
284
ecode = param_put_int(plist, (param_name = ".EmbedFontObjects"), &efo, ecode);
286
param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
289
int cdv = CoreDistVersion;
291
ecode = param_put_int(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
292
if (cdv != CoreDistVersion)
293
param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
296
switch (code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl)) {
299
param_signal_error(plist, param_name, ecode);
302
* Must be 1.2, 1.3, 1.4, or 1.5. Per Adobe documentation, substitute
303
* the nearest achievable value.
305
if (cl < (float)1.15)
307
else if (cl < (float)1.25)
309
else if (cl < (float)1.35)
311
else if (cl < (float)1.45)
318
{ /* HACK : gs_param_list_s::memory is documented in gsparam.h as
319
"for allocating coerced arrays". Not sure why zputdeviceparams
320
sets it to the current memory space, while the device
321
assumes to store them in the device's memory space.
322
As a hackish workaround we temporary replace it here.
323
Doing so because we don't want to change the global code now
324
because we're unable to test it with all devices.
325
Bug 688531 "Segmentation fault running pdfwrite from 219-01.ps".
327
This solution to be reconsidered after fixing
328
the bug 688533 "zputdeviceparams specifies a wrong memory space.".
330
gs_memory_t *mem = plist->memory;
332
plist->memory = pdev->pdf_memory;
333
code = gs_param_read_items(plist, pdev, pdf_param_items);
335
(pdev->is_ps2write && (code = param_read_string(plist, "OPDFReadProcsetPath", &pdev->OPDFReadProcsetPath)) < 0) ||
336
(!pdev->is_ps2write && (code = param_read_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead)) < 0)
344
* Setting FirstObjectNumber is only legal if the file
345
* has just been opened and nothing has been written,
346
* or if we are setting it to the same value.
348
long fon = pdev->FirstObjectNumber;
350
if (fon != save_dev->FirstObjectNumber) {
351
if (fon <= 0 || fon > 0x7fff0000 ||
352
(pdev->next_id != 0 &&
354
save_dev->FirstObjectNumber + pdf_num_initial_ids)
356
ecode = gs_error_rangecheck;
357
param_signal_error(plist, "FirstObjectNumber", ecode);
363
* Set ProcessColorModel now, because gx_default_put_params checks
366
static const char *const pcm_names[] = {
367
"DeviceGray", "DeviceRGB", "DeviceCMYK", "DeviceN", 0
371
ecode = param_put_enum(plist, "ProcessColorModel", &pcm,
374
pdf_set_process_color_model(pdev, pcm);
375
pdf_set_initial_color(pdev, &pdev->saved_fill_color, &pdev->saved_stroke_color,
376
&pdev->fill_used_process_color, &pdev->stroke_used_process_color);
382
if (pdev->PDFX && pdev->PDFA) {
383
ecode = gs_note_error(gs_error_rangecheck);
384
param_signal_error(plist, "PDFA", ecode);
387
if (pdev->PDFX && pdev->ForOPDFRead) {
388
ecode = gs_note_error(gs_error_rangecheck);
389
param_signal_error(plist, "PDFX", ecode);
392
if (pdev->PDFA && pdev->ForOPDFRead) {
393
ecode = gs_note_error(gs_error_rangecheck);
394
param_signal_error(plist, "PDFA", ecode);
398
pdev->HaveTransparency = false;
400
* We have to set version to the new value, because the set of
401
* legal parameter values for psdf_put_params varies according to
405
cl = (float)1.3; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
406
if (pdev->PDFA && cl < 1.4)
408
pdev->version = (cl < 1.2 ? psdf_version_level2 : psdf_version_ll3);
409
if (pdev->ForOPDFRead) {
410
pdev->ResourcesBeforeUsage = true;
411
pdev->HaveCFF = false;
412
pdev->HavePDFWidths = false;
413
pdev->HaveStrokeColor = false;
414
cl = (float)1.2; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
415
pdev->MaxInlineImageSize = max_long; /* Save printer's RAM from saving temporary image data.
416
Immediate images doen't need buffering. */
417
pdev->version = psdf_version_level2;
419
pdev->ResourcesBeforeUsage = false;
420
pdev->HaveCFF = true;
421
pdev->HavePDFWidths = true;
422
pdev->HaveStrokeColor = true;
424
pdev->ParamCompatibilityLevel = cl;
425
ecode = gdev_psdf_put_params(dev, plist);
428
if ((pdev->params.ColorConversionStrategy == ccs_CMYK &&
429
strcmp(pdev->color_info.cm_name, "DeviceCMYK")) ||
430
(pdev->params.ColorConversionStrategy == ccs_sRGB &&
431
strcmp(pdev->color_info.cm_name, "DeviceRGB")) ||
432
(pdev->params.ColorConversionStrategy == ccs_Gray &&
433
strcmp(pdev->color_info.cm_name, "DeviceGray"))) {
434
eprintf("ColorConversionStrategy is incompatible to ProcessColorModel.\n");
435
ecode = gs_note_error(gs_error_rangecheck);
436
pdev->params.ColorConversionStrategy = save_ccs;
438
if (pdev->params.ColorConversionStrategy == ccs_UseDeviceIndependentColor) {
439
if (!pdev->UseCIEColor) {
440
eprintf("Set UseCIEColor for UseDeviceIndependentColor to work properly.\n");
441
ecode = gs_note_error(gs_error_rangecheck);
442
pdev->UseCIEColor = true;
445
if (pdev->params.ColorConversionStrategy == ccs_UseDeviceIndependentColorForImages) {
446
if (!pdev->UseCIEColor) {
447
eprintf("UseDeviceDependentColorForImages is not supported. Use UseDeviceIndependentColor.\n");
448
pdev->params.ColorConversionStrategy = ccs_UseDeviceIndependentColor;
449
if (!pdev->UseCIEColor) {
450
eprintf("Set UseCIEColor for UseDeviceIndependentColor to work properly.\n");
451
ecode = gs_note_error(gs_error_rangecheck);
452
pdev->UseCIEColor = true;
456
if (pdev->params.ColorConversionStrategy == ccs_UseDeviceDependentColor) {
457
if (!strcmp(pdev->color_info.cm_name, "DeviceCMYK")) {
458
eprintf("Replacing the deprecated device parameter value UseDeviceDependentColor with CMYK.\n");
459
pdev->params.ColorConversionStrategy = ccs_CMYK;
460
} else if (!strcmp(pdev->color_info.cm_name, "DeviceRGB")) {
461
eprintf("Replacing the deprecated device parameter value UseDeviceDependentColor with sRGB.\n");
462
pdev->params.ColorConversionStrategy = ccs_sRGB;
464
eprintf("Replacing the deprecated device parameter value UseDeviceDependentColor with Gray.\n");
465
pdev->params.ColorConversionStrategy = ccs_Gray;
468
if (cl < 1.5 && pdev->params.ColorImage.Filter != NULL &&
469
!strcmp(pdev->params.ColorImage.Filter, "JPXEncode")) {
470
eprintf("JPXEncode requires CompatibilityLevel >= 1.5 .\n");
471
ecode = gs_note_error(gs_error_rangecheck);
473
if (cl < 1.5 && pdev->params.GrayImage.Filter != NULL &&
474
!strcmp(pdev->params.GrayImage.Filter, "JPXEncode")) {
475
eprintf("JPXEncode requires CompatibilityLevel >= 1.5 .\n");
476
ecode = gs_note_error(gs_error_rangecheck);
478
if (cl < 1.4 && pdev->params.MonoImage.Filter != NULL &&
479
!strcmp(pdev->params.MonoImage.Filter, "JBIG2Encode")) {
480
eprintf("JBIG2Encode requires CompatibilityLevel >= 1.4 .\n");
481
ecode = gs_note_error(gs_error_rangecheck);
483
if (pdev->HaveTrueTypes && pdev->version == psdf_version_level2) {
484
pdev->version = psdf_version_level2_with_TT ;
487
* Acrobat Reader doesn't handle user-space coordinates larger than
488
* MAX_USER_COORD. To compensate for this, reduce the resolution so
489
* that the page size in device space (which we equate to user space) is
490
* significantly less than MAX_USER_COORD. Note that this still does
491
* not protect us against input files that use coordinates far outside
492
* the page boundaries.
494
#define MAX_EXTENT ((int)(MAX_USER_COORD * 0.9))
495
/* Changing resolution or page size requires closing the device, */
496
if (dev->height > MAX_EXTENT || dev->width > MAX_EXTENT) {
498
max(dev->height / (double)MAX_EXTENT,
499
dev->width / (double)MAX_EXTENT);
501
gx_device_set_resolution(dev, dev->HWResolution[0] / factor,
502
dev->HWResolution[1] / factor);
505
if (pdev->FirstObjectNumber != save_dev->FirstObjectNumber) {
506
if (pdev->xref.file != 0) {
507
fseek(pdev->xref.file, 0L, SEEK_SET);
508
pdf_initialize_ids(pdev);
511
/* Handle the float/double mismatch. */
512
pdev->CompatibilityLevel = (int)(cl * 10 + 0.5) / 10.0;
515
/* Restore all the parameters to their original state. */
516
pdev->version = save_dev->version;
517
pdf_set_process_color_model(pdev, save_dev->pcm_color_info_index);
518
pdev->saved_fill_color = save_dev->saved_fill_color;
519
pdev->saved_stroke_color = save_dev->saved_fill_color;
521
const gs_param_item_t *ppi = pdf_param_items;
523
for (; ppi->key; ++ppi)
524
memcpy((char *)pdev + ppi->offset,
525
(char *)save_dev + ppi->offset,
526
gs_param_type_sizes[ppi->type]);
527
pdev->ForOPDFRead = save_dev->ForOPDFRead;
528
pdev->OPDFReadProcsetPath = save_dev->OPDFReadProcsetPath;
535
gdev_pdf_put_params(gx_device * dev, gs_param_list * plist)
538
gx_device_pdf *pdev = (gx_device_pdf *) dev;
539
gs_memory_t *mem = gs_memory_stable(pdev->memory);
540
gx_device_pdf *save_dev = gs_malloc(mem, sizeof(gx_device_pdf), 1,
541
"saved gx_device_pdf");
544
return_error(gs_error_VMerror);
545
memcpy(save_dev, pdev, sizeof(gx_device_pdf));
546
code = gdev_pdf_put_params_impl(dev, save_dev, plist);
547
gs_free(mem, save_dev, sizeof(gx_device_pdf), 1, "saved gx_device_pdf");
551
/* ---------------- Process DSC comments ---------------- */
554
pdf_dsc_process(gx_device_pdf * pdev, const gs_param_string_array * pma)
557
* The Adobe "Distiller Parameters" documentation says that Distiller
558
* looks at DSC comments, but it doesn't say which ones. We look at
559
* the ones that we see how to map directly to obvious PDF constructs.
565
* If ParseDSCComments is false, all DSC comments are ignored, even if
566
* ParseDSCComentsForDocInfo or PreserveEPSInfo is true.
568
if (!pdev->ParseDSCComments)
571
for (i = 0; i + 1 < pma->size && code >= 0; i += 2) {
572
const gs_param_string *pkey = &pma->data[i];
573
const gs_param_string *pvalue = &pma->data[i + 1];
578
* %%For, %%Creator, and %%Title are recognized only if either
579
* ParseDSCCommentsForDocInfo or PreserveEPSInfo is true.
580
* The other DSC comments are always recognized.
582
* Acrobat Distiller sets CreationDate and ModDate to the current
583
* time, not the value of %%CreationDate. We think this is wrong,
584
* but we do the same -- we ignore %%CreationDate here.
587
if (pdf_key_eq(pkey, "Creator"))
589
else if (pdf_key_eq(pkey, "Title"))
591
else if (pdf_key_eq(pkey, "For"))
594
pdf_page_dsc_info_t *ppdi;
595
char scan_buf[200]; /* arbitrary */
597
if ((ppdi = &pdev->doc_dsc_info,
598
pdf_key_eq(pkey, "Orientation")) ||
599
(ppdi = &pdev->page_dsc_info,
600
pdf_key_eq(pkey, "PageOrientation"))
602
if (pvalue->size == 1 && pvalue->data[0] >= '0' &&
603
pvalue->data[0] <= '3'
605
ppdi->orientation = pvalue->data[0] - '0';
607
ppdi->orientation = -1;
608
} else if ((ppdi = &pdev->doc_dsc_info,
609
pdf_key_eq(pkey, "ViewingOrientation")) ||
610
(ppdi = &pdev->page_dsc_info,
611
pdf_key_eq(pkey, "PageViewingOrientation"))
616
if(pvalue->size >= sizeof(scan_buf) - 1)
617
continue; /* error */
618
memcpy(scan_buf, pvalue->data, pvalue->size);
619
scan_buf[pvalue->size] = 0;
620
if (sscanf(scan_buf, "[%g %g %g %g]",
621
&mat.xx, &mat.xy, &mat.yx, &mat.yy) != 4
623
continue; /* error */
624
for (orient = 0; orient < 4; ++orient) {
625
if (mat.xx == 1 && mat.xy == 0 && mat.yx == 0 && mat.yy == 1)
627
gs_matrix_rotate(&mat, -90.0, &mat);
629
if (orient == 4) /* error */
631
ppdi->viewing_orientation = orient;
635
if (pdf_key_eq(pkey, "EPSF")) {
636
pdev->is_EPS = (pvalue->size >= 1 && pvalue->data[0] != '0');
640
* We only parse the BoundingBox for the sake of
641
* AutoPositionEPSFiles.
643
if (pdf_key_eq(pkey, "BoundingBox"))
644
ppdi = &pdev->doc_dsc_info;
645
else if (pdf_key_eq(pkey, "PageBoundingBox"))
646
ppdi = &pdev->page_dsc_info;
649
if(pvalue->size >= sizeof(scan_buf) - 1)
650
continue; /* error */
651
memcpy(scan_buf, pvalue->data, pvalue->size);
652
scan_buf[pvalue->size] = 0;
653
if (sscanf(scan_buf, "[%lg %lg %lg %lg]",
654
&box.p.x, &box.p.y, &box.q.x, &box.q.y) != 4
656
continue; /* error */
657
ppdi->bounding_box = box;
662
if (pdev->ParseDSCCommentsForDocInfo || pdev->PreserveEPSInfo)
663
code = cos_dict_put_c_key_string(pdev->Info, key,
664
pvalue->data, pvalue->size);