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