PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pstex.c
Go to the documentation of this file.
1 // PLplot pstex (Postscript/LaTeX) device driver.
2 //
3 
4 #include "plDevs.h"
5 
6 #ifdef PLD_pstex
7 
8 #include "plplotP.h"
9 #include "drivers.h"
10 #include "ps.h"
11 
12 // Device info
13 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_pstex =
14  "pstex:Combined Postscript/LaTeX files:0:pstex:41:pstex\n";
15 
16 //--------------------------------------------------------------------------
17 // plD_init_pstex()
18 //
19 // Initialize device.
20 //--------------------------------------------------------------------------
21 
22 
23 static void parse_str( const char *str, char *dest );
24 static void proc_str( PLStream *pls, EscText *args );
25 static int color = 1;
26 
27 static DrvOpt pstex_options[] = { { "color", DRV_INT, &color,
28  "Color Postscript/LaTeX (color=1|0)" },
29  { NULL, DRV_INT, NULL, NULL} };
30 
32 {
33 #ifndef ENABLE_DYNDRIVERS
34  pdt->pl_MenuStr = "Combined Postscript/LaTeX files";
35  pdt->pl_DevName = "pstex";
36 #endif
38  pdt->pl_seq = 41;
42  pdt->pl_eop = (plD_eop_fp) plD_eop_ps;
47 }
48 
49 void
51 {
52  char *ofile;
53  size_t len;
54  PSDev *dev;
55  FILE *fp;
56 
57  plParseDrvOpts( pstex_options );
58  if ( color )
59  plD_init_psc( pls ); // init color postscript driver
60  else
61  plD_init_psm( pls ); // init monochrome postscript driver
62 
63  dev = (PSDev *) pls->dev;
64 
65  pls->dev_text = 1; // want to draw text
66  pls->dev_unicode = 0; // don't want unicode
67 
68  // open latex output file
69  len = strlen( pls->FileName ) + 3;
70  ofile = (char *) malloc( sizeof ( char ) * len );
71  snprintf( ofile, len, "%s_t", pls->FileName );
72  fp = fopen( ofile, "w" );
73  free( ofile );
74  dev->fp = fp;
75 
76  fprintf( fp, "\\begin{picture}(0,0)(0,0)%%\n" );
77  fprintf( fp, "\\includegraphics[scale=1.,clip]{%s}%%\n", pls->FileName );
78  fprintf( fp, "\\end{picture}%%\n" );
79 // fprintf(fp,"\\setlength{\\unitlength}{%fbp}%%\n", 72./25.4/pls->xpmm);
80  fprintf( fp, "\\setlength{\\unitlength}{%fbp}%%\n", 1.0 / ENLARGE );
81  fprintf( fp, "\\begingroup\\makeatletter\\ifx\\SetFigFont\\undefined%%\n" );
82  fprintf( fp, "\\gdef\\SetFigFont#1#2#3#4#5{%%\n" );
83  fprintf( fp, "\\reset@font\\fontsize{#1}{#2pt}%%\n" );
84  fprintf( fp, "\\fontfamily{#3}\\fontseries{#4}\\fontshape{#5}%%\n" );
85  fprintf( fp, "\\selectfont}%%\n" );
86  fprintf( fp, "\\fi\\endgroup%%\n" );
87 
88  dev->cur_pos = ftell( fp );
89  fprintf( fp, "\\begin{picture}(xxxxxx,xxxxxx)(xxxxxx,xxxxxx)%%\n" );
90 }
91 
92 void
93 plD_esc_pstex( PLStream *pls, PLINT op, void *ptr )
94 {
95  switch ( op )
96  {
97  case PLESC_HAS_TEXT:
98  proc_str( pls, ptr );
99  break;
100  default:
101  plD_esc_ps( pls, op, ptr );
102  }
103 }
104 
105 void
106 plD_bop_pstex( PLStream *pls )
107 {
108  plD_bop_ps( pls );
109  plGetFam( pls );
110 }
111 
112 void
113 plD_tidy_pstex( PLStream *pls )
114 {
115  PSDev *dev = (PSDev *) pls->dev;
116  PLFLT scale;
117  FILE *fp;
118 
119  plD_tidy_ps( pls );
120 
121  scale = pls->xpmm * 25.4 / 72.;
122 
123  fp = dev->fp;
124  fprintf( fp, "\\end{picture}\n" );
125 
126  fseek( fp, dev->cur_pos, SEEK_SET );
127  fprintf( fp, "\\begin{picture}(%d,%d)(%d,%d)%%\n%%",
128  ROUND( ( dev->urx - dev->llx ) * scale ),
129  ROUND( ( dev->ury - dev->lly ) * scale ),
130  ROUND( ( dev->llx - XOFFSET ) * scale ),
131  ROUND( ( dev->lly - YOFFSET ) * scale ) );
132 
133  plCloseFile( pls );
134 }
135 
136 void
137 proc_str( PLStream *pls, EscText *args )
138 {
139  PLFLT *t = args->xform;
140  PLFLT a1, alpha, ft_ht, angle;
141  char cptr[256], jst, ref;
142  PSDev *dev = (PSDev *) pls->dev;
143  PLINT clxmin, clxmax, clymin, clymax;
144  FILE *fp;
145 
146  fp = dev->fp;
147 
148  // font height
149  ft_ht = 1.6 * pls->chrht * 72.0 / 25.4; /* ft_ht in points. ht is in mm */
150 
151  // calculate baseline text angle
152  angle = ( (PLFLT) ( ORIENTATION - 1 ) + pls->diorot ) * 90.;
153  a1 = acos( t[0] ) * 180. / PI;
154  if ( t[2] > 0. )
155  alpha = a1 - angle - 90.;
156  else
157  alpha = 360. - a1 - angle - 90.;
158 
159  // parse string for format (escape) characters
160  parse_str( args->string, cptr );
161 
162  //
163  // Reference point (center baseline of string, not latex character reference point).
164  // If base = 0, it is aligned with the center of the text box
165  // If base = 1, it is aligned with the baseline of the text box
166  // If base = 2, it is aligned with the top of the text box
167  // Currently plplot only uses base=0
168  //
169 
170  if ( args->base == 2 ) // not supported by plplot
171  ref = 't';
172  else if ( args->base == 1 )
173  ref = 'b';
174  else
175  ref = 'c';
176 
177  //
178  // Text justification. Left, center and right justification, which
179  // are the more common options, are supported; variable justification is
180  // only approximate, based on plplot computation of it's string lenght
181  //
182 
183  if ( args->just == 0.5 )
184  jst = 'c';
185  else if ( args->just == 1. )
186  jst = 'r';
187  else
188  {
189  jst = 'l';
190  args->x = args->refx; // use hints provided by plplot
191  args->y = args->refy;
192  }
193 
194  // apply transformations
195  difilt( &args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax );
196 
197  // check clip limits. For now, only the reference point of the string is checked;
198  // but the the whole string should be checked -- using a postscript construct
199  // such as gsave/clip/grestore. This method can also be applied to the xfig and
200  // pstex drivers. Zoom side effect: the font size must be adjusted!
201 
202  if ( args->x < clxmin || args->x > clxmax || args->y < clymin || args->y > clymax )
203  return;
204 
205  plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
206  &( args->x ), &( args->y ) );
207 
208 #ifdef DEBUG
209  fprintf( fp, "\\put(%d,%d){\\circle{10}}\n",
210  args->x, args->y );
211 #endif
212 
213  fprintf( fp, "\\put(%d,%d){\\rotatebox{%.1f}{\\makebox(0,0)[%c%c]{\\SetFigFont{%.1f}{12}",
214  args->x, args->y, alpha, jst, ref, ft_ht );
215 
216  //
217  // font family, serie and shape. Currently not supported by plplot
218  //
219  // Use current font instead:
220  // 1: Normal font (latex document default font)
221  // 2: Roman font
222  // 3: Italic font (most probably latex slanted)
223  // 4: Script font (latex sans serif)
224  //
225 
226  switch ( pls->cfont )
227  {
228  case ( 1 ): fprintf( fp, "{\\familydefault}" ); break;
229  case ( 2 ): fprintf( fp, "{\\rmdefault}" ); break;
230  case ( 3 ): fprintf( fp, "{\\itdefault}" ); break;
231  case ( 4 ): fprintf( fp, "{\\sfdefault}" ); break;
232  default: fprintf( fp, "{\\familydefault}" );
233  }
234 
235  fprintf( fp, "{\\mddefault}{\\updefault}\n" );
236 
237  // font color.
238 
239  if ( color )
240  fprintf( fp, "\\special{ps: %.3f %.3f %.3f setrgbcolor}{",
241  pls->curcolor.r / 255., pls->curcolor.g / 255., pls->curcolor.b / 255. );
242  else
243  fprintf( fp, "\\special{ps: 0 0 0 setrgbcolor}{" );
244 
245  fprintf( fp, "%% Your text follows:\n" );
246  fprintf( fp, "%s\n", cptr );
247  fprintf( fp, "}}}}" );
248 
249  //
250  // keep ps driver happy -- needed for background and orientation.
251  // arghhh! can't calculate it, as I only have the string reference
252  // point, not its extent!
253  // Quick (and final?) *hack*, ASSUME that no more than a char height
254  // extents after/before the string reference point.
255  //
256 
257  dev->llx = MIN( dev->llx, args->x - ft_ht * 25.4 / 72. * pls->xpmm );
258  dev->lly = MIN( dev->lly, args->y - ft_ht * 25.4 / 72. * pls->ypmm );
259  dev->urx = MAX( dev->urx, args->x + ft_ht * 25.4 / 72. * pls->xpmm );
260  dev->ury = MAX( dev->ury, args->y + ft_ht * 25.4 / 72. * pls->ypmm );
261 }
262 
263 void
264 parse_str( const char *str, char *dest )
265 {
266  int n, opened = 0, raised = 0, overline = 0, underline = 0, fontset = 0, math = 0;
267  char *tp = dest, c, esc;
268  char greek[] = "abgGdDezyhHiklLmncCopPrsStuUfFxqQwW";
269  char *mathgreek[] = { "alpha", "beta", "gamma", "Gamma", "delta", "Delta",
270  "epsilon", "zeta", "eta", "theta", "Theta", "iota",
271  "kappa", "lambda", "Lambda", "mu", "nu", "xi", "Xi",
272  "o", "pi", "Pi", "rho", "sigma", "Sigma","tau",
273  "upsilon", "Upsilon", "phi", "Phi", "chi",
274  "psi", "Psi", "omega", "Omega" };
275 
276  plgesc( &esc );
277 
278  while ( *str )
279  {
280  if ( *str != esc )
281  {
282  *tp++ = *str++;
283  continue;
284  }
285  str++;
286 
287  switch ( *str++ )
288  {
289  case 'u': // up one level
290  if ( raised < 0 )
291  {
292  *tp++ = '}';
293  opened--;
294  }
295  else
296  {
297  n = sprintf( tp, "\\raisebox{%.2fex}{", 0.6 );
298  tp += n; opened++;
299  }
300  raised++;
301  break;
302 
303  case 'd': // down one level
304  if ( raised > 0 )
305  {
306  *tp++ = '}';
307  opened--;
308  }
309  else
310  {
311  n = sprintf( tp, "\\raisebox{%.2fex}{", -0.6 );
312  tp += n; opened++;
313  }
314  raised--;
315  break;
316 
317  case 'b': // backspace
318  n = sprintf( tp, "\\hspace{-1em}" );
319  tp += n;
320  break;
321 
322  case '+': // toggles overline mode. Side effect, enter math mode.
323  if ( overline )
324  {
325  if ( --math )
326  *tp++ = '}';
327  else
328  {
329  n = sprintf( tp, "}$" );
330  tp += n;
331  }
332  overline--; opened--;
333  }
334  else
335  {
336  if ( !math )
337  *tp++ = '$';
338 
339  n = sprintf( tp, "\\overline{" );
340  tp += n; overline++; opened++; math++;
341  }
342  break;
343 
344  case '-': // toggles underline mode. Side effect, enter math mode.
345  if ( underline )
346  {
347  if ( --math )
348  *tp++ = '}';
349  else
350  {
351  n = sprintf( tp, "}$" );
352  tp += n;
353  }
354  underline--; opened--;
355  }
356  else
357  {
358  if ( !math )
359  *tp++ = '$';
360 
361  n = sprintf( tp, "\\underline{" );
362  tp += n; underline++; opened++; math++;
363  }
364  break;
365 
366  case 'g': // greek letter corresponding to roman letter x
367  c = *str++;
368  n = plP_strpos( greek, c );
369  if ( n != -1 )
370  {
371  if ( !math )
372  *tp++ = '$';
373 
374  *tp++ = '\\';
375  strcpy( tp, mathgreek[n] );
376  if ( isupper( c ) )
377  *tp = toupper( *tp );
378  tp += strlen( mathgreek[n] );
379  if ( !math )
380  *tp++ = '$';
381  }
382  else
383  *tp++ = c;
384 
385  break;
386 
387  case '(': // Hershey symbol number (nnn) (any number of digits) FIXME ???
388  plwarn( "'g(...)' text escape sequence not processed." );
389  while ( *str++ != ')' )
390  ;
391  break;
392 
393  case 'f': // switch font
394 
395  switch ( *str++ )
396  {
397  case 'n': // Normal
398  while ( fontset-- )
399  {
400  *tp++ = '}';
401  opened--;
402  }
403 
404  if ( math )
405  {
406  *tp++ = '$';
407  math = 0;
408  }
409 
410  n = sprintf( tp, "\\normalfont " );
411  tp += n;
412  break;
413 
414  case 'r': // Roman
415  if ( math )
416  n = sprintf( tp, "\\mathrm{" );
417  else
418  n = sprintf( tp, "\\textrm{" );
419 
420  tp += n; opened++; fontset++;
421  break;
422 
423  case 'i': // Italic
424  if ( math )
425  n = sprintf( tp, "\\mathit{" );
426  else
427  n = sprintf( tp, "\\textit{" );
428 
429  tp += n; opened++; fontset++;
430  break;
431 
432  case 's': // Script. Don't, use sans serif
433  if ( math )
434  n = sprintf( tp, "\\mathsf{" );
435  else
436  n = sprintf( tp, "\\textsf{" );
437 
438  tp += n; opened++; fontset++;
439  break;
440  }
441 
442  default:
443  if ( *str == esc )
444  *tp++ = esc;
445  }
446  }
447 
448  while ( opened-- )
449  *tp++ = '}';
450  *tp = '\0';
451 }
452 
453 #else
454 int
456 {
457  return 0;
458 }
459 
460 #endif // PLD_pstexdev