%D \module %D [ file=meta-pdf, %D version=2006.06.07, %D title=\METAPOST\ Graphics, %D subtitle=Conversion to \PDF, %D author=Hans Hagen \& others (see text), %D date=\currentdate, %D copyright=\PRAGMA] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \registerctxluafile{meta-pdf}{1.003} %D We will clean up the color mess later. \writestatus{loading}{MetaPost Graphics / MPS to PDF} \unprotect %D \macros %D {convertMPtoPDF} %D %D The next set of macros implements \METAPOST\ to \PDF\ %D conversion. The traditional method is in the MkII file. %D %D The main conversion command is: %D %D \starttyping %D \convertMPtoPDF {filename} {x scale} {y scale} %D \stoptyping %D %D The dimensions are derived from the bounding box. So we %D only have to say: %D %D \starttyping %D \convertMPtoPDF{mp-pra-1.eps}{1}{1} %D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5} %D \stoptyping \def\PDFMPformoffset {\ifdefined\objectoffset\objectoffset\else\zeropoint\fi} %D The main macro: \def\convertMPtoPDF#1#2#3% scaling no longer supported at this level (so #2 & #3 ignored) {\vbox\bgroup \message{[MP to PDF]}% \xdef\MPfilename{#1}% \glet\MPwidth \!!zeropoint \glet\MPheight\!!zeropoint \glet\MPllx \!!zerocount \glet\MPlly \!!zerocount \glet\MPurx \!!zerocount \glet\MPury \!!zerocount \forgetall \offinterlineskip \setbox\scratchbox\vbox\bgroup \ctxlua{mptopdf.convertmpstopdf("\MPfilename")}\removeunwantedspaces \egroup \setbox\scratchbox\hbox\bgroup \hskip-\MPllx\onebasepoint \raise-\MPlly\onebasepoint \box\scratchbox \egroup \setbox\scratchbox\vbox to \MPheight\bgroup \vfill \hsize\MPwidth \smashbox\scratchbox \box\scratchbox \egroup \wd\scratchbox\MPwidth \ht\scratchbox\MPheight \dopackageMPgraphic\scratchbox \egroup} %D Objects (move all to backend) % \def\dopackageMPgraphic#1% #1 = boxregister % {\scratchdimen\PDFMPformoffset\relax % \ifdim\scratchdimen>\zeropoint % compensate for error % \setbox#1\vbox spread 2\scratchdimen % {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}% % \fi % \setMPPDFobject{#1}% % \ifdim\scratchdimen>\zeropoint % compensate for error % \vbox to \MPheight % {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}% % \else % \getMPPDFobject % \fi} % % \def\setMPPDFobject#1% boxnumber % {\the\pdfbackendeveryxform % \finalizeobjectbox{#1}% % \immediate\pdfxform resources{\pdfcurrentresources}#1% % \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}} % % \let\getMPPDFobject\relax % we don't need to package as each page has all resources anyway \let\dopackageMPgraphic\box %D \macros %D {deleteMPgraphic, %D startMPresources, %D stopMPresources} \ifx\deleteMPgraphic\undefined \def\deleteMPgraphic#1{} \fi \ifx\startMPresources\undefined \let\startMPresources\relax \let\stopMPresources\relax \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 \newconditional\manyMPspecials \settrue\manyMPspecials %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 %D We support specials but assume that the files are somewhat simple %D ones wo we have dropped a few. The reason is that runtime \METAPOST\ %D processing now uses \MPLIB\ so we only need to deal with the %D conversion here. See meta-pdh.mkiv (and older files) for more %D details. Here we just give a few examples. %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]} %D %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 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 \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 \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[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {} %D {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {} %D {\framed[backgroundachtergrond=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 \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 \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 %D %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 \startMPinitializations mp_shade_version := 2 ; \stopMPinitializations %D This is done much cleaner in \MPLIB. % %D A common hook. % % \let\MPfshowcommand\empty % % \def\MPStextext#1#2#3#4#5% if we clean up this plugin model, we can % {\def\MPtextdata{#3}% % delegate the splitter to lua + redesign % \def\MPtextsize{#2}% % \def\lastMPmoveX{#4}% % \def\lastMPmoveY{#5}% % \defconvertedcommand\MPtextdata\MPtextdata % no edef % \splitstring\MPtextdata\at::::\to\MPtexttag\and\MPtextnumber % \executeifdefined{handleMPtext\MPtexttag} % {\setbox\scratchbox\hbox % {\font\temp=#1\space at #2\onebasepoint % \let\c\char % \temp % \MPfshowcommand{#3}}% % \setbox\scratchbox\hbox % {\hskip#4\onebasepoint % \raise#5\onebasepoint % \box\scratchbox}% % \smashbox\scratchbox % \box\scratchbox}} \unexpanded\def\MPStextext#1#2#3#4#5% if we clean up this plugin model, we can {\setbox\scratchbox\hbox {\font\temp=#1\space at #2\onebasepoint \let\c\char \temp #3}% \setbox\scratchbox\hbox {\hskip#4\onebasepoint \raise#5\onebasepoint \box\scratchbox}% \smashbox\scratchbox \box\scratchbox} %D The boundingbox. \def\MPSboundingbox#1#2#3#4% {\xdef\MPllx{#1}\xdef\MPlly{#2}\xdef\MPurx{#3}\xdef\MPury{#4}% \xdef\MPwidth {\the\dimexpr#3\onebasepoint-#1\onebasepoint\relax}% \xdef\MPheight{\the\dimexpr#4\onebasepoint-#2\onebasepoint\relax}} \MPSboundingbox0000 %D Test code: %D %D \startbuffer %D \startMPcode %D fill fullcircle scaled 3cm withcolor red ; %D fill fullcircle scaled 2cm withcolor green ; %D fill fullcircle scaled 1cm withcolor blue ; %D currentpicture := currentpicture shifted (-4cm,0) ; %D fill fullcircle scaled 3cm withcolor cmyk(0,0,1,0) ; %D fill fullcircle scaled 2cm withcolor cmyk(0,1,0,0) ; %D fill fullcircle scaled 1cm withcolor cmyk(0,0,1,0) ; %D currentpicture := currentpicture shifted (-4cm,0) ; %D draw fullcircle scaled 3cm dashed evenly ; %D draw fullcircle scaled 2cm dashed withdots ; %D draw origin withpen pencircle scaled 3mm; %D currentpicture := currentpicture shifted (-4cm,0) ; %D fill fullcircle scaled 2cm shifted (-.5cm,+.5cm) withcolor transparent(1,.5,red); %D fill fullcircle scaled 2cm shifted (-.5cm,-.5cm) withcolor transparent(1,.5,red); %D fill fullcircle scaled 2cm shifted (+.5cm,+.5cm) withcolor transparent(1,.5,green); %D fill fullcircle scaled 2cm shifted (+.5cm,-.5cm) withcolor transparent(1,.5,cmyk(1,0,1,.5)); %D currentpicture := currentpicture shifted (12cm,-4cm) ; %D draw "o e p s" infont defaultfont scaled 2 shifted (-1cm,0) ; %D currentpicture := currentpicture shifted (-4cm,0) ; %D % bug: shift %D draw fullcircle scaled 3cm withpen pencircle yscaled 3mm xscaled 2mm rotated 30 ; %D draw fullcircle scaled 2cm withpen pencircle yscaled 3mm xscaled 2mm rotated 20 withcolor red ; %D filldraw fullcircle scaled 1cm withpen pencircle yscaled 3mm xscaled 2mm rotated 10 withcolor green ; %D currentpicture := currentpicture shifted (-4cm,0) ; %D % shade cannot handle shift %D circular_shade(fullcircle scaled 3cm,0,.2red,.9green) ; %D circular_shade(fullcircle scaled 3cm shifted(+4cm,0),0,cmyk(1,0,0,0),cmyk(0,1,0,0)) ; %D filldraw boundingbox currentpicture enlarged -3cm withpen pencircle scaled 1pt withcolor .5white ; %D \stopMPcode %D \stopbuffer %D %D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection \protect \endinput