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