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