diff options
Diffstat (limited to 'Build/source/libs/potrace/potrace-1.12/src/backend_svg.c')
-rw-r--r-- | Build/source/libs/potrace/potrace-1.12/src/backend_svg.c | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/Build/source/libs/potrace/potrace-1.12/src/backend_svg.c b/Build/source/libs/potrace/potrace-1.12/src/backend_svg.c new file mode 100644 index 00000000000..fd30eda4eb4 --- /dev/null +++ b/Build/source/libs/potrace/potrace-1.12/src/backend_svg.c @@ -0,0 +1,342 @@ +/* Copyright (C) 2001-2015 Peter Selinger. + This file is part of Potrace. It is free software and it is covered + by the GNU General Public License. See the file COPYING for details. */ + + +/* The SVG backend of Potrace. */ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> + +#include "potracelib.h" +#include "curve.h" +#include "main.h" +#include "backend_svg.h" +#include "lists.h" +#include "auxiliary.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* ---------------------------------------------------------------------- */ +/* path-drawing auxiliary functions */ + +/* coordinate quantization */ +static inline point_t unit(dpoint_t p) { + point_t q; + + q.x = (long)(floor(p.x*info.unit+.5)); + q.y = (long)(floor(p.y*info.unit+.5)); + return q; +} + +static point_t cur; +static char lastop = 0; +static int column = 0; +static int newline = 1; + +static void shiptoken(FILE *fout, char *token) { + int c = strlen(token); + if (!newline && column+c+1 > 75) { + fprintf(fout, "\n"); + column = 0; + newline = 1; + } else if (!newline) { + fprintf(fout, " "); + column++; + } + fprintf(fout, "%s", token); + column += c; + newline = 0; +} + +static void ship(FILE *fout, char *fmt, ...) { + va_list args; + static char buf[4096]; /* static string limit is okay here because + we only use constant format strings - for + the same reason, it is okay to use + vsprintf instead of vsnprintf below. */ + char *p, *q; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + buf[4095] = 0; + va_end(args); + + p = buf; + while ((q = strchr(p, ' ')) != NULL) { + *q = 0; + shiptoken(fout, p); + p = q+1; + } + shiptoken(fout, p); +} + +static void svg_moveto(FILE *fout, dpoint_t p) { + cur = unit(p); + + ship(fout, "M%ld %ld", cur.x, cur.y); + lastop = 'M'; +} + +static void svg_rmoveto(FILE *fout, dpoint_t p) { + point_t q; + + q = unit(p); + ship(fout, "m%ld %ld", q.x-cur.x, q.y-cur.y); + cur = q; + lastop = 'm'; +} + +static void svg_lineto(FILE *fout, dpoint_t p) { + point_t q; + + q = unit(p); + + if (lastop != 'l') { + ship(fout, "l%ld %ld", q.x-cur.x, q.y-cur.y); + } else { + ship(fout, "%ld %ld", q.x-cur.x, q.y-cur.y); + } + cur = q; + lastop = 'l'; +} + +static void svg_curveto(FILE *fout, dpoint_t p1, dpoint_t p2, dpoint_t p3) { + point_t q1, q2, q3; + + q1 = unit(p1); + q2 = unit(p2); + q3 = unit(p3); + + if (lastop != 'c') { + 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); + } else { + 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); + } + cur = q3; + lastop = 'c'; +} + +/* ---------------------------------------------------------------------- */ +/* functions for converting a path to an SVG path element */ + +/* Explicit encoding. If abs is set, move to first coordinate + absolutely. */ +static int svg_path(FILE *fout, potrace_curve_t *curve, int abs) { + int i; + dpoint_t *c; + int m = curve->n; + + c = curve->c[m-1]; + if (abs) { + svg_moveto(fout, c[2]); + } else { + svg_rmoveto(fout, c[2]); + } + + for (i=0; i<m; i++) { + c = curve->c[i]; + switch (curve->tag[i]) { + case POTRACE_CORNER: + svg_lineto(fout, c[1]); + svg_lineto(fout, c[2]); + break; + case POTRACE_CURVETO: + svg_curveto(fout, c[0], c[1], c[2]); + break; + } + } + newline = 1; + shiptoken(fout, "z"); + return 0; +} + +/* produce a jaggy path - for debugging. If abs is set, move to first + coordinate absolutely. If abs is not set, move to first coordinate + relatively, and traverse path in the opposite direction. */ +static int svg_jaggy_path(FILE *fout, point_t *pt, int n, int abs) { + int i; + point_t cur, prev; + + if (abs) { + cur = prev = pt[n-1]; + svg_moveto(fout, dpoint(cur)); + for (i=0; i<n; i++) { + if (pt[i].x != cur.x && pt[i].y != cur.y) { + cur = prev; + svg_lineto(fout, dpoint(cur)); + } + prev = pt[i]; + } + svg_lineto(fout, dpoint(pt[n-1])); + } else { + cur = prev = pt[0]; + svg_rmoveto(fout, dpoint(cur)); + for (i=n-1; i>=0; i--) { + if (pt[i].x != cur.x && pt[i].y != cur.y) { + cur = prev; + svg_lineto(fout, dpoint(cur)); + } + prev = pt[i]; + } + svg_lineto(fout, dpoint(pt[0])); + } + newline = 1; + shiptoken(fout, "z"); + return 0; +} + +static void write_paths_opaque(FILE *fout, potrace_path_t *tree) { + potrace_path_t *p, *q; + + for (p=tree; p; p=p->sibling) { + if (info.grouping == 2) { + fprintf(fout, "<g>\n"); + fprintf(fout, "<g>\n"); + } + column = fprintf(fout, "<path fill=\"#%06x\" stroke=\"none\" d=\"", info.color); + newline = 1; + lastop = 0; + if (info.debug == 1) { + svg_jaggy_path(fout, p->priv->pt, p->priv->len, 1); + } else { + svg_path(fout, &p->curve, 1); + } + fprintf(fout, "\"/>\n"); + for (q=p->childlist; q; q=q->sibling) { + column = fprintf(fout, "<path fill=\"#%06x\" stroke=\"none\" d=\"", info.fillcolor); + newline = 1; + lastop = 0; + if (info.debug == 1) { + svg_jaggy_path(fout, q->priv->pt, q->priv->len, 1); + } else { + svg_path(fout, &q->curve, 1); + } + fprintf(fout, "\"/>\n"); + } + if (info.grouping == 2) { + fprintf(fout, "</g>\n"); + } + for (q=p->childlist; q; q=q->sibling) { + write_paths_opaque(fout, q->childlist); + } + if (info.grouping == 2) { + fprintf(fout, "</g>\n"); + } + } +} + +static void write_paths_transparent_rec(FILE *fout, potrace_path_t *tree) { + potrace_path_t *p, *q; + + for (p=tree; p; p=p->sibling) { + if (info.grouping == 2) { + fprintf(fout, "<g>\n"); + } + if (info.grouping != 0) { + column = fprintf(fout, "<path d=\""); + newline = 1; + lastop = 0; + } + if (info.debug == 1) { + svg_jaggy_path(fout, p->priv->pt, p->priv->len, 1); + } else { + svg_path(fout, &p->curve, 1); + } + for (q=p->childlist; q; q=q->sibling) { + if (info.debug == 1) { + svg_jaggy_path(fout, q->priv->pt, q->priv->len, 0); + } else { + svg_path(fout, &q->curve, 0); + } + } + if (info.grouping != 0) { + fprintf(fout, "\"/>\n"); + } + for (q=p->childlist; q; q=q->sibling) { + write_paths_transparent_rec(fout, q->childlist); + } + if (info.grouping == 2) { + fprintf(fout, "</g>\n"); + } + } +} + +static void write_paths_transparent(FILE *fout, potrace_path_t *tree) { + if (info.grouping == 0) { + column = fprintf(fout, "<path d=\""); + newline = 1; + lastop = 0; + } + write_paths_transparent_rec(fout, tree); + if (info.grouping == 0) { + fprintf(fout, "\"/>\n"); + } +} + +/* ---------------------------------------------------------------------- */ +/* Backend. */ + +/* public interface for SVG */ +int page_svg(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) { + + double bboxx = imginfo->trans.bb[0]+imginfo->lmar+imginfo->rmar; + double bboxy = imginfo->trans.bb[1]+imginfo->tmar+imginfo->bmar; + double origx = imginfo->trans.orig[0] + imginfo->lmar; + double origy = bboxy - imginfo->trans.orig[1] - imginfo->bmar; + double scalex = imginfo->trans.scalex / info.unit; + double scaley = -imginfo->trans.scaley / info.unit; + + /* header */ + fprintf(fout, "<?xml version=\"1.0\" standalone=\"no\"?>\n"); + fprintf(fout, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n"); + fprintf(fout, " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"); + + /* set bounding box and namespace */ + fprintf(fout, "<svg version=\"1.0\" xmlns=\"http://www.w3.org/2000/svg\"\n"); + fprintf(fout, " width=\"%fpt\" height=\"%fpt\" viewBox=\"0 0 %f %f\"\n", + bboxx, bboxy, bboxx, bboxy); + fprintf(fout, " preserveAspectRatio=\"xMidYMid meet\">\n"); + + /* metadata: creator */ + fprintf(fout, "<metadata>\n"); + fprintf(fout, "Created by "POTRACE" "VERSION", written by Peter Selinger 2001-2015\n"); + fprintf(fout, "</metadata>\n"); + + /* use a "group" tag to establish coordinate system and style */ + fprintf(fout, "<g transform=\""); + if (origx != 0 || origy != 0) { + fprintf(fout, "translate(%f,%f) ", origx, origy); + } + if (info.angle != 0) { + fprintf(fout, "rotate(%.2f) ", -info.angle); + } + fprintf(fout, "scale(%f,%f)", scalex, scaley); + fprintf(fout, "\"\n"); + fprintf(fout, "fill=\"#%06x\" stroke=\"none\">\n", info.color); + + if (info.opaque) { + write_paths_opaque(fout, plist); + } else { + write_paths_transparent(fout, plist); + } + + /* write footer */ + fprintf(fout, "</g>\n"); + fprintf(fout, "</svg>\n"); + fflush(fout); + + return 0; +} + +/* the Gimppath backend is identical, except that it disables + --opaque, enables --flat, and the dimensions are pixel-based */ +int page_gimp(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) { + info.opaque = 0; + info.grouping = 0; + return page_svg(fout, plist, imginfo); +} |