Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1996, 2000, 2001 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gdevpdfp.c,v 1.53 2005/09/12 11:34:50 leonardo Exp $ */
18
/* Get/put parameters for PDF-writing driver */
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gdevpdfx.h"
24
#include "gdevpdfo.h"
25
#include "gdevpdfg.h"
26
#include "gsparamx.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
private int pdf_dsc_process(gx_device_pdf * pdev,
42
			    const gs_param_string_array * pma);
43
 
44
private const int CoreDistVersion = 5000;	/* Distiller 5.0 */
45
private 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("PrintStatistics", gs_param_type_bool, PrintStatistics),
78
    pi("MaxInlineImageSize", gs_param_type_long, MaxInlineImageSize),
79
 
80
	/* PDF Encryption */
81
    pi("OwnerPassword", gs_param_type_string, OwnerPassword),
82
    pi("UserPassword", gs_param_type_string, UserPassword),
83
    pi("KeyLength", gs_param_type_int, KeyLength),
84
    pi("Permissions", gs_param_type_int, Permissions),
85
    pi("EncryptionR", gs_param_type_int, EncryptionR),
86
    pi("NoEncrypt", gs_param_type_string, NoEncrypt),
87
 
88
	/* Target viewer capabilities (Ghostscript-specific)  */
89
    pi("ForOPDFRead", gs_param_type_bool, ForOPDFRead),
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
    pi("MaxViewerMemorySize", gs_param_type_int, MaxViewerMemorySize),
94
    pi("HaveTrueTypes", gs_param_type_bool, HaveTrueTypes),
95
    pi("HaveCIDSystem", gs_param_type_bool, HaveCIDSystem),
96
    pi("HaveTransparency", gs_param_type_bool, HaveTransparency),
97
    pi("OPDFReadProcsetPath", gs_param_type_string, OPDFReadProcsetPath),
98
    pi("CompressEntireFile", gs_param_type_bool, CompressEntireFile),
99
    pi("PDFX", gs_param_type_bool, PDFX),
100
#undef pi
101
    gs_param_item_end
102
};
103
 
104
/*
105
  Notes on implementing the remaining Distiller functionality
106
  ===========================================================
107
 
108
  Architectural issues
109
  --------------------
110
 
111
  Must optionally disable application of TR, BG, UCR similarly.  Affects:
112
    PreserveHalftoneInfo
113
    PreserveOverprintSettings
114
    TransferFunctionInfo
115
    UCRandBGInfo
116
 
117
  Current limitations
118
  -------------------
119
 
120
  Non-primary elements in HalftoneType 5 are not written correctly
121
 
122
  Acrobat Distiller 3
123
  -------------------
124
 
125
  ---- Image parameters ----
126
 
127
  AntiAlias{Color,Gray,Mono}Images
128
 
129
  ---- Other parameters ----
130
 
131
  CompressPages
132
    Compress things other than page contents
133
  * PreserveHalftoneInfo
134
  PreserveOPIComments
135
    ? see OPI spec?
136
  * PreserveOverprintSettings
137
  * TransferFunctionInfo
138
  * UCRandBGInfo
139
  ColorConversionStrategy
140
    Select color space for drawing commands
141
  ConvertImagesToIndexed
142
    Postprocess image data *after* downsampling (requires an extra pass)
143
 
144
  Acrobat Distiller 4
145
  -------------------
146
 
147
  ---- Other functionality ----
148
 
149
  Document structure pdfmarks
150
 
151
  ---- Parameters ----
152
 
153
  xxxDownsampleType = /Bicubic
154
    Add new filter (or use siscale?) & to setup (gdevpsdi.c)
155
  DetectBlends
156
    Idiom recognition?  PatternType 2 patterns / shfill?  (see AD4)
157
  DoThumbnails
158
    Also output to memory device -- resolution issue
159
 
160
  ---- Job-level control ----
161
 
162
  EmitDSCWarnings
163
    Require DSC parser / interceptor
164
  CreateJobTicket
165
    ?
166
  AutoPositionEPSFiles
167
    Require DSC parsing
168
  PreserveCopyPage
169
    Concatenate Contents streams
170
  UsePrologue
171
    Needs hack in top-level control?
172
 
173
*/
174
 
175
/* ---------------- Get parameters ---------------- */
176
 
