%D \module %D [ file=supp-mpe, %D version=1999.07.10, %D title=\CONTEXT\ Support Macros, %D subtitle=METAPOST Special Extensions, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA / Hans Hagen \& Ton Otten}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. % fuzzy and complicating is the fact that we need to support % context as well as mptopdf, so we cannot fall back on the % special drivers and color module (although there may be % good reasons to use a smaller context instead); also, % shading is handled here while it should move to the special % driver - to do! %D This module is still experimental and deals with some %D extensions to \METAPOST. When using \POSTSCRIPT\ output, %D these extensions can be supplied by means of proper %D preamble definitions, but when producing \PDF\ we have to %D set up the appropriate datastructures ourselves. It acts as %D a plug in into \type {supp-pdf}. As soon as we need more %D extensions, we will generalize these macro. Some %D definitions will move to the special drivers. %D For usage in plain \TEX, say something: %D %D \starttyping %D \input supp-pdf %D \input supp-mpe %D %D \MPcmykcolorstrue %D \MPspotcolorstrue %D \chardef\makeMPintoPDFobject\plusone %D \stoptyping \ifx\writestatus\undefined \immediate\write16{[Loading MPS to PDF extensions.]} \else \writestatus{loading}{ConTeXt Support Macros / MPS extensions} \fi %D We implement extensions by using the \METAPOST\ special %D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones %D are flushed before or after the graphic data, but thereby %D are no longer connected to a position. %D %D We implement specials by overloading the \type {fill} %D operator. By counting the fills, we can let the converter %D treat the appropriate fill in a special way. The %D specification of the speciality can have two forms, %D determined by the setting of a boolean variable: %D %D \starttyping %D _inline_specials_ := false ; % comment like code (default) %D _inline_specials_ := true ; % command like code %D \stoptyping %D %D When the specification is embedded as comment, it looks %D like: %D %D \starttyping %D %%MetaPostSpecial %D \stoptyping %D %D The in||line alternative is more tuned for \POSTSCRIPT, %D since it permits us to define a macro \type {special}. %D %D \starttyping %D inline : special %D \stoptyping %D %D The \type {identifier} determines what to do, and the data %D can be used to accomplish this. A type~2 shading function %D has identifier~2. Alltogether, the number of parameters is %D specified in \type {size}. The \type {number} is the number %D of the fill that needs the special treatment. For a type~2 %D and~3 shaded fill, the datablock contains the following %D data: %D %D \starttyping %D from to n inner_r g b x y outer_r g b x y %D from to n inner_r g b x y radius outer_r g b x y radius %D \stoptyping %D %D The implementation below saves the data on the stack in %D a way similar to the macros in \type {supp-pdf.tex}, and %D just overload a few already defined handlers. That way, %D the existing macros are still generic. \footnote {Actually, %D the macros here are just as generic.} %D %D Currently the only extension concerns shading, which is %D accomplished by handling yet another value of \type %D {\finiMPpath}. The recource disctionary is stored and %D later picked up by the general \CONTEXT\ figure inclusion %D macros. \unprotect %D The \type {%%MetaPostSpecials: version.revision signal} line %D triggers this module into handling color specifications kind %D of special. We need this safeguard for non||special %D usage. \chardef\MPspecialversion = 0 % specials when >1 \chardef\MPspecialrevision = 0 % specials when >1 \chardef\MPspecialsignal = 0 % passed on by graphic \chardef\inlineMPspecials = 1 % only needed for stack resetting %D This macro handles the special definitions that are %D passed as comment. \def\dohandleMPspecialcomment#1 {\setMPargument{#1}% \advance\scratchcounter \minusone \ifcase\scratchcounter \handleMPspecialcommand \donetrue \doresetMPstack \let\handleMPsequence\dohandleMPsequence \expandafter\handleMPsequence \else \expandafter\dohandleMPspecialcomment \fi} \def\handleMPspecialcomment #1 % number of arguments {\doresetMPstack \scratchcounter#1\relax \ifcase\scratchcounter % when zero, inline shading is used \chardef\inlineMPspecials\plusone \let\handleMPsequence\dohandleMPsequence \expandafter\handleMPsequence \else \chardef\inlineMPspecials\zerocount \expandafter\dohandleMPspecialcomment \fi} %D When defined inline, we use another macro to handle the %D definitions. Actually, this macro is called by the %D previous ones. \def\handleMPspecialcommand {\ifcase\inlineMPspecials\or \advance\nofMParguments \minusone % pop the size \fi \ifundefined\MPspecial \message{[unknown \MPspecial]}% \else \csname\MPspecial\endcsname \fi \ifcase\inlineMPspecials \doresetMPstack % 0 \else \resetMPstack % 1 \fi} %D This macro triggers special support. Currently, the %D version and revision number are not used. Any version number %D greater than zero will enable special support. \newconditional\manyMPspecials % \settrue\manyMPspecials \def\handleMPspecialscomment #1.#2 #3 % version.revision signal #4=div=1000|10000 {\doresetMPstack \chardef\MPspecialversion #1% \chardef\MPspecialrevision#2% \chardef\MPspecialsignal #3% \let\handleMPsequence\dohandleMPsequence \ifnum#1=\plusone \expandafter\handleMPsequence \else \expandafter\handleMPspecialscommentx \fi} \def\handleMPspecialscommentx #1 % version 2 % {\doifelsedoifelse{#1}{10000}{\settrue\manyMPspecials}{\setfalse\manyMPspecials}% local {\ifnum10000=0#1\relax \settrue \manyMPspecials \else \setfalse\manyMPspecials \fi \setMPextensions \handleMPsequence} % one can say (in meta-ini): % % \prependtoks % _special_div_ := 1000\ifconditional\manyMPspecials0\fi ; % \to \MPextensions %D In case of \PDF, we need to prepare resourcs. \newtoks\MPstartresources \newtoks\MPstopresources \def\startMPresources {\the\MPstartresources \ifx\currentPDFresources\empty\else \message{[unused resources]}% \fi \global\let\currentPDFresources\empty} \def\stopMPresources {\let\currentPDFresources\empty \the\MPstopresources} %D Since colors are not subjected to transformations, we can %D only use colors as signal. In our case, we use a dummy colored %D path with a red color component of \type {0.n}, so \type %D {0.001} is the first path and \type {0.010} the tenth. Since %D \METAPOST strips trailing zeros, we have to padd the string. \newif\ifMPcmykcolors \newif\ifMPspotcolors \ifx\normalhandleMPrgbcolor\undefined % in case we reload this module \let\normalhandleMPrgbcolor \handleMPrgbcolor \let\normalhandleMPcmykcolor\handleMPcmykcolor \let\normalhandleMPgraycolor\handleMPgraycolor \let\normalhandleMPspotcolor\handleMPspotcolor \fi %D When we are using \CONTEXT, we will fall back to the %D better color conversion routines. This also has the advantage %D that we don't have to parse and convert the file. In this %D alternative, \type {\!MP} is not (yet) supported. Because %D we can (for efficiency reasons) turn off strokecolor, %D something we cannot do in \METAPOST\ converted code. \newif\ifPDFMPstrokecolor \PDFMPstrokecolortrue %D [This code should move to meta-ini.] \ifCONTEXT % we can use this for a better xgstate handling \def\checkPDFMPstrokecolor {\ifPDFMPstrokecolor \PDFstrokecolortrue \fi} \def\normalhandleMPrgbcolor {{\checkPDFMPstrokecolor\execcolorR\gMPa1:\gMPa2:\gMPa3:0:0\od}} \def\normalhandleMPcmykcolor {{\checkPDFMPstrokecolor\execcolorC\gMPa1:\gMPa2:\gMPa3:\gMPa4:0:0\od}} \def\normalhandleMPgraycolor {{\checkPDFMPstrokecolor\execcolorS\gMPa1:0:0\od}} % \def\normalhandleMPspotcolor % {{\checkPDFMPstrokecolor\execcolorP\gMPa1:\gMPa2:0:0\od}} \def\normalhandleMPspotcolor % ??? {{\checkPDFMPstrokecolor\execcolorP\gMPa1:\gMPa2:\gMPa3:\gMPa4:0:0\od}} \fi % In the previous macros we use the special drivers. A more % direct approach would have been: % % \def\doPDFstartrgbcolormode#1#2#3% % {\PDFcode{#1 #2 #3 rg #1 #2 #3 RG}} % % \def\doPDFstartcmykcolormode#1#2#3#4% % {\PDFcode{#1 #2 #3 #4 k #1 #2 #3 #4 K}} % % \def\doPDFstartgraycolormode#1% % {\PDFcode{#1 g #1 G}} % % \appendtoks % \let\dostartrgbcolormode \doPDFstartrgbcolormode % \let\dostartcmykcolormode\doPDFstartcmykcolormode % \let\dostartgraycolormode\doPDFstartgraycolormode % \to \everyMPtoPDFconversion %D Now we can handle special color signals. We only do this %D when special are detected. % \def\MPrgbnumber#1{\expandafter\doMPrgbnumber#1000.0000\relax} % \def\doMPrgbnumber#1.#2#3#4#5\relax{#2#3#4} %D We cannot use \type {\everyMPtoPDFconversion} because in \MPTOPDF\ %D we don't have the \type {\appendtoks} macro available. \def\setMPextensions {\ifconditional\manyMPspecials \def\MPrgbnumber##1{\expandafter\doMPrgbnumber##10000.00000\relax}% \def\doMPrgbnumber##1.##2##3##4##5##6\relax{##2##3##4##5}% \else \def\MPrgbnumber##1{\expandafter\doMPrgbnumber##1000.0000\relax}% \def\doMPrgbnumber##1.##2##3##4##5\relax{##2##3##4}% \fi} %D The naive case looks like: %D %D \starttyping %D \def\handleMPrgbcolor% %D {\setMPcolor %D \ifcase\MPspecialversion %D \resetMPcolor\normalhandleMPrgbcolor %D \else\ifnum\MPrgbnumber\lastMPrvalue=\MPspecialsignal %D % consider it to be a signal %D \else %D \resetMPcolor\normalhandleMPrgbcolor %D \fi\fi} %D \stoptyping %D %D However, since we want \CMYK\ support, we will use the %D following implementation: % \def\setMPcolor % {\edef\lastMPrvalue{\gMPa1}% % \edef\lastMPgvalue{\gMPa2}% % \edef\lastMPbvalue{\gMPa3}} % % speed up (hardly called, so no let is needed) \def\setMPcolor {\edef\lastMPrvalue{\csname\@@MP01\endcsname}% \edef\lastMPgvalue{\csname\@@MP02\endcsname}% \edef\lastMPbvalue{\csname\@@MP03\endcsname}} \def\zeroMPrgbvalue{0.0} \def\resetMPcolor {\let\lastMPrvalue\zeroMPrgbvalue \let\lastMPgvalue\zeroMPrgbvalue \let\lastMPbvalue\zeroMPrgbvalue} \resetMPcolor \def\@@MPSK{@MPSK@} \def\@@MPSP{@MPSP@} \def\interceptMPcmykcolor % todo : \ifMPcmykcolors {\ifcase\MPrgbnumber\lastMPgvalue % cannot happen \or % 1 == cmyk color spec \ifMPcmykcolors \dointerceptMPcmykcolor \fi \or % 2 == spot color \ifMPspotcolors \dointerceptMPspotcolor \fi \or % 3 == rgb transparency \invokeMPtransparencyspecial \or % 4 == cmyk transparency \ifMPcmykcolors \invokeMPtransparencyspecial \fi \or % 5 == spot transparency \ifMPspotcolors \invokeMPtransparencyspecial \fi \else % \writestatus{MPtoPDF}{unknown direct special}% \fi} % ifcsname \def\dointerceptMPcmykcolor {\revokeMPtransparencyspecial \@EA\ifx\csname\@@MPSK\number\MPrgbnumber\lastMPbvalue\endcsname\relax\else \@EA\@EA\@EA\setMPcmyk\csname\@@MPSK\number\MPrgbnumber\lastMPbvalue\endcsname \normalhandleMPcmykcolor \fi} \def\dointerceptMPspotcolor {\revokeMPtransparencyspecial \@EA\ifx\csname\@@MPSP\number\MPrgbnumber\lastMPbvalue\endcsname\relax\else \@EA\@EA\@EA\setMPspot\csname\@@MPSP\number\MPrgbnumber\lastMPbvalue\endcsname \normalhandleMPspotcolor \fi} \def\handleMPrgbcolor {\resetMPcolor \ifcase\MPspecialversion \normalhandleMPrgbcolor \else \setMPcolor \ifnum\MPrgbnumber\lastMPrvalue=\MPspecialsignal\relax \interceptMPcmykcolor \else \revokeMPtransparencyspecial \normalhandleMPrgbcolor \fi \fi} \def\handleMPgraycolor {\resetMPcolor \ifcase\MPspecialversion \else \revokeMPtransparencyspecial \fi \normalhandleMPgraycolor} \def\handleMPcmykcolor {\resetMPcolor \ifcase\MPspecialversion \else \revokeMPtransparencyspecial \fi \normalhandleMPcmykcolor} %D Specials are define and recalled using: \def\MPspecial {MP special \gMPs\nofMParguments} \def\defineMPspecial#1#2% {\setvalue{MP special #1}{#2}} %D The path processing macro is slightly extended. \newtoks \invokeMPspecials \def\finishMPpath {\PDFcode {\ifcase\finiMPpath W n\or S\or f\or B\else W n\fi \extraMPpathcode}} \def\processMPpath {\checkMPpath % ! \ifcase\nofMPsegments\else \let\extraMPpathcode\empty \ifcase\MPspecialversion\else \ifnum\MPrgbnumber\lastMPrvalue=\MPspecialsignal \ifnum\MPrgbnumber\lastMPgvalue>10 % really needed \scratchcounter\MPrgbnumber\lastMPbvalue \edef\currentMPspecial{\the\scratchcounter}% \let\previousMPcolorspec\currentMPcolorspec \edef\currentMPcolorspec{\lastMPrvalue\lastMPgvalue\lastMPbvalue}% \ifx\previousMPcolorspec\currentMPcolorspec \else \revokeMPtransparencyspecial \fi \ifnum\finiMPpath=2 % to outer level \the\invokeMPspecials \fi \fi \fi \fi \flushMPpath \closeMPpath \finishMPpath \fi \let\handleMPsequence\dohandleMPsequence \resetMPstack \nofMPsegments0 \handleMPsequence} %D Shading is an example of a more advanced graphic feature, %D but users will seldom encounter those complications. Here %D we only show a few simple examples, but many other %D alternatives are possible by setting up the functions built %D in \PDF\ in the appropriate way. %D %D Shading has to do with interpolation between two or more %D points or user supplied ranges. In \PDF, the specifications %D of a shade has to be encapsulated in objects and passed on %D as resources. This is a \PDF\ level 1.3. feature. One can %D simulate three dimensional shades as well and define simple %D functions using a limited set of \POSTSCRIPT\ primitives. %D Given the power of \METAPOST\ and these \PDF\ features, we %D can achieve superb graphic effects. %D %D Since everything is hidden in \TEX\ and \METAPOST\ graphics, %D we can stick to high level \CONTEXT\ command, as shown in %D the following exmples. %D %D \startbuffer %D \startuniqueMPgraphic{CircularShade} %D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ; %D circular_shade(p,0,.2red,.9red) ; %D \stopuniqueMPgraphic %D %D \startuniqueMPgraphic{LinearShade} %D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ; %D linear_shade(p,0,.2blue,.9blue) ; %D \stopuniqueMPgraphic %D %D \startuniqueMPgraphic{DuotoneShade} %D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ; %D linear_shade(p,2,.5green,.5red) ; %D \stopuniqueMPgraphic %D \stopbuffer %D %D \typebuffer %D %D \getbuffer %D %D These graphics can be hooked into the overlay mechanism, %D which is available in many commands. %D %D \startbuffer %D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}] %D \defineoverlay[demo 2][\uniqueMPgraphic {LinearShade}] %D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}] %D \stopbuffer %D %D \typebuffer %D %D \getbuffer %D %D These backgrounds can for instance be applied to \type %D {\framed}: %D %D \startbuffer %D \setupframed[width=3cm,height=2cm,frame=off] %D \startcombination[3*1] %D {\framed[background=demo 1]{\bfd \white Demo 1}} {} %D {\framed[background=demo 2]{\bfd \white Demo 2}} {} %D {\framed[background=demo 3]{\bfd \white Demo 3}} {} %D \stopcombination %D \stopbuffer %D %D \typebuffer %D %D \startlinecorrection %D \getbuffer %D \stoplinecorrection %D %D There are a few more alternatives, determined by the second %D parameter passed to \type {circular_shade} and alike. %D %D \def\SomeShade#1#2#3#4#5% %D {\startuniqueMPgraphic{Shade-#1} %D width := \overlaywidth ; %D height := \overlayheight ; %D path p ; p := unitsquare xscaled width yscaled height ; %D #2_shade(p,#3,#4,#5) ; %D \stopuniqueMPgraphic %D \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]% %D \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}} %D %D \startlinecorrection %D \startcombination[5*1] %D {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0} %D {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1} %D {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2} %D {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3} %D {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4} %D \stopcombination %D \stoplinecorrection %D %D \blank %D %D \startlinecorrection %D \startcombination[5*1] %D {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0} %D {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1} %D {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2} %D {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3} %D {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4} %D \stopcombination %D \stoplinecorrection %D %D \blank %D %D \startlinecorrection %D \startcombination[4*1] %D {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0} %D {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1} %D {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2} %D {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3} %D \stopcombination %D \stoplinecorrection %D %D These macros closely cooperate with the \METAPOST\ module %D \type {mp-spec.mp}, which is part of the \CONTEXT\ %D distribution. %D %D The low level (\PDF) implementation is based on the \TEX\ %D based \METAPOST\ to \PDF\ converter. Shading is supported %D by overloading the \type {fill} operator as implemented %D earlier. In \PDF\ type~2 and~3 shading functions are %D specified in terms of: %D %D \starttabulate[|Tl|l|] %D \NC /Domain \NC sort of meeting range \NC \NR %D \NC /C0 \NC inner shade \NC \NR %D \NC /C1 \NC outer shade \NC \NR %D \NC /N \NC smaller values, bigger inner circles \NC \NR %D \stoptabulate \newcount\currentPDFshade % 0 % global (document wide) counter \let\currentMPshades\empty \def\startMPshading#1% {\edef\currentMPspecial{\gMPs{#1}}} \def\stopMPshading {\global\advance\currentPDFshade \plusone \setxvalue{obj:Sh:\currentMPspecial}% {/Sh\the\currentPDFshade\space\the\pdflastobj\space0 R }% \setxvalue{mps:Sh:\currentMPspecial}% {\the\currentPDFshade}} \appendtoks \global\let\currentMPshades\empty \to \MPstartresources \appendtoks \ifx\currentMPshades\empty \else \xdef\currentPDFresources{\currentPDFresources /Shading <<\currentMPshades>>}% \fi \to \MPstopresources \def\invokeMPshadespecial {\ifundefined{mps:Sh:\currentMPspecial}\else \edef\currentMPshade{\getvalue{obj:Sh:\currentMPspecial}}% \doifinstringelse\currentMPshade\currentMPshades \donothing {\xdef\currentMPshades{\currentMPshades\currentMPshade}}% \def\extraMPpathcode{/Sh\getvalue{mps:Sh:\currentMPspecial} sh Q}% \chardef\finiMPpath\zerocount \PDFcode{q /Pattern cs}% \fi} \appendtoks \invokeMPshadespecial \to \invokeMPspecials %D We need to convert the \CMYK\ specials into colors, because %D we have to do it twice, we define a macro. % \def\checkMPshadingcolor#1#2#3#4#5% % {\edef\tempMPrvalue{\csname\@@MP0#1\endcsname}% % \edef\tempMPgvalue{\csname\@@MP0#2\endcsname}% % \edef\tempMPbvalue{\csname\@@MP0#3\endcsname}% % \edef#5% % {\ifx\tempMPrvalue\tempMPgvalue % \ifx\tempMPrvalue\tempMPbvalue % \ifx\tempMPgvalue\tempMPbvalue % \tempMPbvalue % \fi % \fi % \fi}% % \edef#4% todo : spotcolors % {\ifnum\MPrgbnumber\tempMPrvalue=\MPspecialsignal\space % \ifMPcmykcolors\getvalue{\@@MPSK\number\MPrgbnumber\tempMPbvalue}\fi % \fi}} \def\checkMPshadingcolor#1#2#3#4#5% {\edef\tempMPrvalue{\csname\@@MP0#1\endcsname}% \edef\tempMPgvalue{\csname\@@MP0#2\endcsname}% \edef\tempMPbvalue{\csname\@@MP0#3\endcsname}% \global\let\MPresolvedspace\MPgrayspace \global\let\MPresolvedcolor\!!zerocount \ifnum\MPrgbnumber\tempMPrvalue=\MPspecialsignal\relax \ifcase\MPrgbnumber\tempMPgvalue \or % 1 = cmyk \ifMPcmykcolors \expanded{\resolveMPcmykcolor\getvalue{\@@MPSK\number\MPrgbnumber\tempMPbvalue}}\end \fi \or % 2 = spot \ifMPspotcolors \expanded{\resolveMPspotcolor\getvalue{\@@MPSP\number\MPrgbnumber\tempMPbvalue}}\end \fi \or % 3 = rgb transparency % to do \or % 4 == cmyk transparency % \ifMPcmykcolors % to do % \fi \or % 5 == spot transparency % \ifMPspotcolors % to do % \fi \fi \else \ifx\tempMPrvalue\tempMPgvalue \ifx\tempMPrvalue\tempMPbvalue \expanded{\resolveMPgraycolor\tempMPbvalue}\end \else \expanded{\resolveMPrgbcolor\tempMPrvalue\space\tempMPgvalue\space\tempMPbvalue}\end \fi \else \expanded{\resolveMPrgbcolor\tempMPrvalue\space\tempMPgvalue\space\tempMPbvalue}\end \fi \fi \let#4\MPresolvedcolor \let#5\MPresolvedspace} %D We also need to make sure that we have two \RGB\ or %D \CMYK colors, since we have to set the colorspace. \def\setMPshadingcolors#1#2#3#4#5#6% color space {\checkMPshadingcolor{#1}{#2}{#3}\MPshadeAc\MPshadeAs \checkMPshadingcolor{#4}{#5}{#6}\MPshadeBc\MPshadeBs \ifx\MPshadeAs\MPshadeBs \let\MPshadeA\MPshadeAc \let\MPshadeB\MPshadeBc \let\MPshadeC\MPshadeAs \else\ifx\MPshadeAs\MPgrayspace \ifx\MPshadeBs\MPrgbspace \edef\MPshadeA{\MPshadeAc\space\MPshadeAc\space\MPshadeAc}% \else \negatecolorcomponent\MPshadeAc \edef\MPshadeA{0 0 0 \MPshadeAc}% \fi \let\MPshadeB\MPshadeBc \let\MPshadeC\MPshadeBs \else\ifx\MPshadeBs\MPgrayspace \let\MPshadeA\MPshadeAc \ifx\MPshadeAs\MPrgbspace \edef\MPshadeB{\MPshadeBc\space\MPshadeBc\space\MPshadeBc}% \else \negatecolorcomponent\MPshadeBc \edef\MPshadeB{0 0 0 \MPshadeBc}% \fi \let\MPshadeC\MPshadeAs \else % different color spaces \def\MPshadeA{1}% \def\MPshadeB{1}% \let\MPshadeC\MPgrayspace \fi\fi\fi} \let\MPshadeA\MPcmykWhite \let\MPshadeB\MPcmykBlack \let\MPshadeC\MPgrayspace %D The reason why this macro is a bit complicates is that we %D handle black and white situations (otherwise we would have %D to use \CMYK\ b/w in case of a \CMYK\ shade). %D Here are the special handlers: \defineMPspecial{30} {\startMPshading{14}% type 2 \setMPshadingcolors{4}{5}{6}{9}{10}{11}% \immediate\pdfobj {<>}% \immediate\pdfobj {<>}% \stopMPshading} \defineMPspecial{31} {\startMPshading{16}% type 3 \setMPshadingcolors{4}{5}{6}{10}{11}{12}% \immediate\pdfobj {<>}% \immediate\pdfobj {<>}% \stopMPshading} %D Figure inclusion is kind of strange to \METAPOST, but when %D Santiago Muelas started discussing this with me, I was able %D to cook up a solution using specials. \def\invokeMPfigurespecial% {\getvalue{mps:gr:\currentMPspecial}} % or \relax \appendtoks \invokeMPfigurespecial \to \invokeMPspecials \defineMPspecial{10} {\setxvalue{mps:gr:\gMPs8}% {\noexpand\handleMPfigurespecial {\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}% \noexpand\setxvalue{mps:gr:\gMPs8}{}}} % \def\handleMPfigurespecial#1#2#3#4#5#6#7% % {\vbox to 0pt % {\vss % \hbox to 0pt % {\pdfliteral{q #1 #2 #3 #4 #5 #6 cm}% % \pdfimage width 1bp height 1bp {#7}% maybe 10 is better % \pdfliteral{Q}% % \hss}}} % % better, since xform reuse \def\handleMPfigurespecial#1#2#3#4#5#6#7% todo : combine with ext fig {\vbox to \zeropoint {\vss \hbox to \zeropoint {\ifcase\pdfoutput\or % will be hooked into the special driver \doiffileelse{#7} {\doifundefinedelse{mps:x:#7} {\immediate\pdfximage\!!width\onebasepoint\!!height\onebasepoint{#7}% \setxvalue{mps:x:#7}{\pdfrefximage\the\pdflastximage}}% {\message{[reusing figure #7]}}% \PDFcode{q #1 #2 #3 #4 #5 #6 cm}% \rlap{\getvalue{mps:x:#7}}% \PDFcode{Q}} {\message{[unknown figure #7]}}% \fi \hss}}} %D An example of using both special features is the %D following. %D %D \starttyping %D \startMPpage %D externalfigure "hakker1b.png" scaled 22cm rotated 10 shifted (-2cm,0cm); %D externalfigure "hakker1b.png" scaled 10cm rotated -10 ; %D externalfigure "hakker1b.png" scaled 7cm rotated 45 shifted (8cm,12cm) ; %D path p ; p := unitcircle xscaled 15cm yscaled 20cm; %D path q ; q := p rotatedaround(center p,90) ; %D path r ; r := buildcycle(p,q) ; clip currentpicture to r ; %D path s ; s := boundingbox currentpicture enlarged 5mm ; %D picture c ; c := currentpicture ; currentpicture := nullpicture ; %D circular_shade(s,0,.2red,.9red) ; %D addto currentpicture also c ; %D \stopMPpage %D \stoptyping %D This is some experimental hyperlink driver that I wrote %D for Mark Wicks. \defineMPspecial{20} {\setxvalue{mps:hl:\gMPs6}% {\noexpand\handleMPhyperlink {\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}% \noexpand\setxvalue{mps:hl:\gMPs6}{}}} \def\handleMPhyperlink#1#2#3#4#5% {%\ifcase\pdfoutput\or \setbox\scratchbox\hbox {\setbox\scratchbox\null \scratchdimen#1\onebasepoint\scratchdimen-\scratchdimen \advance\scratchdimen#3\onebasepoint \wd\scratchbox\scratchdimen \scratchdimen#2\onebasepoint\scratchdimen-\scratchdimen \advance\scratchdimen#4\onebasepoint \ht\scratchbox\scratchdimen \incolorfalse \gotobox{\box\scratchbox}[#5]}% \setbox\scratchbox\hbox {\scratchdimen\MPxoffset\onebasepoint\advance\scratchdimen#1\onebasepoint \hskip\scratchdimen \scratchdimen\MPyoffset\onebasepoint\advance\scratchdimen#2\onebasepoint \raise\scratchdimen\box\scratchbox}% \smashbox\scratchbox \box\scratchbox }%\fi} \def\invokeMPhyperlinkspecial% {\getvalue{mps:hl:\currentMPspecial}} % or \relax \appendtoks \invokeMPhyperlinkspecial \to \invokeMPspecials %D Special number~1 is dedicated to \CMYK\ support. If you %D want to know why: look at this: %D %D \startbuffer[mp] %D fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ; %D \stopbuffer %D %D \startbuffer[cmyk] %D \startcombination[4*1] %D {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3} %D {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15} %D {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8} %D {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1} %D \stopcombination %D \stopbuffer %D %D \placefigure %D {\CMYK\ support disabled, %D conversion to \RGB.} %D {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]} %D %D \placefigure %D {\CMYK\ support enabled, %D no support in \METAPOST.} %D {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]} %D %D \placefigure %D {\CMYK\ support enabled, %D no conversion to \RGB, %D support in \METAPOST} %D {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]} \defineMPspecial{1} {\ifMPcmykcolors \setxvalue{\@@MPSK\gMPs1}{\gMPs2 \gMPs3 \gMPs4 \gMPs5 }% \fi} \def\setMPcmyk#1 #2 #3 #4 % {\setvalue{\@@MP01}{#1}% \setvalue{\@@MP02}{#2}% \setvalue{\@@MP03}{#3}% \setvalue{\@@MP04}{#4}} %\defineMPspecial{2} % {\ifMPspotcolors % \setxvalue{\@@MPSP\gMPs1}{\gMPs2 \gMPs3 }% % \fi} % \defineMPspecial{2} % {\ifMPspotcolors % \setxvalue{\@@MPSP\gMPs1}{\gMPs2 \gMPs3 }% % \checkMPspot{\gMPs2}{\gMPs3}% % \fi} % % \def\setMPspot#1 #2 % % {\setvalue{\@@MP01}{#1}% % \setvalue{\@@MP02}{#2}} % % \def\checkMPspot#1#2% % {\expanded{\resolveMPspotcolor#1 #2}\end % \ifx\MPspotspace\MPresolvedspace % \edef\MPspotspacespec{/\MPspotspace\space}% % \doifinstringelse\MPspotspacespec\currentMPcolorspaces % \donothing\registerMPcolorspace % \fi} \defineMPspecial{2} {\ifMPspotcolors \setxvalue{\@@MPSP\gMPs1}{\gMPs2 \gMPs3 \gMPs4 \gMPs5 }% space is essential \checkMPspot{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}% \fi} \def\setMPspot#1 #2 #3 #4 % {\setvalue{\@@MP01}{#1}% \setvalue{\@@MP02}{#2}% \setvalue{\@@MP03}{#3}% \setvalue{\@@MP04}{#4}} \def\checkMPspot#1#2#3#4% {\expanded{\resolveMPspotcolor#1 #2 #3 #4}\end \ifx\MPspotspace\MPresolvedspace \edef\MPspotspacespec{/\MPspotspace\space}% \doifinstringelse\MPspotspacespec\currentMPcolorspaces \donothing\registerMPcolorspace \fi} %D This special (number 50) passes positions to a tex file. %D This method uses a two||pass approach an (mis|)|used the %D context positioning macros. In \type {core-pos} we will %D implement the low level submacro needed. %D %D \startbuffer %D \definelayer[test] %D %D \setlayer %D [test] %D [x=\MPx{somepos-1},y=\MPy{somepos-1}] %D {Whatever we want here!} %D %D \setlayer %D [test] %D [x=\MPx{somepos-2},y=\MPy{somepos-2}] %D {Whatever we need there!} %D %D \startuseMPgraphic{oeps} %D draw fullcircle scaled 6cm withcolor red ; %D register ("somepos-1",1cm,2cm,center currentpicture) ; %D register ("somepos-2",4cm,3cm,(-1cm,-2cm)) ; %D \stopuseMPgraphic %D %D \framed[background=test,offset=overlay]{\useMPgraphic{oeps}} %D \stopbuffer %D %D \typebuffer %D %D Here the width and height are not realy used, but one can %D imagine situations where tex has to work with values %D calculated by \METAPOST. %D %D \startlinecorrection %D \getbuffer %D \stoplinecorrection %D %D Later we will implement a more convenient macro: %D %D \starttyping %D \setMPlayer [test] [somepos-1] {Whatever we want here!} %D \setMPlayer [test] [somepos-2] {Whatever we need there!} %D \stoptyping \ifx\dosavepositionwhd\undefined \let\dosavepositionwhd\gobblesevenarguments \fi \defineMPspecial{50} % x y width height label {\bgroup \scratchdimen\MPllx\onebasepoint\scratchdimen-\scratchdimen % \scratchdimen-\MPllx\onebasepoint % moet ook werken \advance\scratchdimen\gMPs1\onebasepoint \edef\x{\number\scratchdimen}% \scratchdimen\gMPs2\onebasepoint \scratchdimen-\scratchdimen \advance\scratchdimen\MPury\onebasepoint \edef\y{\number\scratchdimen}% \scratchdimen\gMPs3\onebasepoint \edef\w{\number\scratchdimen}% \scratchdimen\gMPs4\onebasepoint \edef\h{\number\scratchdimen}% \dosavepositionwhd{\gMPs5}0\x\y\w\h0% \egroup} %D Transparency support used specials 60 (rgb) and 61 %D (cmyk). %D %D \startbuffer %D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0); %D %D fill p rotated 90 withcolor transparent(1,.5,yellow) ; %D fill p rotated 210 withcolor transparent(1,.5,green) ; %D fill p rotated 330 withcolor transparent(1,.5,blue) ; %D \stopbuffer %D %D \typebuffer %D %D \startlinecorrection \processMPbuffer \stoplinecorrection %D %D One can also communicate colors between \CONTEXT\ and %D \METAPOST: %D %D \startbuffer %D \definecolor[tcyan] [c=1,k=.2,t=.5] %D \definecolor[tmagenta][m=1,k=.2,t=.5] %D \definecolor[tyellow] [y=1,k=.2,t=.5] %D \stopbuffer %D %D \typebuffer \getbuffer %D %D \startbuffer %D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0); %D %D fill p rotated 90 withcolor \MPcolor{tcyan} ; %D fill p rotated 210 withcolor \MPcolor{tmagenta} ; %D fill p rotated 330 withcolor \MPcolor{tyellow} ; %D \stopbuffer %D %D \startlinecorrection \processMPbuffer \stoplinecorrection %D %D We save all the three components needed in one macro, %D just to save hash space. \def\@@MPST{@MPST@} \def\assignMPStransparency#1#2#3% {\edef\PDFtransparencyidentifier{#1}% \edef\PDFtransparencyreference {#2}% \edef\PDFtransparencycolorspecs{#3}} % \def\PDFtransparencyspec % {\ifx\MPresolvedspace\MPgrayspace % \MPresolvedcolor\space g \MPresolvedcolor\space G% % \else\ifx\MPresolvedspace\MPrgbspace % \MPresolvedcolor\space rg \MPresolvedcolor\space RG% % \else\ifx\MPresolvedspace\MPcmykspace % \MPresolvedcolor\space k \MPresolvedcolor\space K% % \else\ifx\MPresolvedspace\empty\else % /\MPresolvedspace\space cs \MPresolvedcolor\space sc % /\MPresolvedspace\space CS \MPresolvedcolor\space SC% % \fi\fi\fi\fi} \def\PDFtransparencyspec % todo {\ifx\MPresolvedspace\MPgrayspace \MPresolvedcolor\space g \MPresolvedcolor\space G% \else\ifx\MPresolvedspace\MPrgbspace \MPresolvedcolor\space rg \MPresolvedcolor\space RG% \else\ifx\MPresolvedspace\MPcmykspace \MPresolvedcolor\space k \MPresolvedcolor\space K% \else\ifx\MPresolvedspace\empty\else /\MPresolvedspace\space cs /\MPresolvedspace\space CS \PDFgetspotcolorspec\MPresolvedcolor \fi\fi\fi\fi} \defineMPspecial{3} % rgb {\edef\currentMPspecial{\gMPs6}% \presetPDFtransparency{\gMPs1}{\gMPs2}% \expanded{\resolveMPrgbcolor\gMPs3 \gMPs4 \gMPs5}\end \setevalue{\@@MPST\currentMPspecial}% was \setxvalue, bug ! {\noexpand\assignMPStransparency {\PDFtransparencyidentifier}% {\PDFtransparencyreference}% {\PDFtransparencyspec}}} \defineMPspecial{4} % cmyk {\edef\currentMPspecial{\gMPs7}% \presetPDFtransparency{\gMPs1}{\gMPs2}% \expanded{\resolveMPcmykcolor\gMPs3 \gMPs4 \gMPs5 \gMPs6}\end \setevalue{\@@MPST\currentMPspecial}% was \setxvalue, bug ! {\noexpand\assignMPStransparency {\PDFtransparencyidentifier}% {\PDFtransparencyreference}% {\PDFtransparencyspec}}} % \defineMPspecial{5} % spot % {\edef\currentMPspecial{\gMPs5}% % \presetPDFtransparency{\gMPs1}{\gMPs2}% % \checkMPspot{\gMPs3}{\gMPs4}% % \setevalue{\@@MPST\currentMPspecial}% was \setxvalue, bug ! % {\noexpand\assignMPStransparency % {\PDFtransparencyidentifier}% % {\PDFtransparencyreference}% % {\PDFtransparencyspec}}} \defineMPspecial{5} % spot {\edef\currentMPspecial{\gMPs7}% \presetPDFtransparency{\gMPs1}{\gMPs2}% \checkMPspot{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}% \setevalue{\@@MPST\currentMPspecial}% was \setxvalue, bug ! {\noexpand\assignMPStransparency {\PDFtransparencyidentifier}% {\PDFtransparencyreference}% {\PDFtransparencyspec}}} % beware: for the moment only supported in pdftex; needs a cleanup! \def\registerMPcolorspace {\doifobjectreferencefoundelse{PDFCS}\MPspotspace {\doPDFgetobjectreference{PDFCS}\MPspotspace\PDFobjectreference \xdef\currentMPcolorspaces {\currentMPcolorspaces\MPspotspacespec\PDFobjectreference\space}} \donothing} %D We need to add resource specifications! \appendtoks \global\let\currentMPcolorspaces\empty \to \MPstartresources \appendtoks \ifx\currentMPcolorspaces\empty \else \xdef\currentPDFresources{\currentPDFresources /ColorSpace <<\currentMPcolorspaces>>}% \fi \to \MPstopresources %D For efficiency reasons, we fall back on the allocation %D mechanisms already present. For use within \MPTOPDF, we %D provide a fall back routine. \let\currentMPtransparencies\empty % \def\invokeMPtransparencyspecial % {\doifdefined{\@@MPST\currentMPspecial} % {\getvalue{\@@MPST\currentMPspecial}% % \doifinstringelse % {\PDFtransparencyidentifier}{\currentMPtransparencies} % {} % {\xdef\currentMPtransparencies % {\currentMPtransparencies % \PDFtransparencyidentifier\space % \PDFtransparencyreference\space}}% % \def\extraMPpathcode{ Q}% % \PDFcode{q % \PDFtransparencycolorspecs\space % \PDFtransparencyidentifier\space gs}}} % this one triggers a new graphic state \def\invokeMPtransparencyspecial {\scratchcounter\MPrgbnumber\lastMPbvalue \edef\currentMPspecial{\the\scratchcounter}% \ifundefined{\@@MPST\currentMPspecial}\else \getvalue{\@@MPST\currentMPspecial}% \doifinstringelse\PDFtransparencyidentifier\currentMPtransparencies \donothing\registerMPtransparencyresource % slow \PDFcode {\PDFtransparencycolorspecs\space \PDFtransparencyidentifier\space gs}% % potential optimization % \setevalue{\@@MPST\currentMPspecial}% % {\PDFcode % {\PDFtransparencycolorspecs\space % \PDFtransparencyidentifier\space gs}}% % \getvalue{\@@MPST\currentMPspecial}% \let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial \fi} % this one does a reset \let\revokeMPtransparencyspecial\relax \appendtoks \revokeMPtransparencyspecial \to \MPstopresources \def\dorevokeMPtransparencyspecial % only called if state is set {\ifx\PDFtransparencyresetidentifier\empty\else \doifinstringelse\PDFtransparencyresetidentifier\currentMPtransparencies \donothing\registerMPtransparencyresetresource \PDFcode{\PDFtransparencyresetidentifier\space gs}% % potential optimization % \def\dorevokeMPtransparencyspecial % {\PDFcode % {\PDFtransparencycolorspecs\space % \PDFtransparencyidentifier\space gs}}% \let\dorevokeMPtransparencyspecial\dodorevokeMPtransparencyspecial \let\revokeMPtransparencyspecial\relax % invoke sets it \fi} % and this one a simplified reset % \def\dodorevokeMPtransparencyspecial % used after first invocation % {\getvalue{\@@MPST0}% % \PDFcode{\PDFtransparencyidentifier\space gs}} \def\dodorevokeMPtransparencyspecial % used after first invocation {\PDFcode{\PDFtransparencyresetidentifier\space gs}% \let\revokeMPtransparencyspecial\relax} % invoke sets it % add a resource entry \def\registerMPtransparencyresource {\xdef\currentMPtransparencies {\currentMPtransparencies \PDFtransparencyidentifier\space \PDFtransparencyreference\space}} \def\registerMPtransparencyresetresource {\xdef\currentMPtransparencies {\currentMPtransparencies \PDFtransparencyresetidentifier\space \PDFtransparencyresetreference\space}} \appendtoks \invokeMPtransparencyspecial \to \invokeMPspecials \ifCONTEXT \else \def\@@MPSTN{@MPSTN@} \def\@@MPSTO{@MPSTO@} \newcount\PDFcurrenttransparency \let\PDFtransparencyresetidentifier\empty \let\PDFtransparencyresetreference \empty \let\PDFtransparencyidentifier\empty \let\PDFtransparencyreference \empty \def\initializePDFtransparency {\global\let\initializePDFtransparency\relax \presetPDFtransparency{1}{1}% \xdef\PDFtransparencyresetidentifier{/Tr0}% \xdef\PDFtransparencyresetreference{\the\pdflastobj\space 0 R}} \def\presetPDFtransparency#1#2% {\initializePDFtransparency \@EA\ifx\csname\@@MPSTO#1:#2\endcsname\relax \global\advance\PDFcurrenttransparency \plusone \immediate\pdfobj{\PDFtransparencydictionary{#1}{#2}{}}% \setxvalue{\@@MPSTN#1:#2}{\the\PDFcurrenttransparency}% \setxvalue{\@@MPSTO#1:#2}{\the\pdflastobj}% \fi \edef\PDFtransparencyidentifier{/Tr\getvalue{\@@MPSTN#1:#2}}% \edef\PDFtransparencyreference{\getvalue{\@@MPSTO#1:#2} 0 R}} \def\PDFtransparencydictionary#1#2#3% type fraction extras {<>} \fi \appendtoks \global\let\currentMPtransparencies\empty \to \MPstartresources \appendtoks \ifx\currentMPtransparencies\empty \else \xdef\currentPDFresources{\currentPDFresources /ExtGState <<\currentMPtransparencies>>}% \fi \to \MPstopresources %D In all cases, we need to keep track of the resources %D used. %D A few auxiliary macros: \def\MPgrayspace{DeviceGray} \def\MPrgbspace {DeviceRGB} \def\MPcmykspace{DeviceCMYK} \let\MPspotspace\MPgrayspace \def\MPcmykBlack{0 0 0 0} \def\MPcmykWhite{0 0 0 1} \ifCONTEXT \def\startMPcolorresolve {\bgroup \def\dostartgraycolormode##1% {\global\let\MPresolvedspace\MPgrayspace \xdef\MPresolvedcolor{##1}}% \def\dostartrgbcolormode ##1##2##3% {\global\let\MPresolvedspace\MPrgbspace \xdef\MPresolvedcolor{##1 ##2 ##3}}% \def\dostartcmykcolormode##1##2##3##4% {\global\let\MPresolvedspace\MPcmykspace \xdef\MPresolvedcolor{##1 ##2 ##3 ##4}}% \def\dostartspotcolormode##1##2% {\global\let\MPspotspace\empty \xdef\MPresolvedspace{##1}% \xdef\MPresolvedcolor{##2}% \global\let\MPspotspace\MPresolvedspace}% signal \dostartgraycolormode\!!zerocount} % kind of hackery initialization \let\stopMPcolorresolve\egroup \def\resolveMPrgbcolor#1 #2 #3\end {\startMPcolorresolve \execcolorR#1:#2:#3:0:0\od \stopMPcolorresolve} \def\resolveMPcmykcolor#1 #2 #3 #4\end {\startMPcolorresolve \execcolorC#1:#2:#3:#4:0:0\od \stopMPcolorresolve} \def\resolveMPgraycolor#1\end {\startMPcolorresolve \execcolorS#1:0:0\od \stopMPcolorresolve} % \def\resolveMPspotcolor#1 #2\end % {\startMPcolorresolve % \execcolorP#1:#2:0:0\od % \stopMPcolorresolve} \def\resolveMPspotcolor#1 #2 #3 #4\end {\startMPcolorresolve \ifnum#2>\plusone \checkmultitonecolor{#1}% \fi \execcolorP#1:#2:#3:#4:0:0\od \stopMPcolorresolve} \else \def\resolveMPspotcolor#1 #2\end {\global\let\MPresolvedspace\MPgrayspace \xdef\MPresolvedcolor{0}} \def\resolveMPrgbcolor#1 #2 #3\end {\global\let\MPresolvedspace\MPrgbspace \xdef\MPresolvedcolor{#1 #2 #3}} \def\resolveMPcmykcolor#1 #2 #3 #4\end {\global\let\MPresolvedspace\MPcmykspace \xdef\MPresolvedcolor{#1 #2 #3 #4}} \def\resolveMPgraycolor#1\end {\global\let\MPresolvedspace\MPgrayspace \xdef\MPresolvedcolor{#1}} % should be inverted \fi \protect \endinput