1 /*****
2 * psfile.h
3 * Andy Hammerlindl 2002/06/10
4 *
5 * Encapsulates the writing of commands to a PostScript file.
6 * Allows identification and removal of redundant commands.
7 *****/
8
9 #ifndef PSFILE_H
10 #define PSFILE_H
11
12 #include <fstream>
13 #include <iomanip>
14 #include <sstream>
15
16 #include "pair.h"
17 #include "path.h"
18 #include "bbox.h"
19 #include "pen.h"
20 #include "array.h"
21 #include "callable.h"
22
23 namespace camp {
24
BoundingBox(std::ostream & s,const bbox & box)25 inline void BoundingBox(std::ostream& s, const bbox& box)
26 {
27 s << "%%BoundingBox: " << std::setprecision(0) << std::fixed
28 << box.LowRes() << newl;
29 s.unsetf(std::ios::fixed);
30 s << "%%HiResBoundingBox: " << std::setprecision(9) << box << newl;
31 }
32
33 // An ASCII85Encode filter.
34 class encode85 {
35 ostream *out;
36 int tuple;
37 int pos;
38 int count;
39 static const int width=72;
40 public:
encode85(ostream * out)41 encode85(ostream *out) : out(out), tuple(0), pos(0), count(0) {}
42
~encode85()43 ~encode85() {
44 if(count > 0)
45 encode(tuple, count);
46 if(pos+2 > width)
47 *out << '\n';
48 *out << "~>\n";
49 }
50 private:
encode(unsigned int tuple,int count)51 void encode(unsigned int tuple, int count) {
52 unsigned char buf[5], *s=buf;
53 int i=5;
54 do {
55 *s++=tuple % 85;
56 tuple /= 85;
57 } while(--i > 0);
58 i=count;
59 do {
60 *out << (unsigned char) (*--s + '!');
61 if(pos++ >= width) {
62 pos=0;
63 *out << '\n';
64 }
65 } while(i-- > 0);
66 }
67
68 public:
put(unsigned char c)69 void put(unsigned char c) {
70 switch (count++) {
71 case 0:
72 tuple |= (c << 24);
73 break;
74 case 1:
75 tuple |= (c << 16);
76 break;
77 case 2:
78 tuple |= (c << 8);
79 break;
80 case 3:
81 tuple |= c;
82 if(tuple == 0) {
83 *out << 'z';
84 if(pos++ >= width) {
85 pos=0;
86 *out << '\n';
87 }
88 } else
89 encode(tuple, count);
90 tuple=0;
91 count=0;
92 break;
93 }
94 }
95 };
96
97 class psfile {
98 protected:
99 mem::stack<pen> pens;
100
101 public:
102
103 string filename;
104 bool pdfformat; // Is final output format PDF?
105 bool pdf; // Output direct PDF?
106 unsigned char *buffer;
107 size_t count;
108
109 void write(pen *p, size_t ncomponents);
110 void writefromRGB(unsigned char r, unsigned char g, unsigned char b,
111 ColorSpace colorspace, size_t ncomponents);
112
113 void writeCompressed(const unsigned char *a, size_t size);
114 void dealias(unsigned char *a, size_t width, size_t height, size_t n,
115 bool convertrgb=false, ColorSpace colorspace=DEFCOLOR);
116
beginImage(size_t n)117 void beginImage(size_t n) {
118 buffer=new unsigned char[n];
119 count=0;
120 }
121
122 void outImage(bool antialias, size_t width, size_t height,
123 size_t ncomponents);
124
endImage(bool antialias,size_t width,size_t height,size_t ncomponents)125 void endImage(bool antialias, size_t width, size_t height,
126 size_t ncomponents) {
127 outImage(antialias,width,height,ncomponents);
128 delete[] buffer;
129 }
130
writeByte(unsigned char n)131 void writeByte(unsigned char n) {
132 buffer[count++]=n;
133 }
134
135 protected:
136 pen lastpen;
137 std::ostream *out;
138
139 public:
140 psfile(const string& filename, bool pdfformat);
141
psfile()142 psfile() {pdf=settings::pdf(settings::getSetting<string>("tex"));}
143
144 virtual ~psfile();
145
BoundingBox(const bbox & box)146 void BoundingBox(const bbox& box) {
147 camp::BoundingBox(*out,box);
148 }
149
150 void prologue(const bbox& box);
151 void epilogue();
152 void header(bool eps);
153
154 void close();
155
write(double x)156 void write(double x) {
157 *out << " " << x;
158 }
159
writenewl()160 void writenewl() {
161 *out << newl;
162 }
163
write(pair z)164 void write(pair z) {
165 *out << " " << z.getx() << " " << z.gety();
166 }
167
write(transform t)168 void write(transform t) {
169 if(!pdf) *out << "[";
170 *out << " " << t.getxx() << " " << t.getyx()
171 << " " << t.getxy() << " " << t.getyy()
172 << " " << t.getx() << " " << t.gety();
173 if(!pdf) *out << "]";
174 }
175
resetpen()176 void resetpen() {
177 lastpen=pen(initialpen);
178 lastpen.convert();
179 }
180
181 void setcolor(const pen& p, const string& begin, const string& end);
182 void setopacity(const pen& p);
183
184 virtual void setpen(pen p);
185
186 void write(const pen& p);
187
188 void write(path p, bool newPath=true);
189
190 virtual void writeclip(path p, bool newPath=true) {
191 write(p,newPath);
192 }
193
194 virtual void dot(path p, pen, bool newPath=true) {
195 write(p,newPath);
196 }
197
newpath()198 virtual void newpath() {
199 if(!pdf) *out << "newpath";
200 }
201
moveto(pair z)202 virtual void moveto(pair z) {
203 write(z);
204 if(pdf) *out << " m" << newl;
205 else *out << " moveto" << newl;
206 }
207
lineto(pair z)208 virtual void lineto(pair z) {
209 write(z);
210 if(pdf) *out << " l" << newl;
211 else *out << " lineto" << newl;
212 }
213
curveto(pair zp,pair zm,pair z1)214 virtual void curveto(pair zp, pair zm, pair z1) {
215 write(zp); write(zm); write(z1);
216 if(pdf) *out << " c" << newl;
217 else *out << " curveto" << newl;
218 }
219
closepath()220 virtual void closepath() {
221 if(pdf) *out << "h" << newl;
222 else *out << "closepath" << newl;
223 }
224
225 virtual void stroke(const pen &p, bool dot=false) {
226 if(pdf) *out << "S" << newl;
227 else *out << "stroke" << newl;
228 }
229
strokepath()230 virtual void strokepath() {
231 if(pdf) reportError("PDF does not support strokepath");
232 else *out << "strokepath" << newl;
233 }
234
fill(const pen & p)235 virtual void fill(const pen &p) {
236 if(p.evenodd()) {
237 if(pdf) *out << "f*" << newl;
238 else *out << "eofill" << newl;
239 } else {
240 if(pdf) *out << "f" << newl;
241 else *out << "fill" << newl;
242 }
243 }
244
beginclip()245 virtual void beginclip() {
246 newpath();
247 }
248
endclip(const pen & p)249 virtual void endclip(const pen &p) {
250 if(p.evenodd()) {
251 if(pdf) *out << "W* n" << newl;
252 else *out << "eoclip" << newl;
253 } else {
254 if(pdf) *out << "W n" << newl;
255 else *out << "clip" << newl;
256 }
257 }
258
endpsclip(const pen & p)259 virtual void endpsclip(const pen &p) {endclip(p);}
260
checkLevel()261 void checkLevel() {
262 int n=settings::getSetting<Int>("level");
263 if(n < 3)
264 reportError("PostScript shading requires -level 3");
265 }
266
beginlatticeshade(const vm::array & a,const bbox & b)267 virtual void beginlatticeshade(const vm::array& a, const bbox& b) {}
268 virtual void latticeshade(const vm::array& a, const transform& t);
269
begingradientshade(bool axial,ColorSpace colorspace,const pen & pena,const pair & a,double ra,const pen & penb,const pair & b,double rb)270 virtual void begingradientshade(bool axial, ColorSpace colorspace,
271 const pen& pena, const pair& a, double ra,
272 const pen& penb, const pair& b, double rb) {}
273
274 virtual void gradientshade(bool axial, ColorSpace colorspace,
275 const pen& pena, const pair& a, double ra,
276 bool extenda, const pen& penb, const pair& b,
277 double rb, bool extendb);
278
begingouraudshade(const vm::array & pens,const vm::array & vertices,const vm::array & edges)279 virtual void begingouraudshade(const vm::array& pens,
280 const vm::array& vertices,
281 const vm::array& edges) {}
282 virtual void gouraudshade(const pen& pentype, const vm::array& pens,
283 const vm::array& vertices, const vm::array& edges);
284
285 virtual void tensorshade(const pen& pentype, const vm::array& pens,
286 const vm::array& boundaries, const vm::array& z);
287
288 void vertexpen(vm::array *pi, int j, ColorSpace colorspace);
289
290 void imageheader(size_t width, size_t height, ColorSpace colorspace);
291
292 void image(const vm::array& a, const vm::array& p, bool antialias);
293 void image(const vm::array& a, bool antialias);
294 void image(vm::stack *Stack, vm::callable *f, Int width, Int height,
295 bool antialias);
296
297 void rawimage(unsigned char *a, size_t width, size_t height, bool antialias);
298
299 virtual void gsave(bool tex=false) {
300 if(pdf) *out << "q";
301 else *out << "gsave";
302 if(!tex) *out << newl;
303 pens.push(lastpen);
304 }
305
306 virtual void grestore(bool tex=false) {
307 if(pens.size() < 1)
308 reportError("grestore without matching gsave");
309 lastpen=pens.top();
310 pens.pop();
311 if(pdf) *out << "Q";
312 else *out << "grestore";
313 if(!tex) *out << newl;
314 }
315
translate(pair z)316 virtual void translate(pair z) {
317 if(z == pair(0.0,0.0)) return;
318 if(pdf) *out << " 1 0 0 1 " << newl;
319 write(z);
320 if(pdf) *out << " cm" << newl;
321 *out << " translate" << newl;
322 }
323
324 // Multiply on a transform to the transformation matrix.
concat(transform t)325 virtual void concat(transform t) {
326 if(t.isIdentity()) return;
327 write(t);
328 if(pdf) *out << " cm" << newl;
329 else *out << " concat" << newl;
330 }
331
verbatimline(const string & s)332 void verbatimline(const string& s) {
333 *out << s << newl;
334 }
335
verbatim(const string & s)336 void verbatim(const string& s) {
337 *out << s;
338 }
339
340 // Determine shading and image transparency based on first pen.
setfirstopacity(const vm::array & pens)341 void setfirstopacity(const vm::array& pens) {
342 if(pens.size() > 0) {
343 pen *p=vm::read<pen *>(pens,0);
344 setopacity(*p);
345 }
346 }
347
maxcolorspace(const vm::array & pens)348 ColorSpace maxcolorspace(const vm::array& pens) {
349 ColorSpace colorspace=DEFCOLOR;
350 size_t size=pens.size();
351 for(size_t i=0; i < size; i++) {
352 pen *p=vm::read<pen *>(pens,i);
353 p->convert();
354 colorspace=max(colorspace,p->colorspace());
355 }
356 return colorspace;
357 }
358
maxcolorspace2(const vm::array & penarray)359 ColorSpace maxcolorspace2(const vm::array& penarray) {
360 ColorSpace colorspace=DEFCOLOR;
361 size_t size=penarray.size();
362 for(size_t i=0; i < size; i++)
363 colorspace=max(colorspace,
364 maxcolorspace(vm::read<vm::array>(penarray,i)));
365 return colorspace;
366 }
367
368 };
369
370 } //namespace camp
371
372 #endif
373