/***** * psfile.h * Andy Hammerlindl 2002/06/10 * * Encapsulates the writing of commands to a PostScript file. * Allows identification and removal of redundant commands. *****/ #ifndef PSFILE_H #define PSFILE_H #include #include #include #include "pair.h" #include "path.h" #include "bbox.h" #include "pen.h" #include "array.h" #include "callable.h" namespace camp { inline void BoundingBox(std::ostream& s, const bbox& box) { s << "%%BoundingBox: " << std::setprecision(0) << std::fixed << box.LowRes() << newl; s.unsetf(std::ios::fixed); s << "%%HiResBoundingBox: " << std::setprecision(9) << box << newl; } // An ASCII85Encode filter. class encode85 { ostream *out; int tuple; int pos; int count; static const int width=72; public: encode85(ostream *out) : out(out), tuple(0), pos(0), count(0) {} ~encode85() { if(count > 0) encode(tuple, count); if(pos+2 > width) *out << '\n'; *out << "~>\n"; } private: void encode(unsigned int tuple, int count) { unsigned char buf[5], *s=buf; int i=5; do { *s++=tuple % 85; tuple /= 85; } while(--i > 0); i=count; do { *out << (unsigned char) (*--s + '!'); if(pos++ >= width) { pos=0; *out << '\n'; } } while(i-- > 0); } public: void put(unsigned char c) { switch (count++) { case 0: tuple |= (c << 24); break; case 1: tuple |= (c << 16); break; case 2: tuple |= (c << 8); break; case 3: tuple |= c; if(tuple == 0) { *out << 'z'; if(pos++ >= width) { pos=0; *out << '\n'; } } else encode(tuple, count); tuple=0; count=0; break; } } }; class psfile { protected: mem::stack pens; public: string filename; bool pdfformat; // Is final output format PDF? bool pdf; // Output direct PDF? unsigned char *buffer; size_t count; void write(pen *p, size_t ncomponents); void writefromRGB(unsigned char r, unsigned char g, unsigned char b, ColorSpace colorspace, size_t ncomponents); void writeCompressed(const unsigned char *a, size_t size); void dealias(unsigned char *a, size_t width, size_t height, size_t n, bool convertrgb=false, ColorSpace colorspace=DEFCOLOR); void beginImage(size_t n) { buffer=new unsigned char[n]; count=0; } void outImage(bool antialias, size_t width, size_t height, size_t ncomponents); void endImage(bool antialias, size_t width, size_t height, size_t ncomponents) { outImage(antialias,width,height,ncomponents); delete[] buffer; } void writeByte(unsigned char n) { buffer[count++]=n; } protected: pen lastpen; std::ostream *out; public: bool pdftex() {return settings::pdf(settings::getSetting("tex"));} psfile(const string& filename, bool pdfformat); psfile() {pdf=pdftex();} bool transparentFormat(string outputformat); virtual ~psfile(); void BoundingBox(const bbox& box) { camp::BoundingBox(*out,box); } void prologue(const bbox& box); void epilogue(); void header(bool eps); void close(); void write(double x) { *out << " " << x; } void writenewl() { *out << newl; } void write(pair z) { *out << " " << z.getx() << " " << z.gety(); } void write(transform t) { if(!pdf) *out << "["; *out << " " << t.getxx() << " " << t.getyx() << " " << t.getxy() << " " << t.getyy() << " " << t.getx() << " " << t.gety(); if(!pdf) *out << "]"; } void resetpen() { lastpen=pen(initialpen); lastpen.convert(); } void setcolor(const pen& p, const string& begin, const string& end); void setopacity(const pen& p); virtual void setpen(pen p); void write(const pen& p); void write(path p, bool newPath=true); virtual void writeclip(path p, bool newPath=true) { write(p,newPath); } virtual void dot(path p, pen, bool newPath=true) { write(p,newPath); } virtual void newpath() { if(!pdf) *out << "newpath"; } virtual void moveto(pair z) { write(z); if(pdf) *out << " m" << newl; else *out << " moveto" << newl; } virtual void lineto(pair z) { write(z); if(pdf) *out << " l" << newl; else *out << " lineto" << newl; } virtual void curveto(pair zp, pair zm, pair z1) { write(zp); write(zm); write(z1); if(pdf) *out << " c" << newl; else *out << " curveto" << newl; } virtual void closepath() { if(pdf) *out << "h" << newl; else *out << "closepath" << newl; } virtual void stroke(const pen &p, bool dot=false) { if(pdf) *out << "S" << newl; else *out << "stroke" << newl; } virtual void strokepath() { if(pdf) reportError("PDF does not support strokepath"); else *out << "strokepath" << newl; } virtual void fill(const pen &p) { if(p.evenodd()) { if(pdf) *out << "f*" << newl; else *out << "eofill" << newl; } else { if(pdf) *out << "f" << newl; else *out << "fill" << newl; } } virtual void beginclip() { newpath(); } virtual void endclip(const pen &p) { if(p.evenodd()) { if(pdf) *out << "W* n" << newl; else *out << "eoclip" << newl; } else { if(pdf) *out << "W n" << newl; else *out << "clip" << newl; } } virtual void endpsclip(const pen &p) {endclip(p);} void checkLevel() { int n=settings::getSetting("level"); if(n < 3) reportError("PostScript shading requires -level 3"); } virtual void beginlatticeshade(const vm::array& a, const bbox& b) {} virtual void latticeshade(const vm::array& a, const transform& t); virtual void begingradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, const pen& penb, const pair& b, double rb) {} virtual void gradientshade(bool axial, ColorSpace colorspace, const pen& pena, const pair& a, double ra, bool extenda, const pen& penb, const pair& b, double rb, bool extendb); virtual void begingouraudshade(const vm::array& pens, const vm::array& vertices, const vm::array& edges) {} virtual void gouraudshade(const pen& pentype, const vm::array& pens, const vm::array& vertices, const vm::array& edges); virtual void tensorshade(const pen& pentype, const vm::array& pens, const vm::array& boundaries, const vm::array& z); void vertexpen(vm::array *pi, int j, ColorSpace colorspace); void imageheader(size_t width, size_t height, ColorSpace colorspace); void image(const vm::array& a, const vm::array& p, bool antialias); void image(const vm::array& a, bool antialias); void image(vm::stack *Stack, vm::callable *f, Int width, Int height, bool antialias); void rawimage(unsigned char *a, size_t width, size_t height, bool antialias); virtual void gsave(bool tex=false) { if(pdf) *out << "q"; else *out << "gsave"; if(!tex) *out << newl; pens.push(lastpen); } virtual void grestore(bool tex=false) { if(pens.size() < 1) reportError("grestore without matching gsave"); lastpen=pens.top(); pens.pop(); if(pdf) *out << "Q"; else *out << "grestore"; if(!tex) *out << newl; } virtual void translate(pair z) { if(z == pair(0.0,0.0)) return; if(pdf) *out << " 1 0 0 1 " << newl; write(z); if(pdf) *out << " cm" << newl; *out << " translate" << newl; } // Multiply on a transform to the transformation matrix. virtual void concat(transform t) { if(t.isIdentity()) return; write(t); if(pdf) *out << " cm" << newl; else *out << " concat" << newl; } void verbatimline(const string& s) { *out << s << newl; } void verbatim(const string& s) { *out << s; } // Determine shading and image transparency based on first pen. void setfirstopacity(const vm::array& pens) { if(pens.size() > 0) { pen *p=vm::read(pens,0); setopacity(*p); } } ColorSpace maxcolorspace(const vm::array& pens) { ColorSpace colorspace=DEFCOLOR; size_t size=pens.size(); for(size_t i=0; i < size; i++) { pen *p=vm::read(pens,i); p->convert(); colorspace=max(colorspace,p->colorspace()); } return colorspace; } ColorSpace maxcolorspace2(const vm::array& penarray) { ColorSpace colorspace=DEFCOLOR; size_t size=penarray.size(); for(size_t i=0; i < size; i++) colorspace=max(colorspace, maxcolorspace(vm::read(penarray,i))); return colorspace; } }; } //namespace camp #endif