# --------------------------------------------------------------------------- # This file belongs to the EPSTOMF package. # --------------------------------------------------------------------------- # You are entitled to do with the file whatever you wish. If you alter a file, # however, please remove the line containing the comment: # # `This file belongs to the EPSTOMF package.' # # in order to avoid mess. # --------------------------------------------------------------------------- # AUTHORS: B. Jackowski, P. Pianowski, M. Ry\'cko # HISTORY: # version 0.50: Tuesday, August 15th, 1995 # * first less or more complete version # version 0.51: Monday, October 23rd, 1995 # * comments adjusted to a new distribution # --------------------------------------------------------------------------- # This is an AWK program for the translation of a ``canonical'' (see below) # EPS file into METAFONT lingo; the resulting METAFONT program inputs MFTOEPS # macros (ver. >= 0.61). EPS files created using the MFTOEPS package are # accepted by this converter. # --- # The crucial features of a ``canonical'' EPS file are listed below: # 0. General assumptions: # a) parameters of a command appear in one line along with the command; # b) only explicit numerical values are admissible (variables are not # interpreted); # c) all numbers are expressed in PostScript points (called in TeX # ``big points'': 1/72in), i.e., no local transformations are involved; # d) prior to painting a curve (fill or stroke) its parameters # for filling or stroking are explicitly set; # e) only the commands listed in items 1--11 are interpreted. # 1. `gsave' and `grestore' are represented by `q' and `Q', respectively; # malformed grouping structure may yield unpredictable results. # 2. `moveto' is represented by `m'. # 3. `lineto' is represented by either `l' or `L'. # 4. `curveto' is represented by either `c' or `C'. # 5. `setlinewidth' is represented by `w'. # 6. `setlinejoin' is represented by `j'. # 7. `setlinecap' is represented by `J'. # 8. `setmiterlimit' is represented by `M'. # 9. `setdash' is represented by `d'. # 10. Curves start with `*u' and end with `*U'; no `q'/`Q' commands are # expected to occur inside a curve, i.e., between `*u' and `*U' commands; # `q'/`Q' pairs occuring outside a curve, i.e., between `*U' and `*u' # commands, are ignored; actually, the latter situation should not # occur either. # 11. Component paths of a multi-path curve end consistently either # with `f' (filling), or `s'/`S' (stroking of closed and open paths, # resp.), or `h W n' (clipping; in fact, only `n' is taken taken into # account). # 12. Structural comments `%%BoundingBox' and `%%EndSetup' should occur at # the beginning of the file (in this order). # --- # COMMENTS: # 1. The engine works in such a way that at first a necessary information # about paths is collected; during this stage only the coordinates of # nodes are written; after processing all the data the ``painting'' code # is generated; this complicates the AWK code a bit due to controlling # `gsave'/`grestore' nesting; a simplified approach is used: instead of # recording the full nesting tree, a ``backbone'' of a nesting structure # is reconstructed (cf. item 10 above). # 2. A little bit more complicated (in comparison with other commands) is # the translation of `d' (`setdash') command; in addition to the # assumptions specified above, it is assumed that at least one space # precedes `[' and `d', and follows `]'. # 3. Some complexity is also involved at the METAFONT level at the stage of # computing of a bounding box; as a default, the graphic object is shifted # such that the left lower corner of the bounding box coincides with # the origin of the coordinate system; by manual alteration of the # resulting METAFONT file the user can easily control the situation, e.g., # vertical or horizontal shift (or both) can be prohibited, the original # bounding box can be preserved, etc.; one should also remember that # if clipping is involved, the computed bounding box may be invalid. # 4. Due to rounding errors the original EPS file and the EPS file generated # from a resulting METAFONT file may differ. # --------------------------------------------------------------------------- BEGIN { skipping=1 path_max=0 group_max=0 node_max=0 xl=0; yl=0; xh=72; yh=72; # emergency default # `q'/`Q' nesting is controled by the following three variables # (`ignore_grestore' controls ignoring `q'/`Q' pairs between curves): nesting_level=0; nesting_group=0; ignore_grestore=0 and } # --- (skipping==1) && ($0 ~ /^%%BoundingBox:/) {xl=$2; yl=$3; xh=$4; yh=$5} # --- (skipping==1) && $0=="%%EndSetup" {skipping=0; print "%%% fill fill_C draw_C clip_C set_BB find_BB close_path" print "%%% fill fix_fill_cmyk fix_draw_cmyk" print "%%% fill fix_line_width fix_line_join fix_line_cap" print "%%% fill fix_miter_limit fix_dash" print "%%% message write_preamble" print "%%% endchar write_postamble g_save g_restore" print "%%% addto ~" print "%%\\input mftform" print "input mftoeps; numeric w#, h#, d#, xl#, yl#, xh#, yh#, xs#, ys#;" print "xl#=" xl "bp#; yl#=" yl "bp#; xh#=" xh "bp#; yh#=" yh "bp#;"; print "if false: noxs:=0; fi % no horizontal shift, ignored by default" print "if false: noys:=0; fi % no vertical shift, ignored by default" print "if false: oribb:=0; fi", "% preserving the original bounding box, ignored by default" print "pinbb:=0; % default: shifting the object such that |(xl,yl)=(0,0)|" print "xs#=if known noxs: 0 else: -xl# fi;" print "ys#=if known noys: 0 else: -yl# fi;" print "w#=max(0,xh#+xs#); h#=max(0,yh#+ys#); d#=max(0,-yl#-ys#);" print "%" print "extra_eps_setup:=\"pixels_per_inch:=72\";", "% better resolution for this case" print "eps_mode_setup; define_pixels(xs, ys);" print "%" print "def ~ text xy = \\\\ = (bp*xpart(xy)+xs,bp*ypart(xy)+ys) enddef;" print "%%% step C B L M" print "def M = M_ ( enddef;" print "def M_(suffix $) = z$ enddef;" print "def B = ) B_ ( enddef;" print "def B_(suffix $) = .. controls z$a and z$b .. z$ enddef;" print "def L = ) L_ ( enddef;" print "def L_(suffix $) = -- z$ enddef;" print "def C = ) enddef;" print "def close_path suffix p =" print " p:=p if (point 0 of p)=(point length(p) of p): & else: -- fi cycle;" print "enddef;" print "%%% labels B L M" print "%%% fi C" print "% ---" print "beginchar("0",w#,h#,d#); path p[\\\\];" } # --- skipping==0 { for (i=1; i<=NF; i+=1) { # --- if ($i=="q") {++nesting_level; ++ignore_grestore} # --- if ($i=="Q") { --nesting_level if (ignore_grestore>0) {--ignore_grestore} else {++nesting_group} } # --- if ($i=="*u") { print ""; print "% BEGIN of GROUP", group_max ";" ignore_grestore=0; first_path[group_max]=path_max } # --- if ($i=="k") { fix_fill_cmyk[group_max]=$(i-4) "," $(i-3) "," $(i-2) "," $(i-1) } # --- if ($i=="K") { fix_draw_cmyk[group_max]=$(i-4) "," $(i-3) "," $(i-2) "," $(i-1) } # --- if ($i=="w") fix_line_width[group_max]=$(i-1) "bp" # --- if ($i=="j") fix_line_join[group_max]=$(i-1) # --- if ($i=="J") fix_line_cap[group_max]=$(i-1) # --- if ($i=="M") fix_miter_limit[group_max]=$(i-1) "bp" # --- if ($i=="d") {# this is a little bit more complex case (see comment 2) l=i-2; # $(i-1)="d", $(i-1) is the offset for (j=l; $j !~ /\[/; --j) {} # $j contains the opening bracket for `setdash' # $l contains the closing bracket for `setdash' gsub(/\[/,"",$j); gsub(/\]/,"",$l) # delete both brackets was_something=0 fix_dash[group_max]="("; # construct parameters for `fix_dash' for (k=j; k<=l; ++k) { if ($k != "") { if (was_something==1) {aux=","} else {was_something=1; aux=""} fix_dash[group_max]=fix_dash[group_max] aux $k "bp" } } fix_dash[group_max]=fix_dash[group_max] ") " $(i-1) "bp" } # --- if ($i=="m") { print "% begin of path", path_max ";" print "%%\\BMU\\COLS" print "z" node_max "~" $(i-2) "," $(i-1) ";" node_path[node_max]=path_max; first_node[path_max]=node_max; ++node_max } # --- if (($i=="l") || ($i=="L")) { print "z" node_max "~" $(i-2) "," $(i-1) ";" node_path[node_max]=path_max; arc_type[node_max]="L"; ++node_max } # --- if (($i=="c") || ($i=="C")) { print "z" node_max "a~" $(i-6) "," $(i-5) ";" print "z" node_max "b~" $(i-4) "," $(i-3) ";" print "z" node_max "~" $(i-2) "," $(i-1) ";" node_path[node_max]=path_max; arc_type[node_max]="B"; ++node_max } # --- if (($i=="f") || ($i=="s") || ($i=="S") || ($i=="n")) { print "%%\\EMU"; path_group[path_max]=group_max; last_node[path_max]=node_max-1; group_type[group_max]=$i; # should be consistent for all paths in a group if (($i=="f") || ($i=="s") || ($i=="n")) is_closed_path=1 else is_closed_path=0 aux="p" path_max "=M" first_node[path_max] for (j=first_node[path_max]+1; j<=last_node[path_max]; ++j) { aux=aux " " arc_type[j] j if (j==last_node[path_max]) aux=aux " C;" if (length(aux)>70) {print aux; aux=""} } if (aux!="") print aux if (is_closed_path==1) print "close_path p" path_max ";" print "% end of path", path_max ";" ++path_max } # --- if ($i=="*U") { print "% END of GROUP", group_max ";"; group_nesting_level[group_max]=nesting_level; group_nesting_group[group_max]=nesting_group; last_path[group_max]=path_max-1; ++group_max } } } # --- END { node_max -= 1 path_max -= 1 group_max -= 1 # --- print "" print "if known oribb:" print " set_BB " xl "bp+xs," yl "bp+ys," xh "bp+xs," yh "bp+ys;" print "elseif known pinbb:" print " find_BB p0 for i:=1 upto " path_max": , p[i] endfor;" print " for i:=0 upto " node_max":" print " x[i]:=x[i]-xl_crd; y[i]:=y[i]-yl_crd;" print " if known x[i]a: x[i]a:=x[i]a-xl_crd; fi" print " if known x[i]b: x[i]b:=x[i]b-xl_crd; fi" print " if known y[i]a: y[i]a:=y[i]a-yl_crd; fi" print " if known y[i]b: y[i]b:=y[i]b-yl_crd; fi" print " endfor" print " for i:=0 upto " path_max": p[i]:=p[i] shifted -llxy; endfor" print " set_BB origin, urxy-llxy;" print "else:" print " find_BB p0 for i:=1 upto " path_max": , p[i] endfor;" print "fi" print "write_preamble jobname;" # --- # one extra `gsave'/`grestore' pair is always added by MFTOEPS, hence `-2' for (j=0; j<=group_nesting_level[0]-2; ++j) {print "g_save;"} for (g=0; g<=group_max; ++g) { if (g>0) { k=group_nesting_group[g]-group_nesting_group[g-1]; # k == number of groups closed in the meantime for (j=1; j<=k; ++j) print "g_restore;" k=group_nesting_level[g-1]-k; l=group_nesting_level[g]; # k == current nesting level, l == resulting nesting level for (j=1; j<=(k-l); ++j) print "g_restore;" for (j=-1; j>=(k-l); --j) print "g_save;" } if (fix_fill_cmyk[g]!="") print "fix_fill_cmyk " fix_fill_cmyk[g] ";" if (fix_draw_cmyk[g]!="") print "fix_draw_cmyk " fix_draw_cmyk[g] ";" if (fix_line_width[g]!="") print "fix_line_width " fix_line_width[g] ";" if (fix_line_join[g]!="") print "fix_line_join " fix_line_join[g] ";" if (fix_line_cap[g]!="") print "fix_line_cap " fix_line_cap[g] ";" if (fix_miter_limit[g]!="") print "fix_miter_limit " fix_miter_limit[g] ";" if (fix_dash[g]!="") print "fix_dash " fix_dash[g] ";" if (group_type[g]=="f") aux="fill_C " if ((group_type[g]=="s") || (group_type[g]=="S")) aux="draw_C " if (group_type[g]=="n") aux="clip_C " for (j=first_path[g]; j<=last_path[g]; ++j) { aux=aux "p" j; if (j==last_path[g]) {aux=aux ";"} else {aux=aux ","} if (length(aux)>70) {print aux; aux=""} } if (aux!="") print aux } # --- # one extra `gsave'/`grestore' pair is always added by MFTOEPS, hence `-2' for (j=0; j<=group_nesting_level[group_max]-2; ++j) print "g_restore;" print "write_postamble;" print "labels(range" 1 "thru" node_max ");" print "endchar;" print "% ---" print "end." print "%%\\end" }