1 /* output-pdf.c: utility routines for PDF output
2
3 Copyright (C) 1999, 2000, 2001 Martin Weber.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License
7 as published by the Free Software Foundation; either version 2.1 of
8 the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 USA. */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif /* Def: HAVE_CONFIG_H */
23
24 #include "types.h"
25 #include "spline.h"
26 #include "color.h"
27 #include "output-pdf.h"
28 #include "xstd.h"
29 #include "autotrace.h"
30 #include <time.h>
31 #include <string.h>
32
33 #define SIGN(x) ((x) > 0 ? 1 : (x) < 0 ? -1 : 0)
34 #define ROUND(x) ((int) ((int) (x) + .5 * SIGN (x)))
35
36 /* Output macros. */
37
38 /* This should be used for outputting a string S on a line by itself. */
39 #define OUT_LINE(s) \
40 fprintf (pdf_file, "%s\n", s)
41
42 /* These output their arguments, preceded by the indentation. */
43 #define OUT1(s, e) \
44 fprintf (pdf_file, s, e)
45
46 #define OUT2(s, e1, e2) \
47 fprintf (pdf_file, s, e1, e2)
48
49 #define OUT3(s, e1, e2, e3) \
50 fprintf (pdf_file, s, e1, e2, e3)
51
52 #define OUT4(s, e1, e2, e3, e4) \
53 fprintf (pdf_file, s, e1, e2, e3, e4)
54
55 /* These macros just output their arguments. */
56 #define OUT_STRING(s) fprintf (pdf_file, "%s", s)
57 #define OUT_REAL(r) fprintf (pdf_file, r == (ROUND (r = ROUND((at_real)6.0*r)/(at_real)6.0)) \
58 ? "%.0f " : "%.3f ", r)
59
60 /* For a PostScript command with two real arguments, e.g., lineto. OP
61 should be a constant string. */
62 #define OUT_COMMAND2(first, second, op) \
63 do \
64 { \
65 OUT_REAL (first); \
66 OUT_REAL (second); \
67 OUT_STRING (op "\n"); \
68 } \
69 while (0)
70
71 /* For a PostScript command with six real arguments, e.g., curveto.
72 Again, OP should be a constant string. */
73 #define OUT_COMMAND6(first, second, third, fourth, fifth, sixth, op) \
74 do \
75 { \
76 OUT_REAL (first); \
77 OUT_REAL (second); \
78 OUT_STRING (" "); \
79 OUT_REAL (third); \
80 OUT_REAL (fourth); \
81 OUT_STRING (" "); \
82 OUT_REAL (fifth); \
83 OUT_REAL (sixth); \
84 OUT_STRING (" " op " \n"); \
85 } \
86 while (0)
87
88 /* This should be used for outputting a string S on a line by itself. */
89 #define SOUT_LINE(s) \
90 sprintf (temp, "%s\n", s), *length += strlen(temp)
91
92 /* These output their arguments, preceded by the indentation. */
93 #define SOUT1(s, e) \
94 sprintf (temp, s, e), *length += strlen(temp)
95
96 #define SOUT2(s, e1, e2) \
97 sprintf (temp, s, e1, e2), *length += strlen(temp)
98
99 #define SOUT3(s, e1, e2, e3) \
100 sprintf (temp, s, e1, e2, e3), *length += strlen(temp)
101
102 #define SOUT4(s, e1, e2, e3, e4) \
103 sprintf (temp, s, e1, e2, e3, e4), *length += strlen(temp)
104
105 /* These macros just output their arguments. */
106 #define SOUT_STRING(s) sprintf (temp, "%s", s), *length += strlen(temp)
107 #define SOUT_REAL(r) sprintf (temp, r == (ROUND (r = ROUND((at_real)6.0*r)/(at_real)6.0)) \
108 ? "%.0f " : "%.3f ", r), *length += strlen(temp)
109
110 /* For a PostScript command with two real arguments, e.g., lineto. OP
111 should be a constant string. */
112 #define SOUT_COMMAND2(first, second, op) \
113 do \
114 { \
115 SOUT_REAL (first); \
116 SOUT_REAL (second); \
117 SOUT_STRING (op "\n"); \
118 } \
119 while (0)
120
121 /* For a PostScript command with six real arguments, e.g., curveto.
122 Again, OP should be a constant string. */
123 #define SOUT_COMMAND6(first, second, third, fourth, fifth, sixth, op) \
124 do \
125 { \
126 SOUT_REAL (first); \
127 SOUT_REAL (second); \
128 SOUT_STRING (" "); \
129 SOUT_REAL (third); \
130 SOUT_REAL (fourth); \
131 SOUT_STRING (" "); \
132 SOUT_REAL (fifth); \
133 SOUT_REAL (sixth); \
134 SOUT_STRING (" " op " \n"); \
135 } \
136 while (0)
137
138
139 /* This should be called before the others in this file. It opens the
140 output file `OUTPUT_NAME.pdf', and writes some preliminary boilerplate. */
141
output_pdf_header(FILE * pdf_file,at_string name,int llx,int lly,int urx,int ury)142 static int output_pdf_header(FILE* pdf_file, at_string name,
143 int llx, int lly, int urx, int ury)
144 {
145 OUT_LINE ("%PDF-1.2");
146 OUT_LINE ("1 0 obj");
147 OUT_LINE (" << /Type /Catalog");
148 OUT_LINE (" /Outlines 2 0 R");
149 OUT_LINE (" /Pages 3 0 R");
150 OUT_LINE (" >>");
151 OUT_LINE ("endobj");
152 OUT_LINE ("2 0 obj");
153 OUT_LINE (" << /Type /Outlines");
154 OUT_LINE (" /Count 0");
155 OUT_LINE (" >>");
156 OUT_LINE ("endobj");
157 OUT_LINE ("3 0 obj");
158 OUT_LINE (" << /Type /Pages");
159 OUT_LINE (" /Kids [4 0 R]");
160 OUT_LINE (" /Count 1");
161 OUT_LINE (" >>");
162 OUT_LINE ("endobj");
163 OUT_LINE ("4 0 obj");
164 OUT_LINE (" << /Type /Page");
165 OUT_LINE (" /Parent 3 0 R");
166 OUT4 (" /MediaBox [%d %d %d %d]\n", llx, lly, urx, ury);
167 OUT_LINE (" /Contents 5 0 R");
168 OUT_LINE (" /Resources << /ProcSet 6 0 R >>");
169 OUT_LINE (" >>");
170 OUT_LINE ("endobj");
171
172 return 0;
173 }
174
175
176 /* This should be called after the others in this file. It writes some
177 last informations. */
178
output_pdf_tailor(FILE * pdf_file,size_t length,int llx,int lly,int urx,int ury)179 static int output_pdf_tailor(FILE* pdf_file, size_t length,
180 int llx, int lly, int urx, int ury)
181 {
182 char temp[40];
183 size_t tmp;
184
185 OUT_LINE ("6 0 obj");
186 OUT_LINE (" [/PDF]");
187 OUT_LINE ("endobj");
188 OUT_LINE ("xref");
189 OUT_LINE ("0 7");
190 OUT_LINE ("0000000000 65535 f ");
191 OUT_LINE ("0000000009 00000 n ");
192 OUT_LINE ("0000000092 00000 n ");
193 OUT_LINE ("0000000150 00000 n ");
194 OUT_LINE ("0000000225 00000 n ");
195 sprintf(temp, "%d", llx);
196 tmp = 366;
197 tmp += (strlen (temp));
198 sprintf(temp, "%d", lly);
199 tmp += (strlen (temp));
200 sprintf(temp, "%d", urx);
201 tmp += (strlen (temp));
202 sprintf(temp, "%d", ury);
203 tmp += (strlen (temp));
204 OUT1 ("%010d 00000 n \n", tmp);
205 sprintf(temp, "%d", length);
206 tmp += 50 + length + strlen(temp);
207 OUT1 ("%010d 00000 n \n", tmp);
208 OUT_LINE ("trailer");
209 OUT_LINE (" << /Size 7");
210 OUT_LINE (" /Root 1 0 R");
211 OUT_LINE (" >>");
212 OUT_LINE ("startxref");
213 OUT1 ("%d\n", tmp + 25);
214 OUT_LINE ("%%EOF");
215
216 return 0;
217 }
218
219
220 /* This outputs the PDF code which produces the shape in
221 SHAPE. */
222
223 static void
out_splines(FILE * pdf_file,spline_list_array_type shape,size_t * length)224 out_splines (FILE *pdf_file, spline_list_array_type shape, size_t *length)
225 {
226 char temp[40];
227 unsigned this_list;
228 spline_list_type list;
229
230 color_type last_color = {0,0,0};
231
232 for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
233 this_list++)
234 {
235 unsigned this_spline;
236 spline_type first;
237
238 list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
239 first = SPLINE_LIST_ELT (list, 0);
240
241 if (this_list == 0 || !COLOR_EQUAL(list.color, last_color))
242 {
243 if (this_list > 0)
244 {
245 SOUT_LINE ((shape.centerline || list.open) ? "S" : "f");
246 SOUT_LINE("h");
247 }
248 SOUT4 ("%.3f %.3f %.3f %s\n", (double) list.color.r / 255.0,
249 (double) list.color.g / 255.0, (double) list.color.b / 255.0,
250 (shape.centerline || list.open) ? "RG" : "rg");
251 last_color = list.color;
252 }
253 SOUT_COMMAND2 (START_POINT (first).x, START_POINT (first).y, "m");
254
255 for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
256 this_spline++)
257 {
258 spline_type s = SPLINE_LIST_ELT (list, this_spline);
259
260 if (SPLINE_DEGREE (s) == LINEARTYPE)
261 SOUT_COMMAND2 (END_POINT (s).x, END_POINT (s).y, "l");
262 else
263 SOUT_COMMAND6 (CONTROL1 (s).x, CONTROL1 (s).y,
264 CONTROL2 (s).x, CONTROL2 (s).y,
265 END_POINT (s).x, END_POINT (s).y,
266 "c");
267 }
268 }
269 if (SPLINE_LIST_ARRAY_LENGTH(shape) > 0)
270 SOUT_LINE ((shape.centerline || list.open) ? "S" : "f");
271
272 OUT_LINE ("5 0 obj");
273 OUT1 (" << /Length %d >>\n", *length);
274 OUT_LINE ("stream");
275
276 last_color.r = 0;
277 last_color.g = 0;
278 last_color.b = 0;
279
280 for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
281 this_list++)
282 {
283 unsigned this_spline;
284 spline_type first;
285
286 list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
287 first = SPLINE_LIST_ELT (list, 0);
288
289 if (this_list == 0 || !COLOR_EQUAL(list.color, last_color))
290 {
291 if (this_list > 0)
292 {
293 OUT_LINE ((shape.centerline || list.open) ? "S" : "f");
294 OUT_LINE("h");
295 }
296 OUT4 ("%.3f %.3f %.3f %s\n", (double) list.color.r / 255.0,
297 (double) list.color.g / 255.0, (double) list.color.b / 255.0,
298 (shape.centerline || list.open) ? "RG" : "rg");
299 last_color = list.color;
300 }
301 OUT_COMMAND2 (START_POINT (first).x, START_POINT (first).y, "m");
302
303 for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
304 this_spline++)
305 {
306 spline_type s = SPLINE_LIST_ELT (list, this_spline);
307
308 if (SPLINE_DEGREE (s) == LINEARTYPE)
309 OUT_COMMAND2 (END_POINT (s).x, END_POINT (s).y, "l");
310 else
311 OUT_COMMAND6 (CONTROL1 (s).x, CONTROL1 (s).y,
312 CONTROL2 (s).x, CONTROL2 (s).y,
313 END_POINT (s).x, END_POINT (s).y,
314 "c");
315 }
316 }
317 if (SPLINE_LIST_ARRAY_LENGTH(shape) > 0)
318 OUT_LINE ((shape.centerline || list.open) ? "S" : "f");
319 OUT_LINE ("endstream");
320 OUT_LINE ("endobj");
321
322 }
323
324
output_pdf_writer(FILE * pdf_file,at_string name,int llx,int lly,int urx,int ury,at_output_opts_type * opts,spline_list_array_type shape,at_msg_func msg_func,at_address msg_data)325 int output_pdf_writer(FILE* pdf_file, at_string name,
326 int llx, int lly, int urx, int ury,
327 at_output_opts_type * opts,
328 spline_list_array_type shape,
329 at_msg_func msg_func,
330 at_address msg_data)
331 {
332 int result;
333 size_t length = 0;
334
335 #ifdef _WINDOWS
336 if(pdf_file == stdout)
337 {
338 fprintf(stderr, "This driver couldn't write to stdout!\n");
339 return -1;
340 }
341 #endif
342
343 result = output_pdf_header(pdf_file, name, llx, lly, urx, ury);
344 if (result != 0)
345 return result;
346
347 out_splines(pdf_file, shape, &length);
348
349 output_pdf_tailor(pdf_file, length, llx, lly, urx, ury);
350
351 return 0;
352 }
353