Statistics
| Revision:

gvsig-raster / libjni-potrace / trunk / libjni-potrace / src / main / native / jpotrace / backend_svg.c @ 1780

History | View | Annotate | Download (8.05 KB)

1
/* Copyright (C) 2001-2007 Peter Selinger.
2
   This file is part of Potrace. It is free software and it is covered
3
   by the GNU General Public License. See the file COPYING for details. */
4

    
5
/* $Id: backend_svg.c 147 2007-04-09 00:44:09Z selinger $ */
6

    
7
/* The SVG backend of Potrace. */
8

    
9
#include <stdio.h>
10
#include <stdarg.h>
11
#include <string.h>
12
#include <math.h>
13

    
14
#include "potracelib.h"
15
#include "curve.h"
16
#include "main.h"
17
#include "backend_svg.h"
18
#include "lists.h"
19
#include "auxiliary.h"
20

    
21
#ifdef HAVE_CONFIG_H
22
#include "config.h"
23
#endif
24

    
25
/* ---------------------------------------------------------------------- */
26
/* path-drawing auxiliary functions */
27

    
28
/* coordinate quantization */
29
static inline point_t unit(dpoint_t p) {
30
  point_t q;
31

    
32
  q.x = (long)(floor(p.x*info.unit+.5));
33
  q.y = (long)(floor(p.y*info.unit+.5));
34
  return q;
35
}
36

    
37
static point_t cur;
38
static char lastop = 0;
39
static int column = 0;
40
static int newline = 1;
41

    
42
static void shiptoken(FILE *fout, char *token) {
43
  int c = strlen(token);
44
  if (!newline && column+c+1 > 75) {
45
    fprintf(fout, "\n");
46
    column = 0;
47
    newline = 1;
48
  } else if (!newline) {
49
    fprintf(fout, " ");
50
    column++;
51
  }
52
  fprintf(fout, "%s", token);
53
  column += c;
54
  newline = 0;
55
}
56

    
57
static void ship(FILE *fout, char *fmt, ...) {
58
  va_list args;
59
  static char buf[4096]; /* static string limit is okay here because
60
                            we only use constant format strings - for
61
                            the same reason, it is okay to use
62
                            vsprintf instead of vsnprintf below. */
63
  char *p, *q;
64

    
65
  va_start(args, fmt);
66
  vsprintf(buf, fmt, args);
67
  buf[4095] = 0;
68
  va_end(args);
69

    
70
  p = buf;
71
  while ((q = strchr(p, ' ')) != NULL) {
72
    *q = 0;
73
    shiptoken(fout, p);
74
    p = q+1;
75
  }
76
  shiptoken(fout, p);
77
}
78

    
79
static void svg_moveto(FILE *fout, dpoint_t p) {
80
  cur = unit(p);
81

    
82
  ship(fout, "M%ld %ld", cur.x, cur.y);
83
  lastop = 'M';
84
}
85

    
86
static void svg_rmoveto(FILE *fout, dpoint_t p) {
87
  point_t q;
88

    
89
  q = unit(p);
90
  ship(fout, "m%ld %ld", q.x-cur.x, q.y-cur.y);
91
  cur = q;
92
  lastop = 'm';
93
}
94

    
95
static void svg_lineto(FILE *fout, dpoint_t p) {
96
  point_t q;
97

    
98
  q = unit(p);
99

    
100
  if (lastop != 'l') {
101
    ship(fout, "l%ld %ld", q.x-cur.x, q.y-cur.y);
102
  } else {
103
    ship(fout, "%ld %ld", q.x-cur.x, q.y-cur.y);
104
  }
105
  cur = q;
106
  lastop = 'l';
107
}
108

    
109
static void svg_curveto(FILE *fout, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
110
  point_t q1, q2, q3;
111

    
112
  q1 = unit(p1);
113
  q2 = unit(p2);
114
  q3 = unit(p3);
115

    
116
  if (lastop != 'c') {
117
    ship(fout, "c%ld %ld %ld %ld %ld %ld", q1.x-cur.x, q1.y-cur.y, q2.x-cur.x, q2.y-cur.y, q3.x-cur.x, q3.y-cur.y);
118
  } else {
119
    ship(fout, "%ld %ld %ld %ld %ld %ld", q1.x-cur.x, q1.y-cur.y, q2.x-cur.x, q2.y-cur.y, q3.x-cur.x, q3.y-cur.y);
120
  }
121
  cur = q3;
122
  lastop = 'c';
123
}
124

    
125
/* ---------------------------------------------------------------------- */
126
/* functions for converting a path to an SVG path element */
127

    
128
/* Explicit encoding. If abs is set, move to first coordinate
129
   absolutely. */
