Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 2000 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: gdevpsu.c,v 1.19 2005/03/02 18:08:38 raph Exp $ */
18
/* PostScript-writing utilities */
19
#include "math_.h"
20
#include "time_.h"
21
#include "stat_.h"
22
#include "unistd_.h"
23
#include "gx.h"
24
#include "gscdefs.h"
25
#include "gxdevice.h"
26
#include "gdevpsu.h"
27
#include "spprint.h"
28
#include "stream.h"
29
#include "gserrors.h"
30
 
31
/* ---------------- Low level ---------------- */
32
 
33
/* Write a 0-terminated array of strings as lines. */
34
int
35
psw_print_lines(FILE *f, const char *const lines[])
36
{
37
    int i;
38
    for (i = 0; lines[i] != 0; ++i) {
39
	if (fprintf(f, "%s\n", lines[i]) < 0)
40
            return_error(gs_error_ioerror);
41
    }
42
    return 0;
43
}
44
 
45
/* Write the ProcSet name. */
46
private void
47
psw_put_procset_name(stream *s, const gx_device *dev,
48
		     const gx_device_pswrite_common_t *pdpc)
49
{
50
    pprints1(s, "GS_%s", dev->dname);
51
    pprintd3(s, "_%d_%d_%d",
52
	    (int)pdpc->LanguageLevel,
53
	    (int)(pdpc->LanguageLevel * 10 + 0.5) % 10,
54
	    pdpc->ProcSet_version);
55
}
56
private void
57
psw_print_procset_name(FILE *f, const gx_device *dev,
58
		       const gx_device_pswrite_common_t *pdpc)
59
{
60
    byte buf[100];		/* arbitrary */
61
    stream s;
62
 
63
    s_init(&s, dev->memory);
64
    swrite_file(&s, f, buf, sizeof(buf));
65
    psw_put_procset_name(&s, dev, pdpc);
66
    sflush(&s);
67
}
68
 
69
/* Write a bounding box. */
70
private void
71
psw_print_bbox(FILE *f, const gs_rect *pbbox)
72
{
73
    fprintf(f, "%%%%BoundingBox: %d %d %d %d\n",
74
	    (int)floor(pbbox->p.x), (int)floor(pbbox->p.y),
75
	    (int)ceil(pbbox->q.x), (int)ceil(pbbox->q.y));
76
    fprintf(f, "%%%%HiResBoundingBox: %f %f %f %f\n",
77
	    pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y);
78
}
79
 
80
/* ---------------- File level ---------------- */
81
 
82
private const char *const psw_ps_header[] = {
83
    "%!PS-Adobe-3.0",
84
    "%%Pages: (atend)",
85
 
86
};
87
 
88
private const char *const psw_eps_header[] = {
89
    "%!PS-Adobe-3.0 EPSF-3.0",
90
 
91
};
92
 
93
private const char *const psw_begin_prolog[] = {
94
    "%%EndComments",
95
    "%%BeginProlog",
96
    "% This copyright applies to everything between here and the %%EndProlog:",
97
				/* copyright */
98
				/* begin ProcSet */
99
 
100
};
101
 
102
/*
103
 * To achieve page independence, every page must in the general case
104
 * set page parameters. To preserve duplexing the page cannot set page
105
 * parameters. The following code checks the current page size and sets
106
 * it only if it is necessary.
107
 */
108
private const char *const psw_ps_procset[] = {
109
	/* <w> <h> <sizename> setpagesize - */
110
   "/PageSize 2 array def"
111
   "/setpagesize"              /* x y /a4 -> -          */
112
     "{ PageSize aload pop "   /* x y /a4 x0 y0         */
113
       "3 index eq exch",      /* x y /a4 bool x0       */
114
       "4 index eq and"        /* x y /a4 bool          */
115
         "{ pop pop pop"
116
         "}"
117
         "{ PageSize dup  1",  /* x y /a4 [  ] [  ] 1   */
118
           "5 -1 roll put 0 "  /* x /a4 [ y] 0          */
119
           "4 -1 roll put "    /* /a4                   */
120
           "dup null eq {false} {dup where} ifelse"
121
             "{ exch get exec" /* -                     */
122
             "}",
123
             "{ pop"           /* -                     */
124
               "/setpagedevice where",
125
                 "{ pop 1 dict dup /PageSize PageSize put setpagedevice"
126
                 "}",
127
                 "{ /setpage where"
128
                     "{ pop PageSize aload pop pageparams 3 {exch pop} repeat",
129
                       "setpage"
130
                     "}"
131
                   "if"
132
                 "}"
133
               "ifelse"
134
             "}"
135
           "ifelse"
136
         "}"
137
       "ifelse"
138
     "} bind def",
139
 
140
};
141
 
