Back to index

tetex-bin  3.0
tpic.c
Go to the documentation of this file.
00001 /*  $Header$
00002 
00003     This is dvipdfm, a DVI to PDF translator.
00004     Copyright (C) 1998, 1999 by Mark A. Wicks
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019     
00020     The author may be contacted via the e-mail address
00021 
00022        mwicks@kettering.edu
00023 */
00024 
00025 #include <string.h>
00026 #include <stdlib.h>
00027 #include "system.h"
00028 #include "mem.h"
00029 #include "mfileio.h"
00030 #include "tpic.h"
00031 #include "pdfparse.h"
00032 #include "pdfdoc.h"
00033 #include "pdfdev.h"
00034 #include "dvi.h"
00035 
00036 /* Following "constant" converts milli-inches to
00037    device (in this case PDF stream) coordinates */
00038 
00039 #define MI2DEV (0.072/pdf_dev_scale())
00040 
00041 double pen_size = 1.0;
00042 int fill_shape = 0;
00043 double fill_color = 0.0; double default_fill_color = 0.5;
00044 static struct path
00045 {
00046   double x, y;
00047 } *path = NULL;
00048 unsigned long path_length = 0, max_path_length = 0;
00049 
00050 static void tpic_clear_state (void) 
00051 {
00052   if ((path))
00053     RELEASE(path);
00054   path = NULL;
00055   path_length = 0;
00056   max_path_length = 0;
00057   fill_shape = 0;
00058   fill_color = 0.0;
00059   return;
00060 }
00061 
00062 static void set_pen_size (char **buffer, char *end)
00063 {
00064   char *number;
00065   skip_white (buffer, end);
00066   if ((number = parse_number(buffer, end))) {
00067     pen_size = atof (number) * MI2DEV;
00068     RELEASE (number);
00069   } else {
00070     dump (*buffer, end);
00071     fprintf (stderr, "tpic special: pn: Invalid pen size\n");
00072   }
00073 }
00074 
00075 static void set_fill_color (char **buffer, char *end)
00076 {
00077   char *number;
00078 MEM_START
00079   fill_shape = 1;
00080   fill_color = default_fill_color; 
00081   skip_white (buffer, end);
00082   if ((number = parse_number(buffer, end))) {
00083     fill_color = 1.0 - atof (number);
00084     if (fill_color > 1.0)
00085       fill_color = 1.0;
00086     if (fill_color < 0.0)
00087       fill_color = 0.0;
00088     RELEASE (number);
00089   }
00090 MEM_END
00091 }
00092 
00093 static void add_point (char **buffer, char *end) 
00094 {
00095   char *x= NULL, *y= NULL;
00096 MEM_START
00097   skip_white (buffer, end);
00098   if (*buffer < end)
00099     x = parse_number (buffer, end);
00100   skip_white (buffer, end);
00101   if (*buffer < end)
00102     y = parse_number (buffer, end);
00103   if ((x) && (y)) {
00104     if (path_length >= max_path_length) {
00105       max_path_length += 256;
00106       path = RENEW (path, max_path_length, struct path);
00107     }
00108     path[path_length].x = atof(x)*MI2DEV;
00109     path[path_length].y = atof(y)*MI2DEV;
00110     path_length += 1;
00111   } else {
00112     dump (*buffer, end);
00113     fprintf (stderr, "tpic special: pa: Missing coordinate\n");
00114   }
00115   if (x) RELEASE(x);
00116   if (y) RELEASE(y);
00117 MEM_END
00118   return;
00119 }
00120 
00121 static void show_path (int hidden) 
00122 {
00123   int len;
00124   /* The semantics of a fill_color of 0.0 or 0.5 will be to use current
00125      painting color known to dvipdfm */
00126   if (fill_shape && fill_color != 0.0) {
00127     sprintf (work_buffer, " %.2f g", fill_color);
00128     len = strlen (work_buffer);
00129     pdf_doc_add_to_page (work_buffer, len);
00130   }
00131   if (!hidden && fill_shape) {
00132     pdf_doc_add_to_page (" b", 2);
00133   }
00134   if (hidden && fill_shape) {
00135     pdf_doc_add_to_page (" f", 2);
00136   }
00137   if (!hidden && !fill_shape)
00138     pdf_doc_add_to_page (" S", 2);
00139   if (fill_shape)
00140     fill_shape = 0;
00141   fill_color = 0.0;
00142   fill_shape = 0.0;
00143 }
00144 
00145 
00146 static void flush_path (double x_user, double y_user, int hidden,
00147                      double dash_dot)
00148 {
00149   int len;
00150 MEM_START
00151   /* Make pen_size == 0 equivalent to hidden */
00152   if (pen_size == 0)
00153     hidden = 1;
00154   if (path_length > 1) {
00155     int i;
00156     sprintf (work_buffer, " q");
00157     len = strlen (work_buffer);
00158     pdf_doc_add_to_page (work_buffer, len);
00159     if (pen_size != 0.0) {
00160       sprintf (work_buffer, " %.2f w", pen_size);
00161       len = strlen (work_buffer);
00162     }
00163     pdf_doc_add_to_page (work_buffer, len);
00164     sprintf (work_buffer, " 1 J 1 j");
00165     len = strlen (work_buffer);
00166     pdf_doc_add_to_page (work_buffer, len);
00167     if (dash_dot != 0.0) {
00168       if (dash_dot > 0.0) {
00169        sprintf (work_buffer, " [%.1f %.1f] 0 d",
00170                dash_dot*72.0, dash_dot*36.0);
00171         len = strlen (work_buffer);
00172       } else {
00173        sprintf (work_buffer, " [%.1f %.1f] 0 d", pen_size,
00174                -dash_dot*72.0);
00175         len = strlen (work_buffer);
00176       }
00177       pdf_doc_add_to_page (work_buffer, len);
00178     }
00179     sprintf (work_buffer, " %.2f %.2f m",
00180             x_user+path[0].x, y_user-path[0].y);
00181     len = strlen (work_buffer);
00182     pdf_doc_add_to_page (work_buffer, len);
00183     for (i=0; i<path_length; i++) {
00184       sprintf (work_buffer, " %.2f %.2f l", x_user+path[i].x, y_user-path[i].y);
00185       len = strlen (work_buffer);
00186       pdf_doc_add_to_page (work_buffer, len);
00187     } 
00188     show_path (hidden);
00189     pdf_doc_add_to_page (" Q", 2);
00190   } else {
00191     fprintf (stderr, "tpic special: fp: Not enough points!\n");
00192   }
00193   tpic_clear_state();
00194 MEM_END
00195   return;
00196 }
00197 static void spline_path (double x_user, double y_user, double dash_dot)
00198 {
00199   int len;
00200 MEM_START
00201   /* Spline is meaningless for path length of less than 3 */
00202   if (path_length > 2) {
00203     int i;
00204     sprintf (work_buffer, " q 1.4 M %.2f w", pen_size);
00205     len = strlen (work_buffer);
00206     pdf_doc_add_to_page (work_buffer, len);
00207     if (dash_dot != 0.0) {
00208       if (dash_dot > 0.0) {
00209        sprintf (work_buffer, " [%.1f %.1f] 0 d",
00210                dash_dot*72.0, dash_dot*36.0);
00211         len = strlen (work_buffer);
00212       } else if (dash_dot < 0.0) {
00213        sprintf (work_buffer, " [%.1f %.1f] 0 d 1 J", pen_size,
00214                -dash_dot*72.0);
00215         len = strlen (work_buffer);
00216       }
00217       pdf_doc_add_to_page (work_buffer, len);
00218     }
00219     sprintf (work_buffer, " %.2f %.2f m",
00220             x_user+path[0].x, y_user-path[0].y);
00221     len = strlen (work_buffer);
00222     pdf_doc_add_to_page (work_buffer, len);
00223     sprintf (work_buffer, " %.2f %.2f l",
00224             x_user+0.5*(path[0].x+path[1].x), 
00225             y_user-0.5*(path[0].y+path[1].y));
00226     len = strlen (work_buffer);
00227     pdf_doc_add_to_page (work_buffer, len);
00228     for (i=1; i<path_length-1; i++) {
00229       sprintf (work_buffer, " %.2f %.2f %.2f %.2f y",
00230               x_user+path[i].x, y_user-path[i].y,
00231               x_user+0.5*(path[i].x+path[i+1].x),
00232               y_user-0.5*(path[i].y+path[i+1].y));
00233       len = strlen (work_buffer);
00234       pdf_doc_add_to_page (work_buffer, len);
00235     } 
00236     sprintf (work_buffer, " %.2f %.2f l",
00237             x_user+path[path_length-1].x,
00238             y_user-path[path_length-1].y);
00239     len = strlen (work_buffer);
00240     pdf_doc_add_to_page (work_buffer, len);
00241     show_path (0);
00242     pdf_doc_add_to_page (" Q", 2);
00243   } else {
00244     fprintf (stderr, "tpic special: sp: Not enough points!\n");
00245   }
00246   tpic_clear_state();
00247 MEM_END
00248   return;
00249 }
00250 
00251 static void arc (char **buffer, char *end, double x_user, double
00252                y_user, int hidden) 
00253 {
00254   char *xcs= NULL, *ycs= NULL,
00255     *xrs=NULL, *yrs=NULL, *sas=NULL, *eas=NULL;
00256   char *save;
00257   double xc, yc, xr, yr, sa, ea;
00258 MEM_START
00259   save = *buffer;
00260 /* pen_size == 0 is equivalent to hidden */ 
00261   if (pen_size == 0)
00262     hidden = 1;
00263   if ((xcs=parse_number(buffer, end)) &&
00264       (ycs=parse_number(buffer, end)) &&
00265       (xrs=parse_number(buffer, end)) &&
00266       (yrs=parse_number(buffer, end)) &&
00267       (sas=parse_number(buffer, end)) &&
00268       (eas=parse_number(buffer, end))) {
00269     double c, s, cur_x, cur_y, inc_ang;
00270     double cp1_x, cp1_y, cp2_x, cp2_y;
00271     double new_x, new_y;
00272     int len, i, nsteps;
00273     xc=atof (xcs)*MI2DEV; yc=atof (ycs)*MI2DEV;
00274     xr=atof (xrs)*MI2DEV; yr=atof (yrs)*MI2DEV;
00275     sa=atof (sas); ea=atof (eas);
00276 #define ROTATE(x,y,c,s) {new_x=(c)*(x)-(s)*(y);new_y=(s)*(x)+(c)*(y);x=new_x,y=new_y;}
00277     #define MAX_ANG_STEP 1.0
00278     nsteps = (int) ((ea-sa)/MAX_ANG_STEP) + 1;
00279     inc_ang = (ea-sa)/nsteps;
00280     c = cos(inc_ang); s = sin(inc_ang);
00281     cur_x=cos(sa); cur_y=sin(sa);
00282     cp1_x = cur_x - inc_ang/3.0*cur_y;
00283     cp1_y = cur_y + inc_ang/3.0*cur_x;
00284     cp2_x = cur_x + inc_ang/3.0*cur_y;
00285     cp2_y = cur_y - inc_ang/3.0*cur_x;
00286     sprintf (work_buffer, " q");
00287     len = strlen (work_buffer);
00288     pdf_doc_add_to_page (work_buffer, len);
00289     if (pen_size != 0.0) {
00290       sprintf (work_buffer, " %.2f w", pen_size);
00291       len = strlen (work_buffer);
00292      }
00293     pdf_doc_add_to_page (work_buffer, len);
00294     sprintf (work_buffer, " 1 J");
00295     len = strlen (work_buffer);
00296     pdf_doc_add_to_page (work_buffer, len);
00297     sprintf (work_buffer, " %.2f %.2f m", x_user+xr*cur_x+xc, y_user-yr*cur_y-yc);
00298     len = strlen (work_buffer);
00299     pdf_doc_add_to_page (work_buffer, len);
00300     ROTATE (cp2_x, cp2_y, c, s);
00301     ROTATE (cur_x, cur_y, c, s);
00302     for (i=0; i<nsteps; i++) {
00303       sprintf (work_buffer, " %.2f %.2f %.2f %.2f %.2f %.2f c",
00304               x_user+xr*cp1_x+xc, y_user-yr*cp1_y-yc,
00305               x_user+xr*cp2_x+xc, y_user-yr*cp2_y-yc,
00306               x_user+xr*cur_x+xc, y_user-yr*cur_y-yc);
00307       len = strlen (work_buffer);
00308       pdf_doc_add_to_page (work_buffer, len);
00309       ROTATE (cur_x, cur_y, c, s);
00310       ROTATE (cp1_x, cp1_y, c, s);
00311       ROTATE (cp2_x, cp2_y, c, s);
00312     }
00313     show_path (hidden);
00314     pdf_doc_add_to_page (" Q", 2);
00315   } else {
00316     dump (save, end);
00317     fprintf (stderr, "tpic special: ar/ir: Error in parameters\n");
00318   }
00319   if (xcs) RELEASE(xcs);
00320   if (ycs) RELEASE(ycs);
00321   if (xrs) RELEASE(xrs);
00322   if (yrs) RELEASE(yrs);
00323   if (sas) RELEASE(sas);
00324   if (eas) RELEASE(eas);
00325 MEM_END
00326   tpic_clear_state();
00327   return;
00328 }
00329 
00330 #define TPIC_PN 1
00331 #define TPIC_PA 2
00332 #define TPIC_FP 3
00333 #define TPIC_IP 4
00334 #define TPIC_DA 5
00335 #define TPIC_DT 6
00336 #define TPIC_SP 7
00337 #define TPIC_AR 8
00338 #define TPIC_IA 9
00339 #define TPIC_SH 10
00340 #define TPIC_WH 11
00341 #define TPIC_BK 12
00342 #define TPIC_TX 13
00343 
00344 struct {
00345   char *s;
00346   int tpic_command;
00347 } tpic_specials[] = {
00348   {"pn", TPIC_PN},
00349   {"pa", TPIC_PA},
00350   {"fp", TPIC_FP},
00351   {"ip", TPIC_IP},
00352   {"da", TPIC_DA},
00353   {"dt", TPIC_DT},
00354   {"sp", TPIC_SP},
00355   {"ar", TPIC_AR},
00356   {"ia", TPIC_IA},
00357   {"sh", TPIC_SH},
00358   {"wh", TPIC_WH},
00359   {"bk", TPIC_BK},
00360   {"tx", TPIC_TX}
00361 };
00362 
00363 int tpic_parse_special(char *buffer, UNSIGNED_QUAD size, double
00364                      x_user, double y_user)
00365 {
00366   int i, tpic_command, result = 0;
00367   char *end = buffer + size;
00368   char *token;
00369   skip_white (&buffer, end);
00370   if ((token = parse_ident (&buffer, end))) {
00371     for (i=0; i<(sizeof(tpic_specials)/sizeof(tpic_specials[0])); i++) {
00372       if (!strcmp (tpic_specials[i].s, token))
00373        break;
00374     }
00375     RELEASE (token);
00376   } else
00377     return 0;
00378   if (i < sizeof(tpic_specials)/sizeof(tpic_specials[0])) {
00379     tpic_command = tpic_specials[i].tpic_command;
00380     skip_white (&buffer, end);
00381     result = 1;
00382     switch (tpic_command) {
00383     case TPIC_PN:
00384       set_pen_size (&buffer, end);
00385       break;
00386     case TPIC_PA:
00387       add_point (&buffer, end);
00388       break;
00389     case TPIC_FP:
00390       flush_path(x_user, y_user, 0, 0.0);
00391       break;
00392     case TPIC_IP: 
00393       flush_path(x_user, y_user, 1, 0.0);
00394       break;
00395     case TPIC_DA:
00396       {
00397        char *s;
00398        if ((s=parse_number(&buffer, end))) {
00399          flush_path(x_user, y_user, 0, atof (s));
00400          RELEASE (s);
00401        }
00402       }
00403       break;
00404     case TPIC_DT:
00405       {
00406        char *s;
00407        if ((s=parse_number(&buffer, end))) {
00408          flush_path(x_user, y_user, 0, -atof (s));
00409          RELEASE (s);
00410        }
00411       }
00412       break;
00413     case TPIC_SP:
00414       {
00415        char *s;
00416        if ((s=parse_number(&buffer, end)))
00417          spline_path (x_user, y_user, atof (s));
00418        else
00419          spline_path(x_user, y_user, 0.0);
00420        break;
00421       }
00422     case TPIC_AR:
00423       arc (&buffer, end, x_user, y_user, 0);
00424       break;
00425     case TPIC_IA:
00426       arc (&buffer, end, x_user, y_user, 1);
00427       break;
00428     case TPIC_SH:
00429       set_fill_color (&buffer, end);
00430       break;
00431     case TPIC_WH: 
00432       fill_shape = 1;
00433       fill_color = 1.0;
00434       break;
00435     case TPIC_BK:
00436       fill_shape = 1;
00437       fill_color = 0.0;
00438       break;
00439     case TPIC_TX: 
00440       fill_shape = 1;
00441       {
00442        long num = 0, den = 0;
00443        while (buffer++ < end) {
00444          switch (*(buffer++)) {
00445          case '0':
00446            num += 0;
00447          case '1':
00448          case '2':
00449          case '4':
00450          case '8':
00451            num += 1;
00452            break;
00453          case '3':
00454          case '5':
00455          case '6':
00456          case '9':
00457          case 'a':
00458          case 'A':
00459          case 'c':
00460          case 'C':
00461            num += 2;
00462            break;
00463          case '7':
00464          case 'b':
00465          case 'B':
00466          case 'd':
00467          case 'D':
00468            num += 3;
00469            break;
00470          case 'f':
00471          case 'F':
00472            num += 4;
00473            break;
00474          default:
00475            break;
00476          }
00477          den += 16;
00478        }
00479        if (den != 0) {
00480          default_fill_color = 1.0 - (float) (num)/(den);
00481        }
00482        else {
00483          default_fill_color = 0.5;
00484        }
00485       }
00486       break;
00487     default:
00488       fprintf (stderr, "Fix me, I'm broke.  This should never happen");
00489       exit(1);
00490     }
00491   } else {
00492     result = 0;
00493   }
00494   return result;
00495 }
00496 
00497 
00498