File indexing completed on 2024-12-22 04:04:09

0001 /* Copyright (C) 2001-2019 Peter Selinger.
0002    This file is part of Potrace. It is free software and it is covered
0003    by the GNU General Public License. See the file COPYING for details. */
0004 
0005 
0006 /* The xfig backend of Potrace. */
0007 
0008 #ifdef HAVE_CONFIG_H
0009 #include <config.h>
0010 #endif
0011 
0012 #include <stdio.h>
0013 #include <stdarg.h>
0014 #include <string.h>
0015 #include <math.h>
0016 
0017 #include "main.h"
0018 #include "backend_xfig.h"
0019 #include "potracelib.h"
0020 #include "lists.h"
0021 #include "auxiliary.h"
0022 #include "trans.h"
0023 
0024 #ifndef M_PI
0025 #define M_PI 3.14159265358979323846
0026 #endif
0027 
0028 struct pageformat_s {
0029   const char *name;
0030   int w, h;
0031 };
0032 typedef struct pageformat_s pageformat_t;
0033 
0034 /* page formats known by xfig, and their dimensions in postscript points */
0035 static pageformat_t pageformat[] = {
0036   { "A9",        105,  149 },
0037   { "A8",        149,  211 },
0038   { "A7",        211,  298 },
0039   { "A6",        298,  421 },
0040   { "A5",        421,  595 },
0041   { "A4",        595,  842 },
0042   { "A3",        842, 1191 },
0043   { "A2",       1191, 1685 },
0044   { "A1",       1685, 2383 },
0045   { "A0",       2383, 3370 },
0046 
0047   { "B10",        91,  129 },
0048   { "B9",        129,  182 },
0049   { "B8",        182,  258 },
0050   { "B7",        258,  365 },
0051   { "B6",        365,  516 },
0052   { "B5",        516,  730 },
0053   { "B4",        730, 1032 },
0054   { "B3",       1032, 1460 },
0055   { "B2",       1460, 2064 },
0056   { "B1",       2064, 2920 },
0057   { "B0",       2920, 4127 },
0058 
0059   { "Letter",    612,  792 },
0060   { "Legal",     612, 1008 },
0061   { "Tabloid",   792, 1224 },
0062   { "A",         612,  792 },
0063   { "B",         792, 1224 },
0064   { "C",        1224, 1584 },
0065   { "D",        1584, 2448 },
0066   { "E",        2448, 3168 },
0067 
0068   { NULL, 0, 0 },
0069 };
0070 
0071 /* ---------------------------------------------------------------------- */
0072 /* path-drawing auxiliary functions */
0073 
0074 /* coordinate quantization */
0075 static inline point_t unit(dpoint_t p) {
0076   point_t q;
0077 
0078   q.x = (long)(floor(p.x+.5));
0079   q.y = (long)(floor(p.y+.5));
0080   return q;
0081 }
0082 
0083 static void xfig_point(FILE *fout, dpoint_t p, trans_t t) {
0084   point_t q;
0085 
0086   q = unit(trans(p, t));
0087 
0088   fprintf(fout, "%ld %ld\n", q.x, q.y);
0089 }
0090 
0091 /* ---------------------------------------------------------------------- */
0092 /* functions for converting a path to a xfig */
0093 
0094 /* calculate number of xfig control points in this path */
0095 static int npoints(potrace_curve_t *curve, int m) {
0096   int i;
0097   int n=0;
0098 
0099   for (i=0; i<m; i++) {
0100     switch (curve->tag[i]) {
0101     case POTRACE_CORNER:
0102       n += 1;
0103       break;
0104     case POTRACE_CURVETO:
0105       n += 2;
0106       break;
0107     }
0108   }
0109   return n;
0110 }
0111 
0112 /* do one path. */
0113 static void xfig_path(FILE *fout, potrace_curve_t *curve, trans_t t, int sign, int depth) {
0114   int i;
0115   dpoint_t *c;
0116   int m = curve->n;
0117 
0118   fprintf(fout, "3 1 0 0 0 %d %d 0 20 0.000 0 0 0 %d\n", sign=='+' ? 32 : 33, depth, npoints(curve, m));
0119 
0120   for (i=0; i<m; i++) {
0121     c = curve->c[i];
0122     switch (curve->tag[i]) {
0123     case POTRACE_CORNER:
0124       xfig_point(fout, c[1], t);
0125       break;
0126     case POTRACE_CURVETO:
0127       xfig_point(fout, c[0], t);
0128       xfig_point(fout, c[1], t);
0129       break;
0130     }
0131   }
0132   for (i=0; i<m; i++) {
0133     switch (curve->tag[i]) {
0134     case POTRACE_CORNER:
0135       fprintf(fout, "0\n");
0136       break;
0137     case POTRACE_CURVETO:
0138       fprintf(fout, "1 1\n");
0139       break;
0140     }
0141   }
0142 }
0143 
0144 /* render a whole tree */
0145 static void xfig_write_paths(FILE *fout, potrace_path_t *plist, trans_t t, int depth) {
0146   potrace_path_t *p, *q;
0147 
0148   for (p=plist; p; p=p->sibling) {
0149     xfig_path(fout, &p->curve, t, p->sign, depth);
0150     for (q=p->childlist; q; q=q->sibling) {
0151       xfig_path(fout, &q->curve, t, q->sign, depth >= 1 ? depth-1 : 0);
0152     }
0153     for (q=p->childlist; q; q=q->sibling) {
0154       xfig_write_paths(fout, q->childlist, t, depth >= 2 ? depth-2 : 0);
0155     }
0156   }
0157 }
0158 
0159 /* calculate the depth of a tree. Call with d=0. */
0160 static int xfig_get_depth(potrace_path_t *plist) {
0161   potrace_path_t *p;
0162   int max =0;
0163   int d;
0164 
0165   for (p=plist; p; p=p->sibling) {
0166     d = xfig_get_depth(p->childlist);
0167     if (d > max) {
0168       max = d;
0169     }
0170   }
0171   return max + 1;
0172 }
0173 
0174 /* ---------------------------------------------------------------------- */
0175 /* Backend. */
0176 
0177 /* public interface for XFIG */
0178 int page_xfig(FILE *fout, potrace_path_t *plist, imginfo_t *imginfo) {
0179   trans_t t;
0180   double origx = imginfo->trans.orig[0] + imginfo->lmar;
0181   double origy = - imginfo->trans.orig[1] - imginfo->bmar + info.paperheight;
0182   const char *formatname;
0183   int best, penalty;
0184   pageformat_t *f;
0185   int i;
0186   int x0, y0, x1, y1;  /* in xfig's coordinates */
0187   int depth;
0188   
0189   t.orig[0] = 1200/72.0 * origx;
0190   t.orig[1] = 1200/72.0 * origy;
0191   t.x[0] = 1200/72.0 * imginfo->trans.x[0];
0192   t.x[1] = -1200/72.0 * imginfo->trans.x[1];
0193   t.y[0] = 1200/72.0 * imginfo->trans.y[0];
0194   t.y[1] = -1200/72.0 * imginfo->trans.y[1];
0195 
0196   x0 = (int)(1200/72.0 * (origx - imginfo->trans.orig[0]));
0197   y0 = (int)(1200/72.0 * (origy + imginfo->trans.orig[1]));
0198   x1 = x0 + (int)(1200/72.0 * imginfo->trans.bb[0]);
0199   y1 = y0 - (int)(1200/72.0 * imginfo->trans.bb[1]);
0200 
0201   best = -1;
0202   formatname = "Letter";
0203 
0204   /* find closest page format */
0205   for (i=0; pageformat[i].name; i++) {
0206     f = &pageformat[i];
0207     if (f->w >= info.paperwidth-1 && f->h >= info.paperheight-1) {
0208       penalty = f->w + f->h;
0209       if (best == -1 || penalty < best) {
0210     best = penalty;
0211     formatname = f->name;
0212       }
0213     }
0214   }
0215 
0216   /* header */
0217   fprintf(fout, "#FIG 3.2\n");
0218   fprintf(fout, "#created by " POTRACE " " VERSION ", written by Peter Selinger 2001-2019\n");
0219   fprintf(fout, "Portrait\n");
0220   fprintf(fout, "Center\n");
0221   fprintf(fout, "Inches\n");
0222   fprintf(fout, "%s\n", formatname);
0223   fprintf(fout, "100.0\n");
0224   fprintf(fout, "Single\n");
0225   fprintf(fout, "-2\n");
0226   fprintf(fout, "1200 2\n");  /* 1200 pixels per inch */
0227   fprintf(fout, "0 32 #%06x\n", info.color);
0228   fprintf(fout, "0 33 #%06x\n", info.fillcolor);
0229   fprintf(fout, "6 %d %d %d %d\n", x0-75, y1-35, x1+75, y0+35); /* bounding box */
0230 
0231   /* determine depth of the tree */
0232   depth = xfig_get_depth(plist);
0233 
0234   /* figure out appropriate xfig starting depth. Note: xfig only has 1000 depths available */
0235   if (depth <= 40) {
0236     depth = 50;
0237   } else if (depth < 990) {
0238     depth += 10;
0239   } else {
0240     depth = 999;
0241   }
0242 
0243   /* write paths. Note: can never use "opticurve" with this backend -
0244      it just does not approximate Bezier curves closely enough.  */
0245   xfig_write_paths(fout, plist, t, depth);
0246 
0247   fprintf(fout, "-6\n"); /* end bounding box */
0248 
0249   fflush(fout);
0250 
0251   return 0;
0252 }