summaryrefslogtreecommitdiff
path: root/graphics/asymptote/psfile.h
blob: b722fe4a4372a7dca95a020ae80477a8a2377008 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
/*****
 * 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 <fstream>
#include <iomanip>
#include <sstream>

#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<pen> 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<string>("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<Int>("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<pen *>(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<pen *>(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<vm::array>(penarray,i)));
    return colorspace;
  }

};

} //namespace camp

#endif