1 /* output-eps.c: utility routines for PostScript output.
2
3 Copyright (C) 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-eps.h"
28 #include "xstd.h"
29 #include "autotrace.h"
30 #include <time.h>
31 #include <string.h>
32
33 static at_string now (void);
34
35 #define SIGN(x) ((x) > 0 ? 1 : (x) < 0 ? -1 : 0)
36 #define ROUND(x) ((int) ((int) (x) + .5 * SIGN (x)))
37
38 /* Output macros. */
39
40 /* This should be used for outputting a string S on a line by itself. */
41 #define OUT_LINE(s) \
42 fprintf (ps_file, "%s\n", s)
43
44 /* These output their arguments, preceded by the indentation. */
45 #define OUT1(s, e) \
46 fprintf (ps_file, s, e)
47
48 #define OUT2(s, e1, e2) \
49 fprintf (ps_file, s, e1, e2)
50
51 #define OUT3(s, e1, e2, e3) \
52 fprintf (ps_file, s, e1, e2, e3)
53
54 #define OUT4(s, e1, e2, e3, e4) \
55 fprintf (ps_file, s, e1, e2, e3, e4)
56
57 #define OUT5(s, e1, e2, e3, e4, e5) \
58 fprintf (ps_file, s, e1, e2, e3, e4, e5)
59
60 /* These macros just output their arguments. */
61 #define OUT_STRING(s) fprintf (ps_file, "%s", s)
62 #define OUT_REAL(r) fprintf (ps_file, r == (ROUND (r = ROUND((at_real)6.0*r)/(at_real)6.0)) \
63 ? "%.0f " : "%.3f ", r)
64
65 /* For a PostScript command with two real arguments, e.g., lineto. OP
66 should be a constant string. */
67 #define OUT_COMMAND2(first, second, op) \
68 do \
69 { \
70 OUT_REAL (first); \
71 OUT_REAL (second); \
72 OUT_STRING (op "\n"); \
73 } \
74 while (0)
75
76 /* For a PostScript command with six real arguments, e.g., curveto.
77 Again, OP should be a constant string. */
78 #define OUT_COMMAND6(first, second, third, fourth, fifth, sixth, op) \
79 do \
80 { \
81 OUT_REAL (first); \
82 OUT_REAL (second); \
83 OUT_STRING (" "); \
84 OUT_REAL (third); \
85 OUT_REAL (fourth); \
86 OUT_STRING (" "); \
87 OUT_REAL (fifth); \
88 OUT_REAL (sixth); \
89 OUT_STRING (" " op " \n"); \
90 } \
91 while (0)
92
93 /* This should be called before the others in this file. It opens the
94 output file `OUTPUT_NAME.ps', and writes some preliminary boilerplate. */
95
output_eps_header(FILE * ps_file,at_string name,int llx,int lly,int urx,int ury)96 static int output_eps_header(FILE* ps_file, at_string name,
97 int llx, int lly, int urx, int ury)
98 {
99 at_string time;
100
101 OUT_LINE ("%!PS-Adobe-3.0 EPSF-3.0");
102 OUT1 ("%%%%Creator: Adobe Illustrator by %s\n", at_version(true));
103 OUT1 ("%%%%Title: %s\n", name);
104 OUT1 ("%%%%CreationDate: %s\n", time = now ());
105 OUT4 ("%%%%BoundingBox: %d %d %d %d\n", llx, lly, urx, ury);
106 OUT_LINE ("%%DocumentData: Clean7Bit");
107 OUT_LINE ("%%EndComments");
108
109 free (time);
110 /* Prolog to define Illustrator commands.
111 *
112 * The s and S commands are not used at the moment and could be
113 * removed or commented out.
114 *
115 * Calling f in *U is not really the right thing to do, but since all
116 * paths are simply filled currently, this is the easiest solution.
117 */
118
119 OUT_LINE ("%%BeginProlog");
120 OUT_LINE ("/bd { bind def } bind def");
121 OUT_LINE ("/incompound false def");
122 OUT_LINE ("/m { moveto } bd");
123 OUT_LINE ("/l { lineto } bd");
124 OUT_LINE ("/c { curveto } bd");
125 OUT_LINE ("/F { incompound not {fill} if } bd");
126 OUT_LINE ("/f { closepath F } bd");
127 OUT_LINE ("/S { stroke } bd");
128 OUT_LINE ("/*u { /incompound true def } bd");
129 OUT_LINE ("/*U { /incompound false def f} bd");
130 OUT_LINE ("/k { setcmykcolor } bd"); /* must symbol k for CorelDraw 3/4 */
131 OUT_LINE ("/K { k } bd");
132 OUT_LINE ("%%EndProlog");
133 OUT_LINE ("%%BeginSetup"); /* needed for CorelDraw 3/4 */
134 OUT_LINE ("%%EndSetup"); /* needed for CorelDraw 3/4 */
135
136 return 0;
137 }
138
139 /* This outputs the PostScript code which produces the shape in
140 SHAPE. */
141
142 static void
out_splines(FILE * ps_file,spline_list_array_type shape)143 out_splines (FILE * ps_file, spline_list_array_type shape)
144 {
145 unsigned this_list;
146 spline_list_type list;
147
148 color_type last_color = {0,0,0};
149
150 for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
151 this_list++)
152 {
153 unsigned this_spline;
154 int c, m, y, k;
155 spline_type first;
156
157 list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
158 first = SPLINE_LIST_ELT (list, 0);
159
160 if (this_list == 0 || !COLOR_EQUAL(list.color, last_color))
161 {
162 if (this_list > 0)
163 OUT_LINE("*U");
164 c = k = 255 - list.color.r;
165 m = 255 - list.color.g;
166 if (m < k)
167 k = m;
168 y = 255 - list.color.b;
169 if (y < k)
170 k = y;
171 c -= k;
172 m -= k;
173 y -= k;
174 /* symbol k is used for CorelDraw 3/4 compatibility */
175 OUT5 ("%.3f %.3f %.3f %.3f %s\n", (double) c/255.0,
176 (double) m/255.0,(double) y/255.0, (double) k/255.0,
177 (shape.centerline || list.open) ? "K" : "k");
178 OUT_LINE("*u");
179 last_color = list.color;
180 }
181 OUT_COMMAND2 (START_POINT (first).x, START_POINT (first).y, "m");
182
183 for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
184 this_spline++)
185 {
186 spline_type s = SPLINE_LIST_ELT (list, this_spline);
187
188 if (SPLINE_DEGREE (s) == LINEARTYPE)
189 OUT_COMMAND2 (END_POINT (s).x, END_POINT (s).y, "l");
190 else
191 OUT_COMMAND6 (CONTROL1 (s).x, CONTROL1 (s).y,
192 CONTROL2 (s).x, CONTROL2 (s).y,
193 END_POINT (s).x, END_POINT (s).y,
194 "c");
195 }
196 if (SPLINE_LIST_ARRAY_LENGTH(shape) > 0)
197 OUT_LINE ((shape.centerline || list.open) ? "S" : "f");
198 }
199 if (SPLINE_LIST_ARRAY_LENGTH(shape) > 0)
200 OUT_LINE("*U");
201 }
202
203
output_eps_writer(FILE * ps_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)204 int output_eps_writer(FILE* ps_file, at_string name,
205 int llx, int lly, int urx, int ury,
206 at_output_opts_type * opts,
207 spline_list_array_type shape,
208 at_msg_func msg_func,
209 at_address msg_data)
210 {
211 int result;
212
213 result = output_eps_header(ps_file, name, llx, lly, urx, ury);
214 if (result != 0)
215 return result;
216
217 out_splines(ps_file, shape);
218
219 OUT_LINE ("%%Trailer");
220 OUT_LINE ("%%EOF");
221 return 0;
222 }
223
224
225 static at_string
now(void)226 now (void)
227 {
228 at_string time_string;
229 time_t t = time (0);
230
231 XMALLOC (time_string, 26); /* not 25 ! */
232 strcpy (time_string, ctime (&t));
233 time_string[24] = 0; /* No newline. */
234
235 return time_string;
236 }
237
238