00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <stdio.h>
00010 #include <stdarg.h>
00011 #include <string.h>
00012 #include <math.h>
00013
00014 #include "potracelib.h"
00015 #include "curve.h"
00016 #include "main.h"
00017 #include "backend_svg.h"
00018 #include "lists.h"
00019 #include "auxiliary.h"
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025
00026
00027
00028
00029 static inline point_t unit(dpoint_t p) {
00030 point_t q;
00031
00032 q.x = (long)(floor(p.x*info.unit+.5));
00033 q.y = (long)(floor(p.y*info.unit+.5));
00034 return q;
00035 }
00036
00037 static point_t cur;
00038 static char lastop = 0;
00039 static int column = 0;
00040 static int newline = 1;
00041
00042 static void shiptoken(FILE *fout, char *token) {
00043 int c = strlen(token);
00044 if (!newline && column+c+1 > 75) {
00045 fprintf(fout, "\n");
00046 column = 0;
00047 newline = 1;
00048 } else if (!newline) {
00049 fprintf(fout, " ");
00050 column++;
00051 }
00052 fprintf(fout, "%s", token);
00053 column += c;
00054 newline = 0;
00055 }
00056
00057 static void ship(FILE *fout, char *fmt, ...) {
00058 va_list args;
00059 static char buf[4096];
00060
00061
00062
00063 char *p, *q;
00064
00065 va_start(args, fmt);
00066 vsprintf(buf, fmt, args);
00067 buf[4095] = 0;
00068 va_end(args);
00069
00070 p = buf;
00071 while ((q = strchr(p, ' ')) != NULL) {
00072 *q = 0;
00073 shiptoken(fout, p);
00074 p = q+1;
00075 }
00076 shiptoken(fout, p);
00077 }
00078
00079 static void svg_moveto(FILE *fout, dpoint_t p) {
00080 cur = unit(p);
00081
00082 ship(fout, "M%ld %ld", cur.x, cur.y);
00083 lastop = 'M';
00084 }
00085
00086 static void svg_rmoveto(FILE *fout, dpoint_t p) {
00087 point_t q;
00088
00089 q = unit(p);
00090 ship(fout, "m%ld %ld", q.x-cur.x, q.y-cur.y);
00091 cur = q;
00092 lastop = 'm';
00093 }
00094
00095 static void svg_lineto(FILE *fout, dpoint_t p) {
00096 point_t q;
00097
00098 q = unit(p);
00099
00100 if (lastop != 'l') {
00101 ship(fout, "l%ld %ld", q.x-cur.x, q.y-cur.y);
00102 } else {
00103 ship(fout, "%ld %ld", q.x-cur.x, q.y-cur.y);
00104 }
00105 cur = q;
00106 lastop = 'l';
00107 }
00108
00109 static void svg_curveto(FILE *fout, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
00110 point_t q1, q2, q3;
00111
00112 q1 = unit(p1);
00113 q2 = unit(p2);
00114 q3 = unit(p3);
00115
00116 if (lastop != 'c') {
00117 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);
00118 } else {
00119 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);
00120 }
00121 cur = q3;
00122 lastop = 'c';
00123 }
00124
00125
00126
00127
00128
00129
00130 static int svg_path(FILE *fout, potrace_curve_t *curve, int abs) {
00131 int i;
00132 dpoint_t *c;
00133 int m = curve->n;
00134
00135 c = curve->c[m-1];
00136 if (abs) {
00137 svg_moveto(fout, c[2]);
00138 } else {
00139 svg_rmoveto(fout, c[2]);
00140 }
00141
00142 for (i=0; i<m; i++) {
00143 c = curve->c[i];
00144 switch (curve->tag[i]) {
00145 case POTRACE_CORNER:
00146 svg_lineto(fout, c[1]);
00147 svg_lineto(fout, c[2]);
00148 break;
00149 case POTRACE_CURVETO:
00150 svg_curveto(fout, c[0], c[1], c[2]);
00151 break;
00152 }
00153 }
00154 newline = 1;
00155 shiptoken(fout, "z");
00156 return 0;
00157 }
00158
00159
00160
00161
00162 static int svg_jaggy_path(FILE *fout, point_t *pt, int n, int abs) {
00163 int i;
00164 point_t cur, prev;
00165
00166 if (abs) {
00167 cur = prev = pt[n-1];
00168 svg_moveto(fout, dpoint(cur));
00169 for (i=0; i<n; i++) {
00170 if (pt[i].x != cur.x && pt[i].y != cur.y) {
00171 cur = prev;
00172 svg_lineto(fout, dpoint(cur));
00173 }
00174 prev = pt[i];
00175 }
00176 svg_lineto(fout, dpoint(pt[n-1]));
00177 } else {
00178 cur = prev = pt[0];
00179 svg_rmoveto(fout, dpoint(cur));
00180 for (i=n-1; i>=0; i--) {
00181 if (pt[i].x != cur.x && pt[i].y != cur.y) {
00182 cur = prev;
00183 svg_lineto(fout, dpoint(cur));
00184 }
00185 prev = pt[i];
00186 }
00187 svg_lineto(fout, dpoint(pt[0]));
00188 }
00189 newline = 1;
00190 shiptoken(fout, "z");
00191 return 0;
00192 }
00193
00194 static void write_paths_opaque(FILE *fout, potrace_path_t *tree) {
00195 potrace_path_t *p, *q;
00196 int c;
00197
00198 for (p=tree; p; p=p->sibling) {
00199 if (info.group) {
00200 fprintf(fout, "<g>\n");
00201 fprintf(fout, "<g>\n");
00202 }
00203 c = fprintf(fout, "<path fill=\"#%06x\" stroke=\"none\" d=\"", info.color);
00204 column = c;
00205 newline = 1;
00206 lastop = 0;
00207 if (info.debug == 1) {
00208 svg_jaggy_path(fout, p->priv->pt, p->priv->len, 1);
00209 } else {
00210 svg_path(fout, &p->curve, 1);
00211 }
00212 fprintf(fout, "\"/>\n");
00213 for (q=p->childlist; q; q=q->sibling) {
00214 c = fprintf(fout, "<path fill=\"#%06x\" stroke=\"none\" d=\"", info.fillcolor);
00215 column = c;
00216 newline = 1;
00217 lastop = 0;
00218 if (info.debug == 1) {
00219 svg_jaggy_path(fout, q->priv->pt, q->priv->len, 1);
00220 } else {
00221 svg_path(fout, &q->curve, 1);
00222 }
00223 fprintf(fout, "\"/>\n");
00224 }
00225 if (info.group) {
00226 fprintf(fout, "</g>\n");
00227 }
00228 for (q=p->childlist; q; q=q->sibling) {
00229 write_paths_opaque(fout, q->childlist);
00230 }
00231 if (info.group) {
00232 fprintf(fout, "</g>\n");
00233 }
00234 }
00235 }
00236
00237 static void write_paths_transparent(FILE *fout, potrace_path_t *tree) {
00238 potrace_path_t *p, *q;
00239 int c;
00240
00241 for (p=tree; p; p=p->sibling) {
00242 if (info.group) {
00243 fprintf(fout, "<g>\n");
00244 }
00245 c = fprintf(fout, "<path d=\"");
00246 column = c;
00247 newline = 1;
00248 lastop = 0;
00249 if (info.debug == 1) {
00250 svg_jaggy_path(fout, p->priv->pt, p->priv->len, 1);
00251 } else {
00252 svg_path(fout, &p->curve, 1);
00253 }
00254 for (q=p->childlist; q; q=q->sibling) {
00255 if (info.debug == 1) {
00256 svg_jaggy_path(fout, q->priv->pt, q->priv->len, 0);
00257 } else {
00258 svg_path(fout, &q->curve, 0);
00259 }
00260 }
00261 fprintf(fout, "\"/>\n");
00262 for (q=p->childlist; q; q=q->sibling) {
00263 write_paths_transparent(fout, q->childlist);
00264 }
00265 if (info.group) {
00266 fprintf(fout, "</g>\n");
00267 }
00268 }
00269 }
00270
00271
00272
00273
00274
00275 int page_svg(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) {
00276
00277 int bboxx = (int)ceil(imginfo->trans.bb[0]+imginfo->lmar+imginfo->rmar);
00278 int bboxy = (int)ceil(imginfo->trans.bb[1]+imginfo->tmar+imginfo->bmar);
00279 double origx = imginfo->trans.orig[0] + imginfo->lmar;
00280 double origy = bboxy - imginfo->trans.orig[1] - imginfo->bmar;
00281 double scalex = imginfo->width / imginfo->pixwidth / info.unit;
00282 double scaley = -imginfo->height / imginfo->pixheight / info.unit;
00283
00284
00285 fprintf(fout, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
00286 fprintf(fout, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
00287 fprintf(fout, " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
00288
00289
00290 fprintf(fout, "<svg version=\"1.0\" xmlns=\"http://www.w3.org/2000/svg\"\n");
00291 fprintf(fout, " width=\"%dpt\" height=\"%dpt\" viewBox=\"0 0 %d %d\"\n",
00292 bboxx, bboxy, bboxx, bboxy);
00293 fprintf(fout, " preserveAspectRatio=\"xMidYMid meet\">\n");
00294
00295
00296 fprintf(fout, "<metadata>\n");
00297 fprintf(fout, "Created by "POTRACE" "VERSION", written by Peter Selinger 2001-2007\n");
00298 fprintf(fout, "</metadata>\n");
00299
00300
00301 fprintf(fout, "<g transform=\"");
00302 if (origx != 0 || origy != 0) {
00303 fprintf(fout, "translate(%.0f,%.0f) ", origx, origy);
00304 }
00305 if (info.angle != 0) {
00306 fprintf(fout, "rotate(%.2f) ", -info.angle);
00307 }
00308 fprintf(fout, "scale(%f,%f)", scalex, scaley);
00309 fprintf(fout, "\"\n");
00310 fprintf(fout, "fill=\"#%06x\" stroke=\"none\">\n", info.color);
00311
00312 if (info.opaque) {
00313 write_paths_opaque(fout, plist);
00314 } else {
00315 write_paths_transparent(fout, plist);
00316 }
00317
00318
00319 fprintf(fout, "</g>\n");
00320 fprintf(fout, "</svg>\n");
00321 fflush(fout);
00322
00323 return 0;
00324 }
00325