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