130
static int svg_path(FILE *fout, potrace_curve_t *curve, int abs) {
131
  int i;
132
  dpoint_t *c;
133
  int m = curve->n;
134

    
135
  c = curve->c[m-1];
136
  if (abs) {
137
    svg_moveto(fout, c[2]);
138
  } else {
139
    svg_rmoveto(fout, c[2]);
140
  }
141

    
142
  for (i=0; i<m; i++) {
143
    c = curve->c[i];
144
    switch (curve->tag[i]) {
145
    case POTRACE_CORNER:
146
      svg_lineto(fout, c[1]);
147
      svg_lineto(fout, c[2]);
148
      break;
149
    case POTRACE_CURVETO:
150
      svg_curveto(fout, c[0], c[1], c[2]);
151
      break;
152
    }
153
  }
154
  newline = 1;
155
  shiptoken(fout, "z");
156
  return 0;
157
}
158

    
159
/* produce a jaggy path - for debugging. If abs is set, move to first
160
   coordinate absolutely. If abs is not set, move to first coordinate
161
   relatively, and traverse path in the opposite direction. */
162
static int svg_jaggy_path(FILE *fout, point_t *pt, int n, int abs) {
163
  int i;
164
  point_t cur, prev;
165
  
166
  if (abs) {
167
    cur = prev = pt[n-1];
168
    svg_moveto(fout, dpoint(cur));
169
    for (i=0; i<n; i++) {
170
      if (pt[i].x != cur.x && pt[i].y != cur.y) {
171
        cur = prev;
172
        svg_lineto(fout, dpoint(cur));
173
      }
174
      prev = pt[i];
175
    }
176
    svg_lineto(fout, dpoint(pt[n-1]));
177
  } else {
178
    cur = prev = pt[0];
179
    svg_rmoveto(fout, dpoint(cur));
180
    for (i=n-1; i>=0; i--) {
181
      if (pt[i].x != cur.x && pt[i].y != cur.y) {
182
        cur = prev;
183
        svg_lineto(fout, dpoint(cur));
184
      }
185
      prev = pt[i];
186
    }
187
    svg_lineto(fout, dpoint(pt[0]));
188
  }
189
  newline = 1;
190
  shiptoken(fout, "z");
191
  return 0;
192
}
193

    
194
static void write_paths_opaque(FILE *fout, potrace_path_t *tree) {
195
  potrace_path_t *p, *q;
196
  int c;
197

    
198
  for (p=tree; p; p=p->sibling) {
199
    if (info.group) {
200
      fprintf(fout, "<g>\n");
201
      fprintf(fout, "<g>\n");
202
    }
203
    c = fprintf(fout, "<path fill=\"#%06x\" stroke=\"none\" d=\"", info.color);
204
    column = c;
205
    newline = 1;
206
    lastop = 0;
207
    if (info.debug == 1) {
208
      svg_jaggy_path(fout, p->priv->pt, p->priv->len, 1);
209
    } else {
210
      svg_path(fout, &p->curve, 1);
211
    }
212
    fprintf(fout, "\"/>\n");
213
    for (q=p->childlist; q; q=q->sibling) {
214
      c = fprintf(fout, "<path fill=\"#%06x\" stroke=\"none\" d=\"", info.fillcolor);
215
      column = c;
216
      newline = 1;
217
      lastop = 0;
218
      if (info.debug == 1) {
219
        svg_jaggy_path(fout, q->priv->pt, q->priv->len, 1);
220
      } else {
221
        svg_path(fout, &q->curve, 1);
222
      }
223
      fprintf(fout, "\"/>\n");
224
    }
225
    if (info.group) {
226
      fprintf(fout, "</g>\n");
227
    }
228
    for (q=p->childlist; q; q=q->sibling) {
229
      write_paths_opaque(fout, q->childlist);
230
    }
231
    if (info.group) {
232
      fprintf(fout, "</g>\n");
233
    }
234
  }
235
}
236

    
237
static void write_paths_transparent(FILE *fout, potrace_path_t *tree) {
238
  potrace_path_t *p, *q;
239
  int c;
240

    
241
  for (p=tree; p; p=p->sibling) {
242
    if (info.group) {
243
      fprintf(fout, "<g>\n");
244
    }
245
    c = fprintf(fout, "<path d=\"");
246
    column = c;
247
    newline = 1;
248
    lastop = 0;
249
    if (info.debug == 1) {
250
      svg_jaggy_path(fout, p->priv->pt, p->priv->len, 1);
251
    } else {
252
      svg_path(fout, &p->curve, 1);
253
    }
254
    for (q=p->childlist; q; q=q->sibling) {
255
      if (info.debug == 1) {
256
        svg_jaggy_path(fout, q->priv->pt, q->priv->len, 0);
257
      } else {
258
        svg_path(fout, &q->curve, 0);
259
      }
260
    }
261
    fprintf(fout, "\"/>\n");
262
    for (q=p->childlist; q; q=q->sibling) {
263
      write_paths_transparent(fout, q->childlist);
264
    }
265
    if (info.group) {
266
      fprintf(fout, "</g>\n");
267
    }
268
  }
269
}
270

    
271
/* ---------------------------------------------------------------------- */
272
/* Backend. */
273

    
274
/* public interface for SVG */
275
int page_svg(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) {
276

    
277
  int bboxx = (int)ceil(imginfo->trans.bb[0]+imginfo->lmar+imginfo->rmar);
278
  int bboxy = (int)ceil(imginfo->trans.bb[1]+imginfo->tmar+imginfo->bmar);
279
  double origx = imginfo->trans.orig[0] + imginfo->lmar;
280
  double origy = bboxy - imginfo->trans.orig[1] - imginfo->bmar;
281
  double scalex = imginfo->width / imginfo->pixwidth / info.unit;
282
  double scaley = -imginfo->height / imginfo->pixheight / info.unit;
283

    
284
  /* header */
285
  fprintf(fout, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
286
  fprintf(fout, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
287
  fprintf(fout, " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
288

    
289
  /* set bounding box and namespace */
290
  fprintf(fout, "<svg version=\"1.0\" xmlns=\"http://www.w3.org/2000/svg\"\n");
291
  fprintf(fout, " width=\"%dpt\" height=\"%dpt\" viewBox=\"0 0 %d %d\"\n", 
292
          bboxx, bboxy, bboxx, bboxy);
293
  fprintf(fout, " preserveAspectRatio=\"xMidYMid meet\">\n");
294

    
295
  /* metadata: creator */
296
  fprintf(fout, "<metadata>\n");
297
  fprintf(fout, "Created by \"POTRACE\" \"VERSION\", written by Peter Selinger 2001-2007\n");
298
  fprintf(fout, "</metadata>\n");
299

    
300
  /* use a "group" tag to establish coordinate system and style */
301
  fprintf(fout, "<g transform=\"");
302
  if (origx != 0 || origy != 0) {
303
    fprintf(fout, "translate(%.0f,%.0f) ", origx, origy);
304
  }
305
  if (info.angle != 0) {
306
    fprintf(fout, "rotate(%.2f) ", -info.angle);
307
  }
308
  fprintf(fout, "scale(%f,%f)", scalex, scaley);
309
  fprintf(fout, "\"\n");
310
  fprintf(fout, "fill=\"#%06x\" stroke=\"none\">\n", info.color);
311

    
312
  if (info.opaque) {
313
    write_paths_opaque(fout, plist);
314
  } else {
315
    write_paths_transparent(fout, plist);
316
  }
317

    
318
  /* write footer */
319
  fprintf(fout, "</g>\n");
320
  fprintf(fout, "</svg>\n");
321
  fflush(fout);
322

    
323
  return 0;
324
}
325