backend_svg.c
Go to the documentation of this file.
00001 /* Copyright (C) 2001-2007 Peter Selinger.
00002    This file is part of Potrace. It is free software and it is covered
00003    by the GNU General Public License. See the file COPYING for details. */
00004 
00005 /* $Id: backend_svg.c 147 2007-04-09 00:44:09Z selinger $ */
00006 
00007 /* The SVG backend of Potrace. */
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 /* path-drawing auxiliary functions */
00027 
00028 /* coordinate quantization */
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]; /* static string limit is okay here because
00060                             we only use constant format strings - for
00061                             the same reason, it is okay to use
00062                             vsprintf instead of vsnprintf below. */
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 /* functions for converting a path to an SVG path element */
00127 
00128 /* Explicit encoding. If abs is set, move to first coordinate
00129    absolutely. */
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 /* produce a jaggy path - for debugging. If abs is set, move to first
00160    coordinate absolutely. If abs is not set, move to first coordinate
00161    relatively, and traverse path in the opposite direction. */
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 /* Backend. */
00273 
00274 /* public interface for SVG */
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   /* header */
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   /* set bounding box and namespace */
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   /* metadata: creator */
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   /* use a "group" tag to establish coordinate system and style */
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   /* write footer */
00319   fprintf(fout, "</g>\n");
00320   fprintf(fout, "</svg>\n");
00321   fflush(fout);
00322 
00323   return 0;
00324 }
00325 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


portrait_painter
Author(s): Niklas Meinzer, Ina Baumgarten
autogenerated on Wed Dec 26 2012 16:00:42