142
private const char *const psw_end_prolog[] = {
143
    "end readonly def",
144
    "%%EndResource",		/* ProcSet */
145
    "/pagesave null def",	/* establish binding */
146
    "%%EndProlog",
147
 
148
};
149
 
150
/* Return true when the file is seekable.
151
 * On Windows NT ftell() returns some non-EOF value when used on pipes.
152
 */
153
private bool
154
is_seekable(FILE *f)
155
{ 
156
    struct stat buf;
157
 
158
    if(fstat(fileno(f), &buf))
159
      return 0;
160
    return S_ISREG(buf.st_mode);
161
}
162
 
163
/*
164
 * Write the file header, up through the BeginProlog.  This must write to a
165
 * file, not a stream, because it may be called during finalization.
166
 */
167
int
168
psw_begin_file_header(FILE *f, const gx_device *dev, const gs_rect *pbbox,
169
		      gx_device_pswrite_common_t *pdpc, bool ascii)
170
{
171
    psw_print_lines(f, (pdpc->ProduceEPS ? psw_eps_header : psw_ps_header));
172
    if (pbbox) {
173
	psw_print_bbox(f, pbbox);
174
	pdpc->bbox_position = 0;
175
    } else if (!is_seekable(f)) {	/* File is not seekable. */
176
	pdpc->bbox_position = -1;
177
	fputs("%%BoundingBox: (atend)\n", f);
178
	fputs("%%HiResBoundingBox: (atend)\n", f);
179
    } else {		/* File is seekable, leave room to rewrite bbox. */
180
	pdpc->bbox_position = ftell(f);
181
	fputs("%...............................................................\n", f);
182
	fputs("%...............................................................\n", f);
183
    }
184
    fprintf(f, "%%%%Creator: %s %ld (%s)\n", gs_product, (long)gs_revision,
185
	    dev->dname);
186
    {
187
	time_t t;
188
	struct tm tms;
189
 
190
	time(&t);
191
	tms = *localtime(&t);
192
	fprintf(f, "%%%%CreationDate: %d/%02d/%02d %02d:%02d:%02d\n",
193
		tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
194
		tms.tm_hour, tms.tm_min, tms.tm_sec);
195
    }
196
    if (ascii)
197
	fputs("%%DocumentData: Clean7Bit\n", f);
198
    if (pdpc->LanguageLevel >= 2.0)
199
	fprintf(f, "%%%%LanguageLevel: %d\n", (int)pdpc->LanguageLevel);
200
    else if (pdpc->LanguageLevel == 1.5)
201
	fputs("%%Extensions: CMYK\n", f);
202
    psw_print_lines(f, psw_begin_prolog);
203
    fprintf(f, "%% %s\n", gs_copyright);
204
    fputs("%%BeginResource: procset ", f);
205
    fflush(f);
206
    psw_print_procset_name(f, dev, pdpc);
207
    fputs("\n/", f);
208
    fflush(f);
209
    psw_print_procset_name(f, dev, pdpc);
210
    fputs(" 80 dict dup begin\n", f);
211
    psw_print_lines(f, psw_ps_procset);
212
    fflush(f);
213
    if (ferror(f))
214
        return_error(gs_error_ioerror);
215
    return 0;
216
}
217
 
218
/*
219
 * End the file header.
220
 */
221
int
222
psw_end_file_header(FILE *f)
223
{
224
    return psw_print_lines(f, psw_end_prolog);
225
}
226
 
227
/*
228
 * End the file.
229
 */
230
int
231
psw_end_file(FILE *f, const gx_device *dev,
232
	     const gx_device_pswrite_common_t *pdpc, const gs_rect *pbbox,
233
             int /* should be long */ page_count)
