%D \module %D [ file=supp-mps, %D version=1997.07.05, %D title=\CONTEXT\ Support Macros, %D subtitle=\METAPOST\ Inclusion, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. %D Forget about generic modules \unknown\ ... \ifx \undefined \contextversion \endinput \fi %D \METAPOST\ is John Hobbys alternative for \METAFONT\ and %D produces superior \POSTSCRIPT\ code. In this module we %D integrate \METAPOST\ support int \CONTEXT. We offer two %D tracks: %D %D \startitemize %D \item generating \METAPOST\ code, running this program from %D within \TEX\ using \type{\write18}, and importing the %D result %D \item generating \METAPOST\ code, processing the code %D afterward, and importing the result in a second pass %D \stopitemize %D %D The first approach uses a non standard \TEX\ feature, %D implemented in Web2c. I'm not going to discuss the pros and %D cons of running programs from within others, but all %D arguments against this can be overcome by implementing a %D \TEX\ worthy primitive: %D %D \starttyping %D \excuteMetaPost filename %D \stoptyping %D %D Ok then, let's start: \writestatus{loading}{ConTeXt Support Macros / MetaPost Inclusion} \unprotect \def\@@MPG{@MPG@} %D First we define a handy constant: \bgroup \catcode`\%=\@@other \xdef\letterpercent{\string%} \egroup % todo : sort out ^^M, \par and ; mess %D \macros %D {everyMPgraphic} %D %D Because some graphics interact with \TEX\ (i.e.\ \CONTEXT), we %D provide a hook for additional actions: \type {\everyMPgraphic}. \newtoks\everyMPgraphic \everyMPgraphic{\everyMPgraphic\emptytoks} %D \macros %D {startMPgraphic} %D %D From within \TEX\ one can execute \METAPOST\ code by putting %D it between the two commands %D %D \starttyping %D \startMPgraphic %D \stopMPgraphic %D \stoptyping %D %D This is implemented as: \let\stopMPgraphic\relax \long\def\startMPgraphic#1\stopMPgraphic {\startwritingMPgraphic \writecheckedMPgraphic{#1}% % potential speedup: pass #1 as macro \stopwritingMPgraphic} %D \macros %D {startMPrun} %D %D If we just want to run \METAPOST\ code, that is, not to %D explictly generate a figure in terms of \type{beginfig} and %D \type{endfig}, we can use: %D %D \starttyping %D \startMPgraphic %D \stopMPgraphic %D \stoptyping %D %D \starttyping %D \startMPrun %D \stopMPrun %D \stoptyping %D %D The next booleans are for internal purposes only. % some day a bit more more clear: % % run directly/run afterwards/run external defined % insert directly/insert whenever % use object/don't use objects \newif\ifMPgraphics \MPgraphicstrue \newif\ifMPrun \MPrunfalse \newif\ifMPwrapper \MPwrappertrue \let\stopMPrun\relax \ifCONTEXT \long\def\dostartMPrun#1#2\stopMPrun {\bgroup \MPruntrue \doifsomething{#1}{\def\MPgraphicfile{#1}}% \startwritingMPgraphic \writecheckedMPgraphic{#2}% \stopwritingMPgraphic \egroup} \def\startMPrun {\dosinglegroupempty\dostartMPrun} \else \long\def\startMPrun#1\stopMPrun {\MPruntrue \startwritingMPgraphic \writecheckedMPgraphic{#1}% \stopwritingMPgraphic \MPrunfalse} \fi %D \macros %D {startwritingMPgraphic, %D writeMPgraphic, %D stopwritingMPgraphic} %D %D If the writing process is divided into more steps, one can %D use the components of this macro directly. %D %D \starttyping %D \startwritingMPgraphic %D ... %D \writeMPgraphic{...} %D ... %D \writeMPgraphic{...} %D ... %D \stopwritingMPgraphic %D \stoptyping %D \macros %D {ifrunMPgraphics,ifrunMPTEXgraphics,ifinsertMPgraphics} %D %D These macros look a bit more complicated that one would %D expect at first sight. This is due to the two ways of %D processing these graphics, mentioned in a previous %D paragraph. Which method is used, the direct or indirect %D one, depends on a boolean. \newif\ifrunMPgraphics \runMPgraphicsfalse \newif\ifrunMPTEXgraphics \runMPTEXgraphicsfalse \newif\ifinsertMPgraphics \insertMPgraphicstrue %D If set to true, one can do with a single pass, else one must %D process the \METAPOST\ file \type{mpgraph} between two %D succesive \TEX\ runs. \ifx\MPgraphicfile\undefined \def\MPgraphicfile{mp\ifMPrun run\else graph\fi} \def\MPruntimefile{mprun} \fi %D \macros %D {MPgraphic} %D %D When we run \METAPOST\ from within \TEX, each graphic is %D processed at once, which means that we reuse this file many %D times. When however the execution is delayed, all graphics %D are saved in a separate figure. The current graphic is %D characterized bij a \COUNTER. This counter is available %D in \type{\MPgraphic}. \newcount\nofMPgraphics \newcount\currentMPgraphic \def\MPgraphic{0} % %D \macros % %D {ifreuseMPgraphics} % %D % %D If one want to reuse grapics, one can save much redundant % %D run time by setting the next switch to true. % % \newif\ifreuseMPgraphics \reuseMPgraphicstrue %D The three macros responsible for writing the graphic %D implement both schemes. %D \macros %D {MPinclusions, startMPinclusions, MPinitializations} %D %D One can include for instance common input commands by %D passing them to \type{\MPinclusions}: %D %D \starttyping %D \startMPinclusions %D input mp-mine ; %D \stopMPinclusions %D \stoptyping %D %D \starttyping %D \MPinclusions{input mp-mine} %D \stoptyping %D %D These commands reset their content each time. You can append %D code as follows: %D %D \starttyping %D \startMPinclusions[+] %D input mp-mine ; %D \stopMPinclusions %D \stoptyping %D %D The token register \type {\MPinitializations} is expanded %D before all other inclusions, the extensions are expanded %D only once per run. %D The next hack prevents too long lines: \long\def\runtimeobeyMPlines {\catcode35=11\relax % goodie \ifx\rawcharacter\undefined \let\obeyedline\space \else \obeylines \ifx\outputnewlinechar\undefined \edef\obeyedline{\rawcharacter{\endlinechar}}% \else \let\obeyedline\outputnewlinechar \fi \fi} \long\def\obeyMPlines % anyhow, we end up with ^^M's in the input {\obeylines \let\obeyedline\relax} % delay expansion \ifx\everydump\undefined % maybe we're not using context \else \appendtoks \let\obeyMPlines\runtimeobeyMPlines \to \everydump \fi %D We use two distinguished token registers: \newtoks \MPextensions % once per run (can be multiple graphics) \newtoks \MPinitializations % each graphic \let\stopMPextensions \relax % so that we can use it in \expanded \let\stopMPinitializations\relax % so that we can use it in \expanded \let\stopMPinclusions \relax % so that we can use it in \expanded \def\startMPextensions % no text checking done here ! {\begingroup \obeyMPlines \dostartMPextensions} \def\dostartMPextensions#1\stopMPextensions {\endgroup \MPextensions\expandafter{\the\MPextensions#1}} \def\startMPinitializations % no text checking done here ! {\begingroup \obeyMPlines \dostartMPinitializations} \def\dostartMPinitializations#1\stopMPinitializations {\endgroup \MPinitializations\expandafter{\the\MPinitializations#1}} \def\startMPinclusions {\begingroup \dosingleempty\dostartMPinclusions} \long\def\dostartMPinclusions {\obeyMPlines \dodostartMPinclusions} \long\def\dodostartMPinclusions[#1]#2\stopMPinclusions % document wide {\endgroup \doifelse{#1}{+} {\@EA\long\@EA\def\@EA\theMPinclusions\@EA {\theMPinclusions \writeMPgraphic{#2}}} {\long\def\theMPinclusions {% \expanded ! % \@EA\expanded\@EA{\@EA\writeMPgraphic\@EA{\the\MPextensions;}}% new \writeMPgraphic{#2}}}} \def\MPinclusions {\dosingleempty\doMPinclusions} \long\def\doMPinclusions[#1]#2% {\startMPinclusions[#1]#2\stopMPinclusions} \def\theMPextensions {\@EA\expanded\@EA{\@EA\writeMPgraphic\@EA{\the\MPextensions;}}} \def\theMPinitializations {\@EA\expanded\@EA{\@EA\writeMPgraphic\@EA{\the\MPinitializations;}}} \startMPinclusions \stopMPinclusions %D \macros %D {iflongMPlines} %D %D When grabbing a graphic deifnition, newlines are turned %D into spaces. By default we split the graphic definition %D at the colon, but long lines are still possible by %D setting the next boolean to true. \newwrite\MPwrite \newwrite\MPstaticwrite \newif\iflongMPlines \longMPlinestrue % we now have \obeyMPlines \ifx \overlaywidth \undefined \def \overlaywidth {4cm} \fi \ifx \overlayheight \undefined \def \overlayheight {3cm} \fi \ifx \overlaylinewidth \undefined \def \overlaylinewidth {0pt} \fi \def\presetMPdefinitions {\edef\overlaywidth {\overlaywidth \space}% \edef\overlayheight {\overlayheight \space}% \edef\overlaylinewidth {\overlaylinewidth\space}% \edef\currentwidth {\the\hsize \space}% \edef\currentheight {\the\vsize \space}} %D The \type {;} aware method (the \type {\else} branch) also %D takes care of \type {btex}||\type {etex}, \type %D {verbatimtex}||\type {etex}. The space after \type {tex} %D is essential, since it protects \type {text}. \newif\ifMPTEXgraphic \let\bufferedMPgraphicsline\empty \appendtoks \globallet\bufferedMPgraphicsline\empty \to \everyMPgraphic \chardef\MPgraphicsscanmode\plustwo % 0=no scanning, 1=simple scanning, 2=less simple, 3=even less % the next fails with \chardef\MPgraphicsscanmode\plusone % % \startMPextensions % gp_num_points_with_tex := 3 ; % \stopMPextensions \def\writeMPgraphic % no big #1 passing here {\iflongMPlines \ifMPTEXgraphic \ifcase\MPgraphicsscanmode \let\next\writeMPgraphiclongR \else \let\next\writeMPgraphiclongT \fi \else \let\next\writeMPgraphiclongN \fi \else \ifMPTEXgraphic \ifcase\MPgraphicsscanmode \let\next\writeMPgraphicshortN % we could \let \writeMPgraphicshortR\writeMPgraphicshortN \else \let\next\writeMPgraphicshortT \fi \else \let\next\writeMPgraphicshortN \fi \fi \next} \appendtoks \obeyMPlines \to \everyMPgraphic % more efficient than in each following grouped write \long\def\writeMPgraphiclongR#1% fast, no scanning {\bgroup \let\par\space \immediate\write\MPwrite{#1}% \egroup} \long\def\writeMPgraphiclongT#1% {\bgroup \let\par\space \longMPflushT#1\empty\par\relax\par \egroup} \long\def\writeMPgraphicshortT#1% {\bgroup \let\par\space \shortMPflushT#1\empty;\relax;% \egroup} \long\def\longMPflushT#1#2\par {\ifx#1\relax \else \dowriteMPgraphicline#1#2tex \relax etex\MPend \expandafter\longMPflushT \fi} \long\def\shortMPflushT#1#2;% {\ifx#1\relax \else \dowriteMPgraphicline#1#2tex \relax etex\MPend \expandafter\shortMPflushT \fi} \long\def\writeMPgraphiclongN#1% {\bgroup \let\par\space \longMPflushN#1\empty\par\relax\par \egroup} \long\def\writeMPgraphicshortN#1% {\bgroup \let\par\space \shortMPflushN#1\empty;\relax;% \egroup} \long\def\longMPflushN#1#2\par {\ifx#1\relax \else \nowriteMPgraphicline#1#2\MPend \expandafter\longMPflushN \fi} \long\def\shortMPflushN#1#2;% {\ifx#1\relax \else \nowriteMPgraphicline#1#2\MPend \expandafter\shortMPflushN \fi} \def\dowriteMPgraphicline{\futurelet\next\dodowriteMPgraphicline} \def\nowriteMPgraphicline{\futurelet\next\nonowriteMPgraphicline} %D Will move (check if next is needed): \long\def\nonowriteMPgraphicline#1\MPend {\ifx\next\empty\else\ifx\next\relax\else \bgroup \let\par\space \iflongMPlines %\immediate\write\MPwrite{#1;}% oeps, ; invalid \immediate\write\MPwrite{#1}% \else \long\edef\ascii{#1}% \expandafter\flushMPgraphicline\ascii\empty;\relax;% \fi \egroup \fi\fi} %D A first version: %D %D \starttyping %D \long\def\dodowriteMPgraphicline#1tex #2#3etex#4\MPend% %D {\ifx\next\empty\else\ifx\next\relax\else %D \bgroup %D \let\par=\space %D \ifx#2\relax %D \immediate\write\MPwrite{#1;}% %D \egroup %D \else %D \global\MPTEXgraphictrue %D \convertargument#2#3\to\ascii %D \immediate\write\MPwrite{#1tex \ascii etex}% %D \egroup %D \dowriteMPgraphicline#4tex \relax etex\MPend %D \fi %D \fi\fi} %D \stoptyping %D The next alternative also handles inclusions well. \newtoks \everyMPTEXgraphic \newif\ifforceMPTEXgraphic %D Before we supported the graph module, we had: %D %D \starttyping %D \convertargument etex\to\MPasciiB %D \convertargument textext\to\MPasciiC % geen "text" %D \convertargument graphictext\to\MPasciiD % geen "text" %D %D \long\def\checkMPTEXgraphic#1% %D {\ifforceMPTEXgraphic %D \global\MPTEXgraphictrue %D \else %D \expandafter\convertargument#1\to\MPasciia %D \doifstringinstringelse\MPasciiB\MPasciia{\global\MPTEXgraphictrue} %D {\doifstringinstringelse\MPasciiC\MPasciia{\global\MPTEXgraphictrue} %D {\doifstringinstringelse\MPasciiD\MPasciia{\global\MPTEXgraphictrue} %D {\global\MPTEXgraphicfalse}}}% %D \fi} %D \stoptyping %D %D The next alternative permits extensions in other modules %D without the need to know the details of testing. \newtoks\MPTEXgraphicchecks \long\def\writecheckedMPgraphic#1% {\ifforceMPTEXgraphic \global\MPTEXgraphictrue \else \global\MPTEXgraphicfalse \edef\ascii{#1}\convertcommand\ascii\to\MPascii \the\MPTEXgraphicchecks\relax % \relax is end condition! \fi \flushMPTEXgraphic % verbatimtex etc \writeMPgraphic{#1}} % potential optimization: pass \ascii %D We could have used a kind of array approach using a %D counter appended to \type {MPascii}, but this is an %D as efficient alternative. (The uglyness comes from %D expanding after the string \type {#1}). \let\MPTEXchecklist\empty \def\forceMPTEXcheck#1% {\addtocommalist{#1}\MPTEXchecklist \expanded{\convertargument#1\noexpand\to \@EA\noexpand\csname MPascii#1\endcsname}% \@EA\appendtoks \@EA\doifincsnameelse\csname MPascii#1\endcsname\MPascii {\global\MPTEXgraphictrue\gobbleuntil\relax}\donothing \to \MPTEXgraphicchecks} \forceMPTEXcheck{etex} \forceMPTEXcheck{textext} \forceMPTEXcheck{graphictext} %D \starttyping %D \forceMPTEXgraphictrue %D %D \forceMPTEXcheck{lintext} %D \forceMPTEXcheck{logtext} %D %D \startMPcode %D draw hlintext.lft(0, 20, 5, 20cm, "@3e") ; %D draw vlogtext.bot(0, 10, 9, 10cm, "@3e") ; %D \stopMPcode %D \stoptyping %D A goodie for Mojca (the gnuplot wizzard): %D %D \starttyping %D \startMPcode %D draw fullcircle scaled 4cm ; %D draw \textext{$\sqrt{\frac{3}{2}^3}$} ; %D \stopMPcode %D \stoptyping \long\def\textext#1{\normalunexpanded{textext("#1")}} % or \detokenize \def\flushMPTEXgraphic {\ifMPTEXgraphic \immediate\write\MPwrite{verbatimtex \the\everyMPTEXgraphic\space etex;}% \fi} \long\def\flushMPgraphicline#1#2;% {\ifx#1\relax \else \immediate\write\MPwrite{#1#2;}% \expandafter\flushMPgraphicline \fi} % the next one fails on btex \vbox {\hbox .. leading to \vbox \hbox % % \long\def\dodowriteMPgraphicline#1tex #2#3etex#4\MPend % {\ifx\next\empty\else\ifx\next\relax\else % \bgroup % \let\par\space % \ifx#2\relax % \iflongMPlines % \immediate\write\MPwrite{#1;}% % \else % \edef\ascii{#1}% % \expandafter\flushMPgraphicline\ascii\empty;\relax;% % \fi % \egroup % \else % \convertargument#2#3\to\ascii % \immediate\write\MPwrite{#1tex \ascii etex}% % \egroup % \dowriteMPgraphicline#4tex \relax etex\MPend % \fi % \fi\fi} % % so we need a two step approach % \long\def\dodowriteMPgraphicline#1tex % % {\doifnextcharelse\relax % {\nododowriteMPgraphicline{#1}} % {\redodowriteMPgraphicline{#1}}} % % better and faster % \long\def\dodowriteMPgraphicline#1tex #2% % {\ifx#2\relax % \expandafter\nododowriteMPgraphicline % \else % \expandafter\redodowriteMPgraphicline % \fi{#1} #2} % % \long\def\redodowriteMPgraphicline#1#2etex#3\MPend % {\ifx\next\empty\else\ifx\next\relax\else % \bgroup % \let\par\space % \convertargument#2\to\ascii % \immediate\write\MPwrite{#1tex \ascii etex}% % \egroup % \dowriteMPgraphicline#3tex \relax etex\MPend % \fi\fi} % % \long\def\nododowriteMPgraphicline#1#2\MPend % {\ifx\next\empty\else\ifx\next\relax\else % \bgroup % \let\par\space % \iflongMPlines % \immediate\write\MPwrite{#1;}% % \else % \long\edef\ascii{#1}% % \expandafter\flushMPgraphicline\ascii\empty;\relax;% % \fi % \egroup % \fi\fi} % extra scanning \long\def\dodowriteMPgraphicline#1tex #2% kind of ok {\ifx#2\relax \expandafter\nododowriteMPgraphicline \else \ifcase\MPgraphicsscanmode % can't happen \or \@EAEAEA\redodowriteMPgraphicline \or \doifinstringelse{b$} {#1$}{\@EAEAEA\redodowriteMPgraphicline}% {\doifinstringelse{verbatim$}{#1$}{\@EAEAEA\redodowriteMPgraphicline}% {\@EAEAEA\dododowriteMPgraphicline}}% \else \doifinstringelse { b$}{#1$}{\@EAEAEA\redodowriteMPgraphicline}% {\doifinstringelse {(b$}{#1$}{\@EAEAEA\redodowriteMPgraphicline}% {\doifinstringelse {=b$}{#1$}{\@EAEAEA\redodowriteMPgraphicline}% {\doifinstringelse{verbatim$}{#1$}{\@EAEAEA\redodowriteMPgraphicline}% {\@EAEAEA\dododowriteMPgraphicline}}}}% \fi \fi{#1} #2} \def\dododowriteMPgraphicline#1#2\MPend {\doifsomething{#1}{\xdef\bufferedMPgraphicsline{\bufferedMPgraphicsline#1tex }}% \dowriteMPgraphicline#2tex \relax etex\MPend} \long\def\redodowriteMPgraphicline#1#2etex#3\MPend {\ifx\next\empty \else\ifx\next\relax \else \bgroup \let\par\space \convertargument#2\to\ascii \immediate\write\MPwrite{\bufferedMPgraphicsline#1tex \ascii etex}% \globallet\bufferedMPgraphicsline\empty \egroup \dowriteMPgraphicline#3tex \relax etex\MPend \fi\fi} \long\def\nododowriteMPgraphicline#1#2\MPend {\ifx\next\empty \else\ifx\next\relax \else \bgroup \let\par\space \iflongMPlines \immediate\write\MPwrite{\bufferedMPgraphicsline#1;}% \globallet\bufferedMPgraphicsline\empty \else \long\edef\ascii{\bufferedMPgraphicsline#1}% \expandafter\flushMPgraphicline\ascii\empty;\relax;% \fi \egroup \fi\fi} %D This stripper is suboptimal in the sense that more %D \type{;}'s are output than feasible. Anyhow, \METAPOST\ %D can handle this and users may consider it being a sort %D of error prevention bonus. \ifx\blabelgroup\undefined \let\blabelgroup\bgroup \let\elabelgroup\egroup \fi \newconditional\firstMPgraphic \settrue\firstMPgraphic \appendtoks \let \# \letterhash \let \_ \letterunderscore \let \& \letterampersand \let \{ \letteropenbrace \let \} \letterclosebrace \to \everyMPgraphic %D Not the best place but we need to make sure that no funny %D active characters creep in. Some day we will move this code. \ifx\disablediscretionaries\undefined \let\disablediscretionaries\relax \fi \appendtoks \disablediscretionaries \to \everyMPgraphic \def\writeMPgraph {\immediate\write\MPwrite{mpgraph:=\the\currentMPgraphic;}} \def\startwritingMPgraphic {\blabelgroup \global\advance\nofMPgraphics \plusone \ifMPrun \else \allocateMPslot\currentMPgraphic \fi \enableincludeMPgraphics \xdef\MPgraphic{\the\currentMPgraphic}% \the\everyMPgraphic \presetMPdefinitions % moved to here from \writeMPgraphic \ifrunMPgraphics \openMPgraphicfile1{runtime}% % no reset here ! \theMPextensions \theMPinclusions \else \openMPgraphicfile0{collected}% % reset here ! global added (due to adding \blabelgroup) \theMPextensions \theMPinclusions \global\let\theMPextensions\relax \global\let\theMPinclusions\relax \fi \theMPinitializations % always \ifMPrun \else \ifMPwrapper \immediate\write\MPwrite{let mprunend = end ;}% \immediate\write\MPwrite{beginfig(\the\currentMPgraphic);}% \fi \fi \globallet\flushMPgraphics\closeMPgraphicfiles % \dodostopwritingMPgraphic \globallet\stopwritingMPgraphic\dostopwritingMPgraphic} \let\MPgraphicfiles\empty \let\MPinputtranslation\empty \def\openMPgraphicfile#1#2% #1=alwaysopen #2=message {\@EA\ifx\csname\@@MPG\@@MPG\MPgraphicfile\endcsname\relax \donetrue % \@EA\newwrite\csname\@@MPG\@@MPG\MPgraphicfile\endcsname % for the sake of plain usage \@EA\@EA\csname newwrite\endcsname\csname\@@MPG\@@MPG\MPgraphicfile\endcsname \doglobal\addtocommalist\MPgraphicfile\MPgraphicfiles \else \ifcase#1\relax\donefalse\else\donetrue\fi \fi \@EA\let\@EA\MPwrite\csname\@@MPG\@@MPG\MPgraphicfile\endcsname \ifdone \immediate\openout\MPwrite\MPgraphicfile.mp\relax \ifx\MPinputtranslation\empty\else \immediate\write\MPwrite{\MPinputtranslation}% \immediate\write\MPwrite{verbatimtex \MPinputtranslation etex ;}% \fi \immediate\write\MPwrite{\letterpercent\space #2 graphics of job "\jobname"}% \writeMPgraph \setMPrandomseed \fi} \def\dostopwritingMPgraphic {\ifMPrun \else \ifMPwrapper \immediate\write\MPwrite{endfig;}% \immediate\write\MPwrite{let end=mprunend;}% \fi \fi \ifrunMPgraphics \dodostopwritingMPgraphic \fi \elabelgroup} \def\dodostopwritingMPgraphic {\ifnum\currentMPgraphic>\zerocount \donetrue \else\ifMPrun \donetrue \else \donefalse \fi\fi \ifdone \finishwritingMPgraphics \runMPgraphic\MPgraphicfile \fi \globallet\flushMPgraphics\relax} \def\finishwritingMPgraphics {\ifMPwrapper\immediate\write\MPwrite{end.}\fi \immediate\closeout\MPwrite} \def\closeMPgraphicfiles {\ifrunMPgraphics \else \ifx\MPgraphicsfiles\empty\else \def\docommand##1% {\message{[flush and process ##1.mp afterwards]}% \@EA\let\@EA\MPwrite\csname\@@MPG\@@MPG##1\endcsname \finishwritingMPgraphics}% \processcommacommand[\MPgraphicfiles]\docommand \fi \fi} \let\stopwritingMPgraphic\relax \let\flushMPgraphics \relax %D By default each graphic gets its own slot (number). Later %D on we will define a recycle bin. \def \allocateMPslot#1{\global\advance#1\plusone} \def\deallocateMPslot#1{} %D \macros %D {translateMPinput} %D %D For my polish friends: %D %D \starttyping %D % translate=il2-pl %D %D \translateMPinput{il2-pl} %D %D \startMPenvironment[global] %D \setupbodyfont[plr] %D \stopMPenvironment %D %D \TeX: ± ¶ %D %D \startMPcode %D draw btex MetaPost: ± ¶ etex scaled 5 ; %D \stopMPcode %D \stoptyping \def\translateMPinput#1% % {\xdef\MPinputtranslation{\letterpercent -translate-file=#1\space}} % at some point % {\xdef\MPinputtranslation{\letterpercent --8bit}} % some time later {\globallet\MPinputtranslation\empty} % the new mpost is 8 bit clean %D \macros %D {setMPrandomseed} %D %D Did you notice the random seed initialization? This is %D needed because \METAPOST\ has a rather poor initialization, %D which in some implementations depends on the time in %D minutes. So, in quick successive runs, random is not that %D random. \newif\ifsetMPrandomseed \setMPrandomseedtrue % false by default \def\setMPrandomseed {\ifsetMPrandomseed \ifx\getrandomnumber\undefined \else \getrandomnumber\localMPseed\zerocount{4095}% \writeMPgraphic{randomseed:=\localMPseed;}% \fi\fi} %D This feature has become optional. Thanks to Fabrice Popineau, %D \METAPOST\ can now do a far better job! %D \macros %D {flushMPgraphics} %D %D When we use the indirect method, all graphics are saved in %D one file. This means that we cannot close this file after %D every \type{\stopMPgraphic}. Therefore we need to say: %D %D \starttyping %D \flushMPgraphics %D \stoptyping %D %D else the file is closed without writing the \METAPOST\ end %D command. One will notice this fast enough when in indirect %D mode. When using the direct mode this command is not %D implicitly needed, but ommiting it makes files less %D portable. %D \macros %D {loadcurrentMPgraphic, %D placeMPgraphic} %D %D Once defined, we can call for this graphic by saying: %D %D \starttyping %D \loadcurrentMPgraphic{setups} %D \placeMPgraphic %D \stoptyping %D %D This two stage insert permits some intermediate manipulations %D of the graphic, which temporary saved in: \newbox\MPgraphicbox \def\doloadcurrentMPgraphic#1% {\loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{#1}% \deallocateMPslot\currentMPgraphic} % added \ifCONTEXT \def\loadcurrentMPgraphic{\dosinglegroupempty\doloadcurrentMPgraphic} \else \let\loadcurrentMPgraphic\doloadcurrentMPgraphic \fi \def\loadMPgraphic#1#2% {\setbox\MPgraphicbox\hbox{\ifinsertMPgraphics\insertMPfile{#1}{#2}\fi}} \def\MPllx{0} \def\MPlly{0} % \def\placeMPgraphic% % {\ifMPshiftdrawing % \hbox{\hskip\MPllx\onebasepoint\raise\MPlly\onebasepoint\box\MPgraphicbox}% % \else % \box\MPgraphicbox % \fi} % % experimental: \def\placeMPgraphic {\ifMPshiftdrawing \edef\next {\wd\MPgraphicbox\the\wd\MPgraphicbox \ht\MPgraphicbox\the\ht\MPgraphicbox \dp\MPgraphicbox\the\dp\MPgraphicbox}% \setbox\MPgraphicbox\hbox {\hskip\MPllx\onebasepoint\raise\MPlly\onebasepoint\box\MPgraphicbox}% \next \fi \box\MPgraphicbox} %D \macros %D {startreusableMPgraphic, reuseMPgraphic, useMPbox} %D %D One can use the next macro for defining graphics that are %D to be reused. When the next switch is set, graphics are %D cached. \newif\ifuseMPbox \useMPboxtrue %D We assume that one can set objects: %D %D \starttyping %D \def\douseMPbox#1% %D {\setobject{MP}{#1}\vbox %D {\forgetall %D \loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{}% %D \deallocateMPslot\currentMPgraphic %D \placeMPgraphic}% %D \setgvalue{#1}{\getobject{MP}{#1}}} %D \stoptyping %D %D More safe is to use a number for \type {{MP}{#1}} which permits %D redefinition. We also saves the boundingbox. This helps positioning %D reused graphics in layers. \newcount\MPobjectcounter \ifx\getobject\undefined \def\setobject#1#2{\setbox\scratchbox} \fi % makes dep check happy \ifx\getobject\undefined \def\getobject#1#2{\box \scratchbox} \fi % makes dep check happy \def\douseMPbox#1% {\global\advance\MPobjectcounter\plusone \setobject{MP}{\number\MPobjectcounter}\vbox {\forgetall \loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{}% \deallocateMPslot\currentMPgraphic \placeMPgraphic}% \setxvalue{#1}% {\noexpand\dodouseMPbox{\number\MPobjectcounter}{\MPllx}{\MPlly}{\MPurx}{\MPury}}} \def\dodouseMPbox#1#2#3#4#5% space delimiting would save some tokens {\xdef\MPllx{#2}% but it's not worth the effort and looks \xdef\MPlly{#3}% ugly as well \xdef\MPurx{#4}% \xdef\MPury{#5}% \getobject{MP}{#1}} \def\nouseMPbox#1% {\setxvalue{#1}% {\noexpand\forgetall \noexpand\loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{}% \noexpand\deallocateMPslot{\currentMPgraphic}% \noexpand\placeMPgraphic}} \ifCONTEXT \else \let\douseMPbox\nouseMPbox \fi \ifCONTEXT \else \let\doifobjectssupportedelse\relax \fi \long\def\handlereusableMPgraphic#1#2% {\blabelgroup \enableincludeMPgraphics \startMPgraphic#2\stopMPgraphic \doifobjectssupportedelse\donothing\useMPboxfalse \ifuseMPbox \expandafter \douseMPbox \else \expandafter \nouseMPbox \fi {\@@MPG#1}% \getvalue{\@@MPG#1}% \elabelgroup} % \long\def\startreusableMPgraphic#1#2\stopreusableMPgraphic % {\ifundefined{\@@MPG#1}% % \long\setgvalue{\@@MPG#1}{\handlereusableMPgraphic{#1}{#2}}% % \fi} \long\def\dostartreusableMPgraphic#1#2\stopreusableMPgraphic {\blabelgroup \long\setgvalue{\@@MPG#1}{\handlereusableMPgraphic{#1}{#2}}% \elabelgroup} \def\reuseMPgraphic#1% {\blabelgroup \getvalue{\@@MPG#1}% \elabelgroup} \let\stopreusableMPgraphic \relax % so that we can use it in \expanded %D \macros %D {startuseMPgraphic,useMPgraphic} %D %D The every||time||it's||used original one is defined below. %D This one makes sense when the graphic uses random numbers. %D %D We can run (process graphic) without including them at that %D particular place. Therefore we explicitly disable %D inclusions (resulting in an dummy figure) when we are in MP %D run mode (see mfun-004 for an example, we process an %D example buffer which produced graphics). \long\def\handleuseMPgraphic#1#2% {\bgroup \enableincludeMPgraphics \startMPgraphic#2\stopMPgraphic \ifMPrun \else \loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{}% \placeMPgraphic \fi \deallocateMPslot\currentMPgraphic \egroup} \long\def\startuseMPgraphic {\blabelgroup \obeyMPlines \dostartuseMPgraphic} \long\def\dostartuseMPgraphic#1#2\stopuseMPgraphic {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}}% \elabelgroup} \long\def\startusableMPgraphic {\blabelgroup \obeyMPlines \dostartusableMPgraphic} \long\def\dostartusableMPgraphic#1#2\stopusableMPgraphic {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}}% \elabelgroup} \let\useMPgraphic\reuseMPgraphic \let\stopuseMPgraphic \relax % so that we can use it in \expanded \let\stopusableMPgraphic \relax % so that we can use it in \expanded %D \macros %D {doifMPgraphicelse} %D %D For (mainly internal) purposes we provide a test macro. % \def\doifMPgraphicelse#1% % {\doifdefinedelse{\@@MPG#1}} \def\doifMPgraphicelse#1% {\blabelgroup \doifdefinedelse{\@@MPG#1}% {\elabelgroup\firstoftwoarguments} {\elabelgroup\secondoftwoarguments}} %D \macros %D {includeMPgraphic} %D %D In a graphic one can call up another (predefined one) %D like: %D %D \starttyping %D \startuseMPgraphic{a} %D fill fullcircle scaled 100 ; %D \stopuseMPgraphic %D %D \startuseMPgraphic{b} %D \includeMPgraphic{a} %D fill fullsquare rotated 45 scaled 50 withcolor red ; %D \stopuseMPgraphic %D %D \useMPgraphic{b} %D \stoptyping \def\includeMPgraphic#1% {\executeifdefined{\@@MPG#1};} % ; if not found \def\enableincludeMPgraphics {\let\handleuseMPgraphic \secondoftwoarguments \let\handlereusableMPgraphic\secondoftwoarguments} %D We didn't yet define the macro responsible for processing %D the graphic from within \TEX. \def\runMPgraphic#1% {\ifrunMPgraphics \executeMETAPOST{#1}% \else % \message{[flush and process \MPgraphicfile.mp afterwards]}% \fi} %D \macros %D {useMETAFUNformat} %D %D For faster running, one can generate a format, saying %D %D \starttyping %D mpost -ini context %D \stoptyping %D %D (The resulting \type {mem} file should be moved to the %D right location. Watch out for misatching \type {progname} %D directives, since they can clutter memory. \newif\ifuseMETAFUNformat %D \macros %D {executeMetaPost, executeMETAPOST, executesystemcommand} %D %D With \type{\executeMETAPOST} being defined as: \ifx\undefined\executeMETAPOST \def\executeMETAPOST#1{\executesystemcommand{\executeMetaPost{#1}}} \fi %D There are two system dependant definitions: \ifx\undefined\executesystemcommand \def\executesystemcommand#1{\immediate\write18{#1}} \fi \ifx\TEXEXECcommand \undefined \def\TEXEXECcommand{texmfstart texexec} \fi \ifx\undefined\executeMetaPost \ifx\undefined\interactionmode \chardef\interactionmode=255 \fi \def\MPOSTbatchswitch {-interaction=batchmode} % was -int, but newer mpost does not support partial flags \def\MPOSTnonstopswitch {-interaction=nonstopmode} % was -int, but newer mpost does not support partial flags \def\MPOSTformatswitch {-progname=metafun -mem=} \def\MPOSTdriver {dvips} \def\executeMPOST#1% direct call {mpost \ifcase\interactionmode\MPOSTbatchswitch\or\MPOSTnonstopswitch\fi \space\ifuseMETAFUNformat \MPOSTformatswitch metafun \fi #1} \def\executeMPTEX#1% slower, due to nested texexec call {\TEXEXECcommand\space --batch \ifcase\interactionmode --logfile='mptex.log' \fi --output=\MPOSTdriver\space \ifuseMETAFUNformat --mpformat=metafun \fi --mptex --nomp --once #1} \def\executeMetaPost {\ifrunMPTEXgraphics \ifMPTEXgraphic \@EAEAEA\executeMPTEX \else \@EAEAEA\executeMPOST \fi \else \@EA\executeMPOST \fi} \fi %D The batchmode and nonstopmode (introduced in 2003 for %D Patrick Gundlach) switches may differ per binary and are %D supported by \TEXEXEC. %D \macros %D {insertMPfile} %D %D One can define this command in advance or redefine it after %D loading this module. The same goes for the forward %D reference to the figure loading macro: \ifx\undefined\insertMPfile \def\insertMPfile#1#2% {\ifx\undefined\externalfigure \message{[insert file #1 here]}% \else \externalfigure [#1] [\c!type=\c!mps,\c!object=\v!no, \c!symbol=\v!yes,\c!reset=\v!yes, \c!maxwidth=,\c!maxheight=, \c!frame=\v!off,\c!background=, #2]% \fi} \fi %D This macro takes {\em two} arguments, the second one can be %D used to pass info to the inclusion macro. Some examples %D of its use can be found in the modules \type{supp-tpi} and %D \type{prag-log}. %D This module can be used in \PLAIN\ \TEX too. When using %D \DVIPS, just try to process: %D %D \starttyping %D \input supp-mps %D %D \runMPgraphicstrue %D %D \def\insertMPfile#1#2% %D {\special{psfile=#1}} %D %D \startuseMPgraphic{1} %D prologues := 1; %D draw (0,0) withpen pencircle scaled 100; %D \stopuseMPgraphic %D %D \useMPgraphic{1} %D \stoptyping %D %D Don't forget to enable \type{\write18}. When does not say %D \type{\runMPgraphicstrue}, the \METAPOST\ scratch file %D must be closed by saying %D %D \starttyping %D \flushMPgraphics %D \stoptyping %D %D When using the indirect method, one has to process the file %D \type{mpgraph.mp} between two successive \TEX\ runs. %D %D \METAPOST\ needs the public domain \DVI\ to \POSTSCRIPT\ %D converter \DVIPS. This symbiosis originates in the need to %D include the fonts (glyphs) that \METAPOST\ uses in the %D \POSTSCRIPT\ file. Driver independancy was one of my %D prerequisites for using \METAPOST, so I decided to build %D this kind of support myself. Personally I consider driver %D dependancy a drawback for the dissemination of such a %D package. The second part of this module more or less %D decouples \METAPOST\ and \DVIPS. %D %D The macros hereafter are copied from the module %D \type{m-metapost}. After writing module \type{supp-pdf} I %D added this method to the module named and after a while %D decided to hook it into module \type{spec-yy}. Therefore %D they made it into a support module, but in a slightly %D different way. %D \macros %D {includeMPfonts, ifincludeMPfonts} %D %D The method we use is both robust and simple: one can do %D with calling the next macro with the filename as argument: %D %D \starttyping %D \includeMPfonts{filename} %D \stoptyping %D %D We can turn of this mechanism with: %D %D \starttyping %D \includeMPfontsfalse %D \stoptyping %D %D {\em Currently this method fails for situations where the %D font definition is not on one line, which is he case when %D unkerned fonts are used along with long lines. One solution %D for this is to increase the value of \type {max_print_line} %D in \type {texmf.cnf}.}} \newif\ifincludeMPfonts \includeMPfontstrue \def\includeMPfonts#1% {\ifincludeMPfonts \bgroup \message{[MP fonts #1]}% %\uncatcodespecials \endlinechar\minusone \setMPspecials \obeyMPspecials \setbox\scratchbox\hbox {\hskip-\maxdimen \doprocessfile\scratchread{#1}\handleMPfont}% \smashbox\scratchbox \box\scratchbox \egroup \fi} \def\UseMetaPostGraphic {\includeMPfonts} % upward compatible \def\DontUseMetaPostGraphics {\includeMPfontsfalse} % upward compatible %D The characters are collected in a box and moved as far as %D possible into the left margin. The resulting box has no %D dimensions and can be prepended (appended) to the special %D that handles the inclusion. The characters are in the file %D but made invisible. %D %D In \CONTEXT\ font handling is intergrated in the figure %D inclusion macros. A decent plain \TEX\ alternative is: %D %D \starttyping %D \def\includeMPgraphic#1% %D {\hbox\bgroup %D \includeMPfonts{#1}% %D \dogetEPSboundingbox{#1}{\dimen2}{\dimen4}{\dimen6}{\dimen8}% %D \advance\dimen6 by -\dimen2 %D \advance\dimen8 by -\dimen4 %D \vbox to \dimen8 %D {\forgetall %D \vfill %D \hsize\dimen6 %D \special %D {PSfile="#1"\space %D llx=\EPSllx\space %D lly=\EPSlly\space %D urx=\EPSurx\space %D ury=\EPSury\space}}% %D \egroup} %D \stoptyping %D %D This macro needs \type {supp-eps.tex} and provided no %D scaling. For \LATEX\ users the next one will do: %D %D \starttyping %D \def\includeMPgraphic#1#% %D {\hbox\bgroup %D \def\includeMPgraphics##1% %D {\includeMPfonts{##1}% %D \includegraphics[typetype=mps,#1]{##1}% or whatever type they use %D \egroup}% %D \includeMPgraphics} %D \stoptyping %D We scan the graphics file for the \type{fshow} operator, %D that is, lines that start with \type{(}. If found it %D interprets the line, which looks like: %D %D \starttyping %D (string ... string) font size fshow %D \stoptyping %D %D Font definitions specified in the preamble are simply %D ignored. Only lines starting with \type{(} are interpreted. \def\dohandleMPfont#1#2\relax {\if#1(\expandafter\includeMPcharacters\fileline\relax\fi} \def\handleMPfont {\expandafter\dohandleMPfont\fileline\relax} %D Before we start scanning for data, we first change some %D \CATCODES. The first set of macro's is copied from module %D \type{supp-pdf}. This scheme is a bit overdone for this %D module, but using the same macros saves us some memory. \def\octalMPcharacter#1#2#3% {\char'#1#2#3\relax} \bgroup \catcode`\|=\@@comment \catcode`\%=\@@active \catcode`\[=\@@active \catcode`\]=\@@active \catcode`\{=\@@active \catcode`\}=\@@active \catcode`B=\@@begingroup \catcode`E=\@@endgroup \gdef\keepMPspecials| B\let%\letterpercent| \def[B\noexpand[E| \def]B\noexpand]E| \def{B\noexpand{E| \def}B\noexpand}EE \gdef\ignoreMPspecials| B\let%\letterpercent| \def[BE| \def]BE| \def{BE| \def}BEE \gdef\obeyMPspecials| B\def%B\char 37\relax E| \def[B\char 91\relax E| \def]B\char 93\relax E| \def{B\char123\relax E| \def}B\char125\relax EE \gdef\setMPspecials| B\setnaturalcatcodes \catcode`\\=\@@escape \catcode`\%=\@@active \catcode`\[=\@@active \catcode`\]=\@@active \catcode`\{=\@@active \catcode`\}=\@@active \lccode`\-=0 | latex sets this to `\- \lccode`\%=`\% | otherwise it's seen as a number \def\(B\char40\relax E| \def\)B\char41\relax E| \def\\B\char92\relax E| \def\0B\octalMPcharacter0E| \def\1B\octalMPcharacter1E| \def\2B\octalMPcharacter2E| \def\3B\octalMPcharacter3E| \def\4B\octalMPcharacter4E| \def\5B\octalMPcharacter5E| \def\6B\octalMPcharacter6E| \def\7B\octalMPcharacter7E| \def\8B\octalMPcharacter8E| \def\9B\octalMPcharacter9EE \egroup %D The lines starting with \type{(} are interpreted and %D handled by %D %D \starttyping %D \def\includeMPcharacters(#1) #2 #3 #4\relax% %D {\font\temp=#2 at #3bp\temp#1} %D \stoptyping %D %D While processing some \TUG~98 proceedings, I also had to %D deal with: %D %D \starttyping %D /nfont {10 div dup scale 10} def %D (T) ANTTB 7.13086 nfont fshow %D \stoptyping %D %D which comes to rounding sizes. This is something %D experimental. (The macro in supp-pdf.tex is more %D advanced.) \def\PSnfont{nfont} \def\includeMPcharacters(#1) #2 #3 #4#5#6#7#8#9\relax {\edef\temp{#4#5#6#7#8}% \ifx\temp\PSnfont % round font size (to pt) \scratchdimen#3\onepoint \ifdim\scratchdimen<\onepoint \def\size{1pt}% \else \advance\scratchdimen .5\onepoint \def\size##1.##2\relax{\def\size{##1pt}}% \expandafter\size\the\scratchdimen\relax \fi \else \edef\size{#3bp}% \fi \font\temp=#2 at \size \temp\if#1 \char32\else#1\fi} %D This method is both robust and reasonable fast. The only %D disadvantage is that when not embedded properly in the %D graphics inclusion macros, one has to load all graphics by %D hand. %D Now let's see if things work all right and show the example %D files that are part of the \METAPOST\ distribution: %D %D \setupexternalfigures[directory={../sample}] %D \startlinecorrection %D \setupalign[middle] %D \leavevmode %D \startcombination[3*3] %D {\externalfigure[mp-exa-1][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-2][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-3][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-4][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-5][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-6][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-7][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-8][frame=on,width=.2\hsize]} {} %D {\externalfigure[mp-exa-9][frame=on,width=.2\hsize]} {} %D \stopcombination %D \stoplinecorrection %D %D Here we used calls like: %D %D \starttyping %D \externalfigure[mp-exa-1][methode-mps,frame=on,width=.2\hsize] %D \stoptyping %D \macros %D {convertMPcolors, %D ifconvertMPcolors,ifreduceMPcolors,ifforceMPcolors} %D %D When I told the editors that I wanted to use colored %D \METAPOST\ graphics in the color issue of the \MAPS, I was %D asked to use the \cap{CMYK} colorspace instead of \cap{RGB} %D one. However, \METAPOST\ only supports \cap{RGB} colors. I %D decided to write a utility to convert the \type %D {setrgbcolor} operators into \type {setcmykcolor} ones, and %D some experiments showed me that I could best let \TEX\ do it %D itself. Here it is: %D %D There are two booleans that control the conversion process. %D These are false by default. \newif\ifconvertMPcolors \newif\ifreduceMPcolors \newif\ifforcegrayMPcolors %D The main macro is called as: %D %D \starttyping %D \convertMPcolors{filename} %D \stoptyping %D %D When active, this macro returns a message saying if indeed %D conversion took place. The old file is overwritten! This %D saves time in a succesive passes and can't harm, simply %D because MP can generate them anew. \def\convertMPcolorpath{} \def\convertMPcolorfile{metacmyk.tmp} \def\convertMPcolors#1% todo: open on local path, no copy {\bgroup \ifforcegrayMPcolors \donetrue \else\ifconvertMPcolors \donetrue \else \donefalse \fi\fi \ifdone \message{[MP color conversion #1}% \endlinechar\minusone \uncatcodespecials \donefalse \immediate\openout\scratchwrite\convertMPcolorpath\convertMPcolorfile\relax \doprocessfile\scratchread{#1}\handleMPcolor \immediate\closeout\scratchwrite \ifdone \immediate\openout\scratchwrite\convertMPcolorpath#1\relax \doprocessfile\scratchread{\convertMPcolorpath \convertMPcolorfile}\handleMPcopy \immediate\closeout\scratchwrite \message{done]}% \else \message{not needed]}% \fi \immediate\openout\scratchwrite\convertMPcolorpath\convertMPcolorfile \immediate\closeout\scratchwrite \fi \egroup} %D The process is rather simple: read a line, look for the %D \type {setrgbcolor} operator, recalculate the components and %D check for gray reduction or black removal, write the result %D to a temporary file, and go on. Afterwards, the file is %D copied back. We don't have to reduce to gray scales; %D \METAPOST\ already takes care of that. %D The next macro is needed for forced conversion. This macro %D is copied from \type{colo-ini}, just in case one uses this %D module outside \CONTEXT. \ifx\@@cl@@s \undefined \def\@@cl@@s{0} \fi \ifx\convertRGBtoGRAY\undefined \def\convertRGBtoGRAY#1#2#3% {\scratchdimen#1\onepoint \scratchdimen300\scratchdimen \scratchcounter\scratchdimen \scratchdimen#2\onepoint \scratchdimen590\scratchdimen \advance\scratchcounter \scratchdimen \scratchdimen#3\onepoint \scratchdimen110\scratchdimen \advance\scratchcounter \scratchdimen \advance\scratchcounter \!!medcard \divide\scratchcounter \!!maxcard \edef\@@cl@@s{\realcolorvalue\scratchcounter}} \fi %D BTW, this code is quite old, and not as complete as the %D \PDF\ converter, which also handles spot colors and so. \def\handleMPcolor {\expandafter\dohandleMPcolor\fileline setrgbcolor*\\} \def\dohandleMPcolor#1setrgbcolor#2#3\\% {\if#2*% \immediate\write\scratchwrite{#1}% \else \dodohandleMPcolor#1setrgbcolor#2#3\\% \fi} \def\dodohandleMPcolor#1 #2 #3setrgbcolor#4setrgbcolor*\\% old and maybe broke {\bgroup \ifdim#1pt=.123pt \immediate\write\scratchwrite{#1 #2 #3 setrgbcolor}% \else \ifforcegrayMPcolors \convertRGBtoGRAY{#1}{#2}{#3}% \immediate\write\scratchwrite {\@@cl@@s \space setgray #4}% \else \dimen0=\onepoint \advance\dimen0 -#1\points \dimen2=\onepoint \advance\dimen2 -#2\points \dimen4=\onepoint \advance\dimen4 -#3\points \ifreduceMPcolors \dimen6\dimen0 \ifdim\dimen2<\dimen6 \dimen6\dimen2 \fi \ifdim\dimen4<\dimen6 \dimen6\dimen4 \fi \advance\dimen0 -\dimen6 \advance\dimen2 -\dimen6 \advance\dimen4 -\dimen6 \else \dimen6\zeropoint \fi \immediate\write\scratchwrite {\withoutpt\the\dimen0 \space \withoutpt\the\dimen2 \space \withoutpt\the\dimen4 \space \withoutpt\the\dimen6 \space setcmykcolor #4}% \fi \fi \egroup \donetrue} % needed for message \def\handleMPcopy {\immediate\write\scratchwrite{\fileline}} %D The next examples show the color conversion macros in %D action. These examples also demonstrate in||text \METAPOST\ %D handling. As we will see, the conversion is hooked into the %D \CONTEXT\ color mechanism. %D %D By setting both \type{rgb} and \type{cmyk} to off, we force %D conversion to gray scales using: %D %D \placeformula[-] %D \startformula %D G = .30r + .59g + .11b %D \stopformula %D %D By using buffers, we keep the \ASCII\ layout clean: %D %D \startbuffer %D \startbuffer[rgb] %D \setupcolors[rgb=ja,cmyk=nee,reduction=no,conversion=no] %D \useMPgraphic{hans} %D \stopbuffer %D %D \startbuffer[cmyk] %D \setupcolors[rgb=nee,cmyk=ja,reduction=no,conversion=no] %D \useMPgraphic{hans} %D \stopbuffer %D %D \startbuffer[cmy] %D \setupcolors[rgb=nee,cmyk=ja,reduction=yes,conversion=no] %D \useMPgraphic{hans} %D \stopbuffer %D %D \startbuffer[gray] %D \setupcolors[rgb=nee,cmyk=nee,reduction=no,conversion=no] %D \useMPgraphic{hans} %D \stopbuffer %D \stopbuffer %D %D \typebuffer %D \getbuffer %D %D The graphic is rather simple and is generated each time %D it's called: %D %D \global\runMPgraphicstrue %D %D \startbuffer %D \startbuffer[graphic] %D \startuseMPgraphic{hans} %D width :=\the\textwidth/5; %D height := width/4; %D fill fullcircle %D xscaled width %D yscaled height %D withcolor (\RedGreenBlue); %D \stopuseMPgraphic %D \stopbuffer %D \stopbuffer %D %D \typebuffer %D \getbuffer %D %D Next we combine the four alternative interpretations in a %D combination: %D %D \startbuffer %D \startbuffer[result] %D \startcombination[4] %D {\getbuffer[rgb]} {\tfxx original} %D {\getbuffer[cmyk]} {\ttxx\string\convertMPcolorstrue} %D {\getbuffer[cmy]} {\ttxx\string\reduceMPcolorstrue} %D {\getbuffer[gray]} {\ttxx\string\forcegrayMPcolorstrue} %D \stopcombination %D \stopbuffer %D \stopbuffer %D %D \typebuffer %D \getbuffer %D %D Finally we call the buffers, using different setting: %D %D \startbuffer %D \placefigure %D {\METAPOST\ color conversions} %D {\def\RedGreenBlue{.1,.4,.6}\getbuffer[graphic]\getbuffer[result]\vskip6pt %D \def\RedGreenBlue{.1,.6,.4}\getbuffer[graphic]\getbuffer[result]\vskip6pt %D \def\RedGreenBlue{.4,.1,.6}\getbuffer[graphic]\getbuffer[result]\vskip6pt %D \def\RedGreenBlue{.4,.6,.1}\getbuffer[graphic]\getbuffer[result]\vskip6pt %D \def\RedGreenBlue{.6,.1,.4}\getbuffer[graphic]\getbuffer[result]\vskip6pt %D \def\RedGreenBlue{.6,.4,.1}\getbuffer[graphic]\getbuffer[result]} %D \stopbuffer %D %D \typebuffer %D \getbuffer %D %D By the way, when the \POSTSCRIPT\ file resulting from %D this input is converted into \PDF\ and viewed in Acrobat %D Reader, one can quite different colors from those %D displayed in \GHOSTSCRIPT, which view equals the %D \POSTSCRIPT\ originals. %D \macros %D {experimental} %D %D Some experimental macros: %D %D \starttyping %D \startMPdrawing %D \stopMPdrawing %D \pushMPdrawing %D \popMPdrawing %D \resetMPdrawing %D \ifMPdrawingdone %D \getMPdrawing %D \MPdivten[number] %D \stoptyping %D %D These macros are used in \PPCHTEX. \let\MPdrawingdata\empty \newif\ifMPdrawingdone \MPdrawingdonefalse \newif\ifMPshiftdrawing \MPshiftdrawingfalse \def\resetMPdrawing {\globallet\MPdrawingdata\empty \global\MPdrawingdonefalse} % why global push/pop here? \def\pushMPdrawing {\globalpushmacro\MPdrawingdata \globallet\MPdrawingdata\empty} \def\popMPdrawing {\globalpopmacro\MPdrawingdata} \def\getMPdrawing {\ifMPdrawingdone \expandafter\startMPgraphic\MPdrawingdata\stopMPgraphic \loadcurrentMPgraphic{}% \deallocateMPslot\currentMPgraphic \placeMPgraphic \fi} \def\startMPdrawing {\dosingleempty\dostartMPdrawing} \long\def\dostartMPdrawing[#1]#2\stopMPdrawing {\relax \bgroup \enableincludeMPgraphics \presetMPdefinitions % in case #2 has measures \doifelse{#1}{-}{\convertargument#2\to\asciia}{\long\def\asciia{#2}}% \long\xdef\MPdrawingdata{\MPdrawingdata\asciia}% \egroup} \let\stopMPdrawing\relax \def\MPdivten[#1]% {\@EA\@EA\@EA\doMPdivten\@EA\@EA\@EA[\@EA#1]} \def\doMPdivten[#1]% {\ifnum#1> 9999 \dodoMPdivtenB#1\else \ifnum#1> 999 \dodoMPdivtenC#1\else \ifnum#1> 99 \dodoMPdivtenD#1\else \ifnum#1> 9 \dodoMPdivtenE#1\else \ifnum#1> 0 \dodoMPdivtenF#1\else \ifnum#1<-9999 \dodoMPdivtenA#1\else \ifnum#1< -999 \dodoMPdivtenB#1\else \ifnum#1< -99 \dodoMPdivtenC#1\else \ifnum#1< -9 \dodoMPdivtenD#1\else \ifnum#1< 0 \dodoMPdivtenE#1\else 0 \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} \def\dodoMPdivtenA#1#2#3#4#5#6{#1#2#3#4#5.#6} \def\dodoMPdivtenB #1#2#3#4#5{#1#2#3#4.#5} \def\dodoMPdivtenC #1#2#3#4{#1#2#3.#4} \def\dodoMPdivtenD #1#2#3{#1#2.#3} \def\dodoMPdivtenE #1#2{#1.#2} \def\dodoMPdivtenF #1{.#1} % if we assume etex ... \def\MPdivten[#1]{\withoutpt\the\dimexpr#1pt/10\relax} %D \macros %D {startMPclip,grabMPclippath} %D %D We can use \METAPOST\ to calculate arbitrary clipping %D paths. Such a path is defined by (for instance): %D %D \starttyping %D \startMPclip{window} %D clip currentpicture to fullcircle xscaled \width yscaled \height ; %D \stopMPclip %D \stoptyping %D %D Such a path can be extracted (processed) by: %D %D \starttyping %D \grabMPclippath{window}{method}{width}{height}{default path} %D \stoptyping %D %D Currently only method 1 makes sense; it produces \PDF\ %D code. This macro only makes sense when hooked into a %D special routine. \let\MPclippath\empty \long\def\startMPclip#1#2\stopMPclip {\blabelgroup \long\setgvalue{MPC:#1}{\startMPgraphic#2\stopMPgraphic\dograbMPclippath}% \elabelgroup} \let\stopMPclip\relax \def\grabMPclippath#1#2#3#4#5% {\blabelgroup \edef\width {#3\space}\let\overlaywidth \width \edef\height{#4\space}\let\overlayheight\height \doifdefinedelse{MPC:#1} {\getvalue{MPC:#1}% \setxvalue{MPC:#1}{\noexpand\xdef\noexpand\MPclippath{\MPclippath}}}% {\xdef\MPclippath{#5}}% \ifcase#2\else % method 1 : \doglobal\stripcharacter urveto\from\MPclippath\to\MPclippath \doglobal\stripcharacter oveto\from\MPclippath\to\MPclippath \doglobal\stripcharacter ineto\from\MPclippath\to\MPclippath \fi \elabelgroup} %D We pose some restrictions to the \METAPOST\ code and pickup %D the clip path from the file. %D %D We turn the slash into a comment. The \type {\hbox} grabs spaces %D and the \type {%} triggers the grabber. Next we filter the %D clipping path, or actually, the first path. % \bgroup % \catcode`\%=\@@active % \catcode`\/=\@@comment % \gdef\dograbMPclippath/ % {\setbox\scratchbox=\hbox\bgroup/ % \catcode`\%=\@@active % \obeylines\let\obeyedline\space % \def\do##1newpath##2closepath##3\od/ % {\xdef\MPclippath{##2}\endinput}/ % \def%##1%%EOF/ % {\do##1newpathclosepath\od\endinput}/ % \readfile{\MPgraphicfile.\the\currentMPgraphic}{}{}/ % \deallocateMPslot\currentMPgraphic / new % \egroup} % \egroup \bgroup \catcode`\%=\@@active \catcode`\/=\@@comment \gdef\dograbMPclippath/ {\setbox\scratchbox=\hbox\bgroup/ \catcode`\%=\@@active \obeylines\let\obeyedline\space \def\do##1q n##2p W##3\od/ {\xdef\MPclippath{##2}\endinput}/ \def%##1%%EOF/ {\do##1q np W\od\endinput}/ \readfile{\MPgraphicfile.\the\currentMPgraphic}{}{}/ \ifx\MPclippath\empty \def\do##1newpath##2closepath##3\od/ {\xdef\MPclippath{##2}\endinput}/ \def%##1%%EOF/ {\do##1newpathclosepath\od\endinput}/ \readfile{\MPgraphicfile.\the\currentMPgraphic}{}{}/ \fi \deallocateMPslot\currentMPgraphic / new \egroup} \egroup %D \macros %D {recycleMPslots} %D %D When coding and embedding many \METAPOST\ figures in a %D document, one can save quite some disk space by using %D \PDFTEX\ and setting the next switch: \newif\ifrecycleMPslots \recycleMPslotstrue %D When a graphic takes space in the text flow, we can run %D into deadlock typesetting. In the first pass, the graphic %D is not available, but in the second pass it is. The %D placeholder that was put there in the first pass in now %D replace by the real graphic and as a result the document %D shrinks or grows and pages are removed or added. This in %D turn can trigger generation of other graphics, like those %D in the background. Graphics start swapping place and again %D page breaks change. You can imagine the mess we en dup %D with. %D %D This is why we provide was to use a dedicate range if %D numbers for fixed graphcs. Such graphics will not en dup %D in the text flow (at least their dimensions don't %D contribute to the main vertical list, and thereby they %D cannot interfere. We use a rather safe maximum of 4000 %D graphics here and 8000 in \type {meta-ini}. \newcount \maxnofMPgraphics \maxnofMPgraphics = 4000 % 8000 \newcount \minnofMPgraphics \minnofMPgraphics = 1 \newif \ifMPstaticgraphic \MPstaticgraphicfalse % determines slot allocation \def\locateMPslot#1% slightly faster on one slot, much faster on multiple slots {\ifundefined{\number#1MP}% no \ifcsname \letgvalueempty{\number#1MP}% \expandafter\gobbletwoarguments \else \global\advance#1\plusone \fi \locateMPslot#1} \def\allocateMPslot#1% {\ifrunMPgraphics \ifx\pdfliteral\undefined \recycleMPslotsfalse % quite certainly not pdftex \else\ifcase\pdfoutput \recycleMPslotsfalse % dvi mode or not pdftex (we need to handle dvipdfmx) \fi\fi \else \recycleMPslotsfalse \fi \ifrecycleMPslots % \doloop % slow but used seldom % {\doifundefined{\recurselevel MP} % {\letgvalueempty{\recurselevel MP}% % \global#1\recurselevel % \exitloop}}% \global#1\plusone \locateMPslot#1% % \message{[MP slot + \number#1]% \else\ifMPstaticgraphic % beware not the same as static graphics \global#1\maxnofMPgraphics \global\advance\maxnofMPgraphics \minusone \else \global#1\minnofMPgraphics \global\advance\minnofMPgraphics \plusone \fi\fi \ifnum\minnofMPgraphics<\maxnofMPgraphics \else \writestatus\m!systems{increase \string\maxnofMPgraphics}% \fi} \def\deallocateMPslot#1% {\ifrunMPgraphics \ifcase\pdfoutput \recycleMPslotsfalse \fi \else \recycleMPslotsfalse \fi \ifrecycleMPslots \global\letbeundefined{\number#1MP}% %\message{[MP slot - \number#1]}% \fi} %D Experimental and overloaded later, since we need to be %D more clever due to \METAPOST's limit of 4~open files. \def\MPdatafile {mp-\the\currentMPgraphic.mpd} \def\getMPdata {\input \MPdatafile\relax} %D \macros %D {MPtoks, MPbox} %D %D For convenience, we provide some scratch registers: \ifx\undefined\MPtoks \newtoks\MPtoks \fi \ifx\undefined\MPbox \newbox \MPbox \fi %D \macros %D {startMPcode} %D %D We can save some typing with: %D %D \starttyping %D \startMPcode whatever \stopMPcode %D \stoptyping %D %D this automatically places the graphic \long\def\startMPcode {\begingroup \obeyMPlines \dostartMPcode} \long\def\dostartMPcode#1\stopMPcode {\startuseMPgraphic{@@}#1\stopuseMPgraphic \useMPgraphic{@@}% \endgroup} \let\stopMPcode\relax %D \macros %D {startstaticMPgraphic} %D %D Dedicated to Aditya Mahajan. See meta-ini for usage. % \long\def\startstaticMPgraphic#1#2\stopstaticMPgraphic % {\bgroup % \MPstaticgraphictrue % \setMPrandomseedfalse % \def\MPgraphicfile{#1}% no \jobname here % \let\allocateMPslot \gobbleoneargument % \let\deallocateMPslot\gobbleoneargument % \let\runMPgraphic \gobbleoneargument % \MPextensions\emptytoks % \MPinitializations\emptytoks % \runMPgraphicstrue % \MPwrapperfalse % \enableincludeMPgraphics % \def\sometxt##1{\string\sometxt{##1}}% % \currentMPgraphic\plusone % hack, else no close % \startMPgraphic#2\stopMPgraphic % \executeMPgraphicfile % \egroup} % different version, less messy hooked into the rest \long\def\startstaticMPgraphic#1#2\stopstaticMPgraphic {\blabelgroup \def\MPgraphicfile{#1}% no \jobname here \let\MPwrite\MPstaticwrite \immediate\openout\MPwrite=\MPgraphicfile.mp \setMPrandomseedfalse \enableincludeMPgraphics \def\sometxt##1{\string\sometxt{##1}}% \the\everyMPgraphic \presetMPdefinitions \theMPinclusions % brrr \writeMPgraphic{\letterpercent mpenvironment: \the\everyMPTEXgraphic}% \writeMPgraphic{beginfig(1);}% \writeMPgraphic{#2}% \writeMPgraphic{endfig; end.}% \immediate\closeout\MPwrite \executeMPgraphicfile \elabelgroup} % this will go to meta-ini \def\delaysystemcommand {\ifx\installprogram\undefined \expandafter\executesystemcommand \else \expandafter\installprogram \fi} \def\MPgraphicfilerunner {texmfstart --ifchanged=\MPgraphicfile.mp texexec --mpstatic \MPgraphicfile.mp} \ifx\doifmode\undefined \def\executeMPgraphicfile {\ifrunMPgraphics\@EA\executesystemcommand\else\@EA\delaysystemcommand\fi{\MPgraphicfilerunner}} \else \def\executeMPgraphicfile{\doifmode{*\v!first} {\ifrunMPgraphics\@EA\executesystemcommand\else\@EA\delaysystemcommand\fi{\MPgraphicfilerunner}}} \fi %D Special for \XETEX\ (problem with newlines). This will go %D away once the version supporting \type {--8bit} is %D widespread. \ifnum\texengine=\xetexengine \let\obeyMPlines\relax \longMPlinesfalse % alas \fi \protect \endinput