177
/* Get parameters. */
178
int
179
gdev_pdf_get_params(gx_device * dev, gs_param_list * plist)
180
{
181
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
182
    float cl = (float)pdev->CompatibilityLevel;
183
    int code = gdev_psdf_get_params(dev, plist);
184
    int cdv = CoreDistVersion;
185
    int EmbedFontObjects = 1;
186
 
187
    if (code < 0 ||
188
	(code = param_write_int(plist, ".EmbedFontObjects", &EmbedFontObjects)) < 0 ||
189
	(code = param_write_int(plist, "CoreDistVersion", &cdv)) < 0 ||
190
	(code = param_write_float(plist, "CompatibilityLevel", &cl)) < 0 ||
191
	/* Indicate that we can process pdfmark and DSC. */
192
	(param_requested(plist, "pdfmark") > 0 &&
193
	 (code = param_write_null(plist, "pdfmark")) < 0) ||
194
	(param_requested(plist, "DSC") > 0 &&
195
	 (code = param_write_null(plist, "DSC")) < 0) ||
196
	(code = gs_param_write_items(plist, pdev, NULL, pdf_param_items)) < 0
197
	);
198
    return code;
199
}
200
 
201
/* ---------------- Put parameters ---------------- */
202
 
203
/* Put parameters. */
204
int
205
gdev_pdf_put_params(gx_device * dev, gs_param_list * plist)
206
{
207
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
208
    int ecode, code;
209
    gx_device_pdf save_dev;
210
    float cl = (float)pdev->CompatibilityLevel;
211
    bool locked = pdev->params.LockDistillerParams;
212
    gs_param_name param_name;
213
 
214
    /*
215
     * If this is a pseudo-parameter (pdfmark or DSC),
216
     * don't bother checking for any real ones.
217
     */
218
 
219
    {
220
	gs_param_string_array ppa;
221
 
222
	code = param_read_string_array(plist, (param_name = "pdfmark"), &ppa);
223
	switch (code) {
224
	    case 0:
225
		code = pdf_open_document(pdev);
226
		if (code < 0)
227
		    return code;
228
		code = pdfmark_process(pdev, &ppa);
229
		if (code >= 0)
230
		    return code;
231
		/* falls through for errors */
232
	    default:
233
		param_signal_error(plist, param_name, code);
234
		return code;
235
	    case 1:
236
		break;
237
	}
238
 
239
	code = param_read_string_array(plist, (param_name = "DSC"), &ppa);
240
	switch (code) {
241
	    case 0:
242
		code = pdf_open_document(pdev);
243
		if (code < 0)
244
		    return code;
245
		code = pdf_dsc_process(pdev, &ppa);
246
		if (code >= 0)
247
		    return code;
248
		/* falls through for errors */
249
	    default:
250
		param_signal_error(plist, param_name, code);
251
		return code;
252
	    case 1:
253
		break;
254
	}
255
    }
256
 
257
    /*
258
     * Check for LockDistillerParams before doing anything else.
259
     * If LockDistillerParams is true and is not being set to false,
260
     * ignore all resettings of PDF-specific parameters.  Note that
261
     * LockDistillerParams is read again, and reset if necessary, in
262
     * psdf_put_params.
263
     */
264
    ecode = code = param_read_bool(plist, "LockDistillerParams", &locked);
265
 
266
    if (!(locked && pdev->params.LockDistillerParams)) {
267
	/* General parameters. */
268
 
269
	{
270
	    int efo = 1;
271
 
272
	    ecode = param_put_int(plist, (param_name = ".EmbedFontObjects"), &efo, ecode);
273
	    if (efo != 1)
274
		param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
275
	}
276
	{
277
	    int cdv = CoreDistVersion;
278
 
279
	    ecode = param_put_int(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
280
	    if (cdv != CoreDistVersion)
281
		param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
282
	}
283
 
284
	save_dev = *pdev;
285
 
286
	switch (code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl)) {
287
	    default:
288
		ecode = code;
289
		param_signal_error(plist, param_name, ecode);
290
	    case 0:
291
		/*
292
		 * Must be 1.2, 1.3, or 1.4.  Per Adobe documentation, substitute
293
		 * the nearest achievable value.
294
		 */
295
		if (cl < (float)1.15)
296
		    cl = (float)1.1;
297
		else if (cl < (float)1.25)
298
		    cl = (float)1.2;
299
		else if (cl >= (float)1.35)
300
		    cl = (float)1.4;
301
		else
302
		    cl = (float)1.3;
303
	    case 1:
304
		break;
305
	}
306
 
307
	code = gs_param_read_items(plist, pdev, pdf_param_items);
308
	if (code < 0)
309
	    ecode = code;
310
	{
311
	    /*
312
	     * Setting FirstObjectNumber is only legal if the file
313
	     * has just been opened and nothing has been written,
314
	     * or if we are setting it to the same value.
315
	     */
316
	    long fon = pdev->FirstObjectNumber;
317
 
318
	    if (fon != save_dev.FirstObjectNumber) {
319
		if (fon <= 0 || fon > 0x7fff0000 ||
320
		    (pdev->next_id != 0 &&
321
		     pdev->next_id !=
322
		     save_dev.FirstObjectNumber + pdf_num_initial_ids)
323
		    ) {
324
		    ecode = gs_error_rangecheck;
325
		    param_signal_error(plist, "FirstObjectNumber", ecode);
326
		}
327
	    }
328
	}
329
	{
330
	    /*
331
	     * Set ProcessColorModel now, because gx_default_put_params checks
332
	     * it.
333
	     */
334
	    static const char *const pcm_names[] = {
335
		"DeviceGray", "DeviceRGB", "DeviceCMYK", "DeviceN", 0
336
	    };
337
	    int pcm = -1;
338
 
339
	    ecode = param_put_enum(plist, "ProcessColorModel", &pcm,
340
				   pcm_names, ecode);
341
	    if (pcm >= 0) {
342
		pdf_set_process_color_model(pdev, pcm);
343
		pdf_set_initial_color(pdev, &pdev->saved_fill_color, &pdev->saved_stroke_color,
344
				&pdev->fill_used_process_color, &pdev->stroke_used_process_color);
345
	    }
346
	}
347
    }
348
    if (ecode < 0)
349
	goto fail;
350
    /*
351
     * We have to set version to the new value, because the set of
352
     * legal parameter values for psdf_put_params varies according to
353
     * the version.
354
     */
355
    if (pdev->PDFX)
356
	cl = (float)1.3; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
357
    pdev->version = (cl < 1.2 ? psdf_version_level2 : psdf_version_ll3);
358
    if (pdev->ForOPDFRead) {
359
	pdev->ResourcesBeforeUsage = true;
360
	pdev->HaveCFF = false;
361
	pdev->HavePDFWidths = false;
362
	pdev->HaveStrokeColor = false;
363
	cl = (float)1.2; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
364
	pdev->MaxInlineImageSize = max_long; /* Save printer's RAM from saving temporary image data.
365
					        Immediate images doen't need buffering. */
366
	pdev->version = psdf_version_level2;
367
    } else {
368
	pdev->ResourcesBeforeUsage = false;
369
	pdev->HaveCFF = true;
370
	pdev->HavePDFWidths = true;
371
	pdev->HaveStrokeColor = true;
372
    }
373
    ecode = gdev_psdf_put_params(dev, plist);
374
    if (ecode < 0)
375
	goto fail;
376
    if (pdev->HaveTrueTypes && pdev->version == psdf_version_level2) {
377
	pdev->version = psdf_version_level2_with_TT ;
378
    }
379
    /*
380
     * Acrobat Reader doesn't handle user-space coordinates larger than
381
     * MAX_USER_COORD.  To compensate for this, reduce the resolution so
382
     * that the page size in device space (which we equate to user space) is
383
     * significantly less than MAX_USER_COORD.  Note that this still does
384
     * not protect us against input files that use coordinates far outside
385
     * the page boundaries.
386
     */
387
#define MAX_EXTENT ((int)(MAX_USER_COORD * 0.9))
388
    /* Changing resolution or page size requires closing the device, */
389
    if (dev->height > MAX_EXTENT || dev->width > MAX_EXTENT) {
390
	double factor =
391
	    max(dev->height / (double)MAX_EXTENT,
392
		dev->width / (double)MAX_EXTENT);
393
 
394
	gx_device_set_resolution(dev, dev->HWResolution[0] / factor,
395
				 dev->HWResolution[1] / factor);
396
    }
397
#undef MAX_EXTENT
398
    if (pdev->FirstObjectNumber != save_dev.FirstObjectNumber) {
399
	if (pdev->xref.file != 0) {
400
	    fseek(pdev->xref.file, 0L, SEEK_SET);
401
	    pdf_initialize_ids(pdev);
402
	}
403
    }
404
    /* Handle the float/double mismatch. */
405
    pdev->CompatibilityLevel = (int)(cl * 10 + 0.5) / 10.0;
406
    return 0;
407
 fail:
408
    /* Restore all the parameters to their original state. */
409
    pdev->version = save_dev.version;
410
    pdf_set_process_color_model(pdev, save_dev.pcm_color_info_index);
411
    pdev->saved_fill_color = save_dev.saved_fill_color;
412
    pdev->saved_stroke_color = save_dev.saved_fill_color;
413
    {
414
	const gs_param_item_t *ppi = pdf_param_items;
415
 
416
	for (; ppi->key; ++ppi)
417
	    memcpy((char *)pdev + ppi->offset,
418
		   (char *)&save_dev + ppi->offset,
419
		   gs_param_type_sizes[ppi->type]);
420
    }
421
    return ecode;
422
}
423
 