234
{
235
    if (f == NULL)
236
        return 0;	/* clients should be more careful */
237
    fprintf(f, "%%%%Trailer\n%%%%Pages: %ld\n", (long)page_count);
238
    if (ferror(f))
239
        return_error(gs_error_ioerror);
240
    if (dev->PageCount > 0 && pdpc->bbox_position != 0) {
241
	if (pdpc->bbox_position >= 0) {
242
	    long save_pos = ftell(f);
243
 
244
	    fseek(f, pdpc->bbox_position, SEEK_SET);
245
	    psw_print_bbox(f, pbbox);
246
            fputc('%', f);
247
            if (ferror(f))
248
                return_error(gs_error_ioerror);
249
            fseek(f, save_pos, SEEK_SET);
250
	} else
251
	    psw_print_bbox(f, pbbox);
252
    }
253
    if (!pdpc->ProduceEPS)
254
	fputs("%%EOF\n", f);
255
    if (ferror(f))
256
        return_error(gs_error_ioerror);
257
    return 0;
258
}
259
 
260
/* ---------------- Page level ---------------- */
261
 
262
/*
263
 * Write the page header.
264
 */
265
int
266
psw_write_page_header(stream *s, const gx_device *dev,
267
                      const gx_device_pswrite_common_t *pdpc,
268
                      bool do_scale, long page_ord, int dictsize)
269
{
270
    long page = dev->PageCount + 1;
271
 
272
    pprintld2(s, "%%%%Page: %ld %ld\n%%%%BeginPageSetup\n", page, page_ord);
273
    /*
274
     * Adobe's documentation says that page setup must be placed outside the
275
     * save/restore that encapsulates the page contents, and that the
276
     * showpage must be placed after the restore.  This means that to
277
     * achieve page independence, *every* page's setup code must include a
278
     * setpagedevice that sets *every* page device parameter that is changed
279
     * on *any* page.  Currently, the only such parameter relevant to this
280
     * driver is page size, but there might be more in the future.
281
     */
282
    psw_put_procset_name(s, dev, pdpc);
283
    stream_puts(s, " begin\n");
284
    if (!pdpc->ProduceEPS) {
285
	int width = (int)(dev->width * 72.0 / dev->HWResolution[0] + 0.5);
286
	int height = (int)(dev->height * 72.0 / dev->HWResolution[1] + 0.5);
287
	typedef struct ps_ {
288
	    const char *size_name;
289
	    int width, height;
290
	} page_size;
291
	static const page_size sizes[] = {
292
	    {"/11x17", 792, 1224},
293
	    {"/a3", 842, 1190},
294
	    {"/a4", 595, 842},
295
	    {"/b5", 501, 709},
296
	    {"/ledger", 1224, 792},
297
	    {"/legal", 612, 1008},
298
	    {"/letter", 612, 792},
299
	    {"null", 0, 0}
300
	};
301
	const page_size *p = sizes;
302
 
303
	while (p->size_name[0] == '/' &&
304
	       (p->width != width || p->height != height))
305
	    ++p;
306
	pprintd2(s, "%d %d ", width, height);
307
	pprints1(s, "%s setpagesize\n", p->size_name);
308
    }
309
    pprintd1(s, "/pagesave save store %d dict begin\n", dictsize);
310
    if (do_scale)
311
	pprintg2(s, "%g %g scale\n",
312
		 72.0 / dev->HWResolution[0], 72.0 / dev->HWResolution[1]);
313
    stream_puts(s, "%%EndPageSetup\ngsave mark\n");
314
    if (s->end_status == ERRC)
315
        return_error(gs_error_ioerror);
316
    return 0;
317
}
318
 
319
/*
320
 * Write the page trailer.  We do this directly to the file, rather than to
321
 * the stream, because we may have to do it during finalization.
322
 */
323
int
324
psw_write_page_trailer(FILE *f, int num_copies, int flush)
325
{
326
    fprintf(f, "cleartomark end end pagesave restore\n");
327
    if (num_copies != 1)
328
	fprintf(f, "userdict /#copies %d put\n", num_copies);
329
    fprintf(f, " %s\n%%%%PageTrailer\n", (flush ? "showpage" : "copypage"));
330
    fflush(f);
331
    if (ferror(f))
332
        return_error(gs_error_ioerror);
333
    return 0;
334
}