424
/* ---------------- Process DSC comments ---------------- */
425
 
426
private int
427
pdf_dsc_process(gx_device_pdf * pdev, const gs_param_string_array * pma)
428
{
429
    /*
430
     * The Adobe "Distiller Parameters" documentation says that Distiller
431
     * looks at DSC comments, but it doesn't say which ones.  We look at
432
     * the ones that we see how to map directly to obvious PDF constructs.
433
     */
434
    int code = 0;
435
    int i;
436
 
437
    /*
438
     * If ParseDSCComments is false, all DSC comments are ignored, even if
439
     * ParseDSCComentsForDocInfo or PreserveEPSInfo is true.
440
     */
441
    if (!pdev->ParseDSCComments)
442
	return 0;
443
 
444
    for (i = 0; i + 1 < pma->size && code >= 0; i += 2) {
445
	const gs_param_string *pkey = &pma->data[i];
446
	const gs_param_string *pvalue = &pma->data[i + 1];
447
	const char *key;
448
	int code;
449
 
450
	/*
451
	 * %%For, %%Creator, and %%Title are recognized only if either
452
	 * ParseDSCCommentsForDocInfo or PreserveEPSInfo is true.
453
	 * The other DSC comments are always recognized.
454
	 *
455
	 * Acrobat Distiller sets CreationDate and ModDate to the current
456
	 * time, not the value of %%CreationDate.  We think this is wrong,
457
	 * but we do the same -- we ignore %%CreationDate here.
458
	 */
459
 
460
	if (pdf_key_eq(pkey, "Creator"))
461
	    key = "/Creator";
462
	else if (pdf_key_eq(pkey, "Title"))
463
	    key = "/Title";
464
	else if (pdf_key_eq(pkey, "For"))
465
	    key = "/Author";
466
	else {
467
	    pdf_page_dsc_info_t *ppdi;
468
 
469
	    if ((ppdi = &pdev->doc_dsc_info,
470
		 pdf_key_eq(pkey, "Orientation")) ||
471
		(ppdi = &pdev->page_dsc_info,
472
		 pdf_key_eq(pkey, "PageOrientation"))
473
		) {
474
		if (pvalue->size == 1 && pvalue->data[0] >= '0' &&
475
		    pvalue->data[0] <= '3'
476
		    )
477
		    ppdi->orientation = pvalue->data[0] - '0';
478
		else
479
		    ppdi->orientation = -1;
480
	    } else if ((ppdi = &pdev->doc_dsc_info,
481
			pdf_key_eq(pkey, "ViewingOrientation")) ||
482
		       (ppdi = &pdev->page_dsc_info,
483
			pdf_key_eq(pkey, "PageViewingOrientation"))
484
		       ) {
485
		gs_matrix mat;
486
		int orient;
487
 
488
		if (sscanf((const char *)pvalue->data, "[%g %g %g %g]",
489
			   &mat.xx, &mat.xy, &mat.yx, &mat.yy) != 4
490
		    )
491
		    continue;	/* error */
492
		for (orient = 0; orient < 4; ++orient) {
493
		    if (mat.xx == 1 && mat.xy == 0 && mat.yx == 0 && mat.yy == 1)
494
			break;
495
		    gs_matrix_rotate(&mat, -90.0, &mat);
496
		}
497
		if (orient == 4) /* error */
498
		    orient = -1;
499
		ppdi->viewing_orientation = orient;
500
	    } else {
501
		gs_rect box;
502
 
503
		if (pdf_key_eq(pkey, "EPSF")) {
504
		    pdev->is_EPS = (pvalue->size >= 1 && pvalue->data[0] != '0');
505
		    continue;
506
		}
507
		/*
508
		 * We only parse the BoundingBox for the sake of
509
		 * AutoPositionEPSFiles.
510
		 */
511
		if (pdf_key_eq(pkey, "BoundingBox"))
512
		    ppdi = &pdev->doc_dsc_info;
513
		else if (pdf_key_eq(pkey, "PageBoundingBox"))
514
		    ppdi = &pdev->page_dsc_info;
515
		else
516
		    continue;
517
		if (sscanf((const char *)pvalue->data, "[%lg %lg %lg %lg]",
518
			   &box.p.x, &box.p.y, &box.q.x, &box.q.y) != 4
519
		    )
520
		    continue;	/* error */
521
		ppdi->bounding_box = box;
522
	    }
523
	    continue;
524
	}
525
 
526
	if (pdev->ParseDSCCommentsForDocInfo || pdev->PreserveEPSInfo)
527
	    code = cos_dict_put_c_key_string(pdev->Info, key,
528
					     pvalue->data, pvalue->size);
529
    }
530
    return code;
531
}