diff options
Diffstat (limited to 'tex/context/base/supp-pdf.tex')
-rw-r--r-- | tex/context/base/supp-pdf.tex | 2476 |
1 files changed, 1304 insertions, 1172 deletions
diff --git a/tex/context/base/supp-pdf.tex b/tex/context/base/supp-pdf.tex index caf9d72e4..dae770f16 100644 --- a/tex/context/base/supp-pdf.tex +++ b/tex/context/base/supp-pdf.tex @@ -1,1172 +1,1304 @@ -%D \module
-%D [ file=supp-pdf,
-%D version=1997.05.21,
-%D title=\CONTEXT\ Support Macros,
-%D subtitle=\METAPOST\ to \PDF\ conversion,
-%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. Non||commercial use is
-%C granted.
-
-%D These macros are written as generic as possible. Some
-%D general support macro's are loaded from a small module
-%D especially made for non \CONTEXT\ use. In this module I
-%D use a matrix transformation macro written by Tanmoy
-%D Bhattacharya. Thanks to extensive testing of Sebastian
-%D Ratz I was able to complete this module within reasonable
-%D time. First we take care of non||\CONTEXT\ use:
-
-\ifx \undefined \writestatus \input supp-mis.tex \relax \fi
-
-%D This module handles some \PDF\ conversion and insertions
-%D topics. The macros use the \PDFTEX\ primitive
-%D \type{\pdfliteral}.
-
-\writestatus{loading}{Context Support Macros / PDF}
-
-\unprotect
-
-\ifx\pdfliteral\undefined
- \def\pdfliteral#1{\message{[ignored pdfliteral: #1]}}
-\fi
-
-%D \macros
-%D {convertPDFtoPDF}
-%D {}
-%D
-%D \PDFTEX\ supports verbatim inclusion of \PDF\ code. The
-%D following macro takes care of inserting externally defined
-%D illustrations in \PDF\ format. According to a suggestion
-%D Tanmoy Bhattacharya posted to the \PDFTEX\ mailing list, we
-%D first skip lines until \type{stream} is reached and then
-%D copy lines until \type{endstream} is encountered. This
-%D scheme only works with vectorized graphics in which no
-%D indirect references to objects are used. Bitmaps also don't
-%D work. Interpreting their specifications is beyond the
-%D current implementation.
-%D
-%D \starttypen
-%D \convertPDFtoPDF
-%D {filename}
-%D {x scale} {y scale}
-%D {x offset } {y offset}
-%D {width} {height}
-%D \stoptypen
-%D
-%D When the scales are set to~1, the last last four values
-%D are the same as the bounding box, e.g.
-%D
-%D \starttypen
-%D \convertPDFtoPDF{mp-pra-1.pdf} {1} {1}{-1bp}{-1bp}{398bp}{398bp}
-%D \convertPDFtoPDF{mp-pra-1.pdf}{.5}{.5} {0bp} {0bp}{199bp}{199bp}
-%D \stoptypen
-%D
-%D Keep in mind, that this kind of copying only works for
-%D pure and valid pdf code (without fonts).
-
-%D The scanning and copying is straightforward and quite fast.
-%D To speed up things we use two constants.
-
-\def\@@PDFstream@@ {stream}
-\def\@@PDFendstream@@ {endstream}
-
-%D \macros
-%D {PDFmediaboxprefered}
-%D {}
-%D
-%D If needed, the macros can scan for the mediabox that
-%D specifies the dimensions and offsets of the graphic. When
-%D we say:
-%D
-%D \starttypen
-%D \PDFmediaboxpreferedtrue
-%D \stoptypen
-%D
-%D the mediabox present in the file superseded the user
-%D specified, already scaled and calculated offset and
-%D dimensions. Beware: the user supplied values are not the
-%D bounding box ones!
-
-\newif\ifPDFmediaboxprefered
-
-\def\setPDFboundingbox#1#2#3#4#5#6%
- {\dimen0=#1\dimen0=#5\dimen0
- \ScaledPointsToBigPoints{\number\dimen0}\PDFxoffset
- \dimen0=#3\dimen0=#5\dimen0
- \xdef\PDFwidth{\the\dimen0}%
- \dimen0=#2\dimen0=#6\dimen0
- \ScaledPointsToBigPoints{\number\dimen0}\PDFyoffset
- \dimen0=#4\dimen0=#6\dimen0
- \xdef\PDFheight{\the\dimen0}%
- \global\let\PDFxoffset=\PDFxoffset
- \global\let\PDFyoffset=\PDFyoffset}
-
-\def\setPDFmediabox#1[#2 #3 #4 #5]#6\done%
- {\dimen2=#2bp\dimen2=-\dimen2
- \dimen4=#3bp\dimen4=-\dimen4
- \dimen6=#4bp\advance\dimen6 by \dimen2
- \dimen8=#5bp\advance\dimen8 by \dimen4
- \setPDFboundingbox{\dimen2}{\dimen4}{\dimen6}{\dimen8}\PDFxscale\PDFyscale}
-
-\def\checkPDFmediabox#1/MediaBox#2#3\done%
- {\ifx#2\relax \else
- \message{mediabox}%
- \setPDFmediabox#2#3\done
- \fi}
-
-%D We use the general macro \type{\doprocessfile} and feed this
-%D with a line handling macro that changed it's behavior when
-%D the stream operators are encountered.
-
-\def\handlePDFline%
- {\ifx\@@PDFstream@@\fileline
- \let\doprocessPDFline=\copyPDFobject
- \startPDFtoPDF
- \else\ifPDFmediaboxprefered
- \expandafter\checkPDFmediabox\fileline/MediaBox\relax\done
- \fi\fi}
-
-\def\copyPDFobject%
- {\ifx\@@PDFendstream@@\fileline
- \ifPDFmediaboxprefered
- \let\doprocessPDFline=\findPDFmediabox
- \else
- \let\doprocessPDFline=\relax
- \fi
- \else
- \advance\scratchcounter by 1
- \pdfliteral{\fileline}%
- \fi}
-
-\def\findPDFmediabox%
- {\expandafter\checkPDFmediabox\fileline/MediaBox\relax\done}
-
-%D The main conversion macro wraps the \PDF\ codes in a box
-%D that is output as an object. The graphics are embedded
-%D in~\type{q} and~\type{Q} and are scaled and positioned using
-%D one transform call (\type{cm}). This saves some additional
-%D scaling.
-
-\def\startPDFtoPDF%
- {\setbox0=\vbox\bgroup
- \message{[PDF to PDF \PDFfilename}%
- \forgetall
- \scratchcounter=0
- \let\stopPDFtoPDF=\dostopPDFtoPDF}
-
-\def\dostopPDFtoPDF%
- {\ifnum\scratchcounter<0 \scratchcounter=1 \fi
- \message{(\the\scratchcounter\space lines)]}%
- \egroup
- \wd0=\PDFwidth
- \vbox to \PDFheight
- {\forgetall
- \vfill
- \pdfliteral{q}%
- \pdfliteral{1 0 0 1 \PDFxoffset\space \PDFyoffset\space cm}%
- \pdfliteral{\PDFxscale\space 0 0 \PDFyscale\space 0 0 cm}%
- \box0
- \pdfliteral{Q}}}
-
-\def\stopPDFtoPDF%
- {\message{[PDF to PDF \PDFfilename\space not found]}}
-
-\def\convertPDFtoPDF#1#2#3#4#5#6#7%
- {\bgroup
- \def\PDFfilename{#1}%
- \def\PDFxscale {#2}%
- \def\PDFyscale {#3}%
- \setPDFboundingbox{#4}{#5}{#6}{#7}{1}{1}%
- \uncatcodespecials
- \endlinechar=-1
- \let\doprocessPDFline=\handlePDFline
- \doprocessfile\scratchread\PDFfilename\doprocessPDFline
- \stopPDFtoPDF
- \egroup}
-
-%D \macros
-%D {convertMPtoPDF}
-%D {}
-%D
-%D The next set of macros implements \METAPOST\ to \PDF\
-%D conversion. Because we want to test as fast as possible, we
-%D first define the \POSTSCRIPT\ operators that \METAPOST\
-%D uses. We don't define irrelevant ones, because these are
-%D skipped anyway.
-
-\def \PScurveto {curveto}
-\def \PSlineto {lineto}
-\def \PSmoveto {moveto}
-\def \PSshowpage {showpage}
-\def \PSnewpath {newpath}
-\def \PSfshow {fshow}
-\def \PSclosepath {closepath}
-\def \PSfill {fill}
-\def \PSstroke {stroke}
-\def \PSclip {clip}
-\def \PSrlineto {rlineto}
-\def \PSsetlinejoin {setlinejoin}
-\def \PSsetlinecap {setlinecap}
-\def \PSsetmiterlimit {setmiterlimit}
-\def \PSsetgray {setgray}
-\def \PSsetrgbcolor {setrgbcolor}
-\def \PSsetcmykcolor {setcmykcolor}
-\def \PSsetdash {setdash}
-\def \PSgsave {gsave}
-\def \PSgrestore {grestore}
-\def \PStranslate {translate}
-\def \PSscale {scale}
-\def \PSconcat {concat}
-\def \PSdtransform {dtransform}
-
-\def \PSBoundingBox {BoundingBox:}
-\def \PSHiResBoundingBox {HiResBoundingBox:}
-\def \PSExactBoundingBox {ExactBoundingBox:}
-\def \PSPage {Page:}
-
-%D By the way, the \type {setcmykcolor} operator is not
-%D output by \METAPOST\ but can result from converting the
-%D \kap{RGB} color specifications, as implemented in
-%D \type{supp-mps}.
-
-%D In \POSTSCRIPT\ arguments precede the operators. Due to the
-%D fact that in some translations we need access to those
-%D arguments, as well as that sometimes we have to skip them,
-%D we stack them up. The stack is one||dimensional for non path
-%D operators and two||dimensional for operators inside a path.
-%D This is because we have to save the whole path for
-%D (optional) postprocessing. Values are pushed onto the stack
-%D by:
-%D
-%D \starttypen
-%D \setMPargument {value}
-%D \stoptypen
-%D
-%D They can be retrieved by the short named macros:
-%D
-%D \starttypen
-%D \gMPa {number}
-%D \sMPa {number}
-%D \stoptypen
-%D
-%D When scanning a path specification, we also save the
-%D operator, using
-%D
-%D \starttypen
-%D \setMPkeyword {n}
-%D \stoptypen
-%D
-%D The path drawing operators are coded for speed: \type{clip},
-%D \type{stroke}, \type{fill} and \type{fillstroke} become
-%D 1, 2, 3 and~4.
-%D
-%D When processing the path this code can be retrieved
-%D using
-%D
-%D \starttypen
-%D \getMPkeyword{n}
-%D \stoptypen
-%D
-%D When setting an argument, the exact position on the stack
-%D depend on the current value of the \COUNTERS\
-%D \type{\nofMPsegments} and \type{\nofMParguments}.
-
-\newcount\nofMPsegments
-\newcount\nofMParguments
-
-%D These variables hold the coordinates. The argument part of
-%D the stack is reset by:
-%D
-%D \starttypen
-%D \resetMPstack
-%D \stoptypen
-%D
-%D We use the prefix \type{@@MP} to keep the stack from
-%D conflicting with existing macros. To speed up things bit
-%D more, we use the constant \type{\@@MP}.
-
-\def\@@MP{@@MP}
-
-\def\setMPargument#1%
- {\advance\nofMParguments by 1
- \expandafter\def
- \csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname%
- {\do#1}}
-
-\def\gMPa#1%
- {\csname\@@MP0#1\endcsname}
-
-\def\gMPs#1%
- {\csname\@@MP\the\nofMPsegments#1\endcsname}
-
-\def\setMPkeyword#1
- {\expandafter\def\csname\@@MP\the\nofMPsegments0\endcsname{#1}%
- \advance\nofMPsegments by 1
- \nofMParguments=0\relax}
-
-\def\getMPkeyword#1%
- {\csname\@@MP#10\endcsname}
-
-%D When we reset the stack, we can assume that all further
-%D comment is to be ignored as well as handled in strings.
-%D By redefining the reset macro after the first call, we
-%D save some run time.
-
-\def\resetMPstack%
- {\catcode`\%=\@@active
- \let\handleMPgraphic=\handleMPendgraphic
- \def\resetMPstack{\nofMParguments=0\relax}%
- \resetMPstack}
-
-%D The arguments are saved with the preceding command
-%D \type{\do}. By default this command expands to nothing, but
-%D when we deal with strings it's used to strip off the
-%D \type{(} and \type{)}.
-%D
-%D Strings are kind of tricky, because characters can be
-%D passed verbatim \type{(hello)}, by octal number
-%D \type{(\005)} or as command \type{(\()}. We therefore
-%D cannot simply ignore \type{(} and \type{)}, the way we do
-%D with \type{[} and \type{]}. Another complication is that
-%D strings may contain characters that normally have a
-%D special meaning in \TEX, like \type{$} and \type{{}}.
-%D
-%D A previous solution made \type{\} an active character and
-%D let it look ahead for a number or character. W ehad to
-%D abandon this scheme because of the need for verbatim
-%D support. The next solution involved some \CATCODE\
-%D trickery but works well.
-
-\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\ignoreMPspecials|
- B\def%BE|
- \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\catcode`\%=\@@active
- \catcode`\[=\@@active
- \catcode`\]=\@@active
- \catcode`\{=\@@active
- \catcode`\}=\@@active
- \catcode`\$=\@@letter
- \catcode`\_=\@@letter
- \catcode`\#=\@@letter
- \catcode`\^=\@@letter
- \catcode`\&=\@@letter
- \catcode`\|=\@@letter
- \catcode`\~=\@@letter
- \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 We use the comment symbol as a sort of trigger:
-
-\bgroup
-\catcode`\%=\@@active
-\gdef\startMPscanning{\let%=\startMPconversion}
-\egroup
-
-%D In earlier versions we used the sequence
-%D
-%D \starttypen
-%D \expandafter\handleMPsequence\input filename\relax
-%D \stoptypen
-%D
-%D Persistent problems in \LATEX\ however forced us to use a
-%D different scheme. Every \POSTSCRIPT\ file starts with a
-%D \type{%}, so we temporary make this an active character
-%D that starts the scanning and redefines itself. (The problem
-%D originates in the redefinition by \LATEX\ of the
-%D \type{\input} primitive.)
-
-\def\startMPconversion%
- {\catcode`\%=\@@ignore
- \ignoreMPspecials
- \handleMPsequence}
-
-%D Here comes the main loop. Most arguments are numbers. This
-%D means that they can be recognized by their \type{\lccode}.
-%D This method saves a lot of processing time. We could
-%D speed up the conversion by handling the \type{path}
-%D seperately.
-
-\def\dohandleMPsequence#1#2 %
- {\ifnum\lccode`#1=0
- \setMPargument{#1#2}%
- \else
- \edef\somestring{#1#2}%
- \ifx\somestring\PSmoveto
- \edef\lastMPmoveX{\gMPa1}%
- \edef\lastMPmoveY{\gMPa2}%
- \pdfliteral{\gMPa1 \gMPa2 m}%
- \resetMPstack
- \else\ifx\somestring\PSnewpath
- \let\handleMPsequence=\handleMPpath
- \else\ifx\somestring\PSgsave
- \pdfliteral{q}%
- \resetMPstack
- \else\ifx\somestring\PSgrestore
- \pdfliteral{Q}%
- \resetMPstack
- \else\ifx\somestring\PSdtransform % == setlinewidth
- \let\handleMPsequence=\handleMPdtransform
- \else\ifx\somestring\PSconcat
- \pdfliteral{\gMPa1 \gMPa2 \gMPa3 \gMPa4 \gMPa5 \gMPa6 cm}%
- \resetMPstack
- \else\ifx\somestring\PSsetrgbcolor
- \pdfliteral{\gMPa1 \gMPa2 \gMPa3 rg \gMPa1 \gMPa2 \gMPa3 RG}%
- \resetMPstack
- \else\ifx\somestring\PSsetcmykcolor
- \pdfliteral{\gMPa1 \gMPa2 \gMPa3 \gMPa4 k \gMPa1 \gMPa2 \gMPa3 \gMPa4 K}%
- \resetMPstack
- \else\ifx\somestring\PSsetgray
- \pdfliteral{\gMPa1 g \gMPa1 G}%
- \resetMPstack
- \else\ifx\somestring\PStranslate
- \pdfliteral{1 0 0 1 \gMPa1 \gMPa2 cm}%
- \resetMPstack
- \else\ifx\somestring\PSsetdash
- \handleMPsetdash
- \resetMPstack
- \else\ifx\somestring\PSsetlinejoin
- \pdfliteral{\gMPa1 j}%
- \resetMPstack
- \else\ifx\somestring\PSsetmiterlimit
- \pdfliteral{\gMPa1 M}%
- \resetMPstack
- \else\ifx\somestring\PSfshow
- \handleMPfshow
- \resetMPstack
- \else\ifx\somestring\PSsetlinecap
- \pdfliteral{\gMPa1 J}%
- \resetMPstack
- \else\ifx\somestring\PSrlineto
- \pdfliteral{\lastMPmoveX\space \lastMPmoveY\space l S}%
- \resetMPstack
- \else\ifx\somestring\PSscale
- \pdfliteral{\gMPa1 0 0 \gMPa2 0 0 cm}%
- \resetMPstack
- \else
- \handleMPgraphic{#1#2}%
- \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
- \fi
- \handleMPsequence}
-
-%D Beginning and ending the graphics is taken care of by the
-%D macro \type{\handleMPgraphic}, which is redefined when
-%D the first graphics operator is met.
-
-\def\handleMPendgraphic#1%
- {\ifx\somestring\PSshowpage
- \let\handleMPsequence=\finishMPgraphic
- \else
- \setMPargument{#1}%
- \fi}
-
-\def\handleMPbegingraphic#1%
- {\ifx\somestring\PSBoundingBox
- \let\handleMPsequence=\handleMPboundingbox
- \else\ifx\somestring\PSHiResBoundingBox
- \let\handleMPsequence=\handleMPboundingbox
- \else\ifx\somestring\PSExactBoundingBox
- \let\handleMPsequence=\handleMPboundingbox
- \else\ifx\somestring\PSPage
- \let\handleMPsequence=\handleMPpage
- \else
- \setMPargument{#1}%
- \fi\fi\fi\fi}
-
-\let\handleMPgraphic=\handleMPbegingraphic
-
-%D We check for three kind of bounding boxes: the normal one
-%D and two high precission ones:
-%D
-%D \starttypen
-%D BoundingBox: llx lly ucx ucy
-%D HiResBoundingBox: llx lly ucx ucy
-%D ExactBoundingBox: llx lly ucx ucy
-%D \stoptypen
-%D
-%D The dimensions are saved for later use.
-
-\def\handleMPboundingbox #1 #2 #3 #4
- {\dimen0=#1pt\dimen0=-\MPxscale\dimen0
- \dimen2=#2pt\dimen2=-\MPyscale\dimen2
- \xdef\MPxoffset{\withoutpt{\the\dimen0}}%
- \xdef\MPyoffset{\withoutpt{\the\dimen2}}%
- \dimen0=#1bp\dimen0=-\dimen0
- \dimen2=#2bp\dimen2=-\dimen2
- \advance\dimen0 by #3bp
- \dimen0=\MPxscale\dimen0
- \xdef\MPwidth{\the\dimen0}%
- \advance\dimen2 by #4bp
- \dimen2=\MPyscale\dimen2
- \xdef\MPheight{\the\dimen2}%
- \nofMParguments=0
- \let\handleMPsequence=\dohandleMPsequence
- \handleMPsequence}
-
-%D We use the \type{page} comment as a signal that
-%D stackbuilding can be started.
-
-\def\handleMPpage #1 #2
- {\nofMParguments=0
- \let\handleMPsequence=\dohandleMPsequence
- \handleMPsequence}
-
-%D \METAPOST\ draws it dots by moving to a location and
-%D invoking \type{0 0 rlineto}. This operator is not
-%D available in \PDF. Our solution is straightforward: we draw
-%D a line from $(current\_x, current\_y)$ to itself. This
-%D means that the arguments of the preceding \type{moveto} have
-%D to be saved.
-
-\def\lastMPmoveX{0}
-\def\lastMPmoveY{0}
-
-%D These saved coordinates are also used when we handle the
-%D texts. Text handling proved to be a bit of a nuisance, but
-%D finaly I saw the light. It proved that we also had to
-%D take care of \type{(split arguments)}.
-
-\def\handleMPfshow%
- {\setbox0=\hbox
- {\obeyMPspecials
- \edef\size{\gMPa{\the\nofMParguments} }%
- \advance\nofMParguments by -1
- \font\temp=\gMPa{\the\nofMParguments} at \size bp
- \advance\nofMParguments by -1
- \temp
- \ifnum\nofMParguments=1
- \def\do(##1){##1}%
- \gMPa1%
- \else
- \scratchcounter=1
- \def\do(##1{##1}%
- \gMPa{\the\scratchcounter}\space
- \def\do{}%
- \loop
- \advance\scratchcounter by 1
- \ifnum\scratchcounter<\nofMParguments
- \gMPa{\the\scratchcounter}\space
- \repeat
- \def\do##1){##1}%
- \gMPa{\the\scratchcounter}%
- \fi
- \unskip}%
- \dimen0=\lastMPmoveY bp
- \advance\dimen0 by \ht0
- \ScaledPointsToBigPoints{\number\dimen0}\lastMPmoveY
- \pdfliteral{n q 1 0 0 1 \lastMPmoveX\space\lastMPmoveY\space cm}%
- \dimen0=\ht0
- \advance\dimen0 by \dp0
- \box0
- \vskip-\dimen0
- \pdfliteral{Q}}
-
-%D Most operators are just converted and keep their
-%D arguments. Dashes however need a bit different treatment,
-%D otherwise \PDF\ viewers complain loudly. Another
-%D complication is that one argument comes after the \type{]}.
-%D When reading the data, we simple ignore the array boundary
-%D characters. We save ourselves some redundant newlines and
-%D at the same time keep the output readable by packing the
-%D literals.
-
-\def\handleMPsetdash%
- {\bgroup
- \def\somestring{[}%
- \scratchcounter=1
- \loop
- \ifnum\scratchcounter<\nofMParguments
- \edef\somestring{\somestring\space\gMPa{\the\scratchcounter}}%
- \advance\scratchcounter by 1
- \repeat
- \edef\somestring{\somestring]\gMPa{\the\scratchcounter} d}%
- \pdfliteral{\somestring}%
- \egroup}
-
-%D The \type{setlinewidth} commands look a bit complicated. There are
-%D two alternatives, that alsways look the same. As John Hobby
-%D says:
-%D
-%D \startsmaller
-%D \starttypen
-%D x 0 dtransform exch truncate exch idtransform pop setlinewidth
-%D 0 y dtransform truncate idtransform setlinewidth pop
-%D \stoptypen
-%D
-%D These are just fancy versions of \type{x setlinewidth} and
-%D \type{y setlinewidth}. The \type{x 0 ...} form is used if
-%D the path is {\em primarily vertical}. It rounds the width
-%D so that vertical lines come out an integer number of pixels
-%D wide in device space. The \type{0 y ...} form does the same
-%D for paths that are {\em primarily horizontal}. The reason
-%D why I did this is Knuth insists on getting exactly the
-%D widths \TEX\ intends for the horizontal and vertical rules
-%D in \type{btex...etex} output. (Note that PostScript scan
-%D conversion rules cause a horizontal or vertical line of
-%D integer width $n$ in device space to come out $n+1$ pixels
-%D wide, regardless of the phase relative to the pixel grid.)
-%D \stopsmaller
-%D
-%D The common operator in these sequences is \type{dtransform},
-%D so we can use this one to trigger setting the linewidth.
-
-\def\handleMPdtransform%
- {\ifdim\gMPa1pt>\!!zeropoint
- \pdfliteral{\gMPa1 w}%
- \def\next##1 ##2 ##3 ##4 ##5 ##6 {\handleMPsequence}%
- \else
- \pdfliteral{\gMPa2 w}%
- \def\next##1 ##2 ##3 ##4 {\handleMPsequence}%
- \fi
- \let\handleMPsequence=\dohandleMPsequence
- \resetMPstack
- \next}
-
-%D The most complicated command is \type{concat}. \METAPOST\
-%D applies this operator to \type{stoke}. At that moment the
-%D points set by \type{curveto} and \type{moveto}, are already
-%D fixed. In \PDF\ however the \type{cm} operator affects the
-%D points as well as the pen (stroke). Like more \PDF\
-%D operators, \type{cm} is a defined in a bit ambiguous way.
-%D The only save route for non||circular penshapes, is saving
-%D teh path, recalculating the points and applying the
-%D transformation matrix in such a way that we can be sure
-%D that its behavior is well defined. This comes down to
-%D inverting the path and applying \type{cm} to that path as
-%D well as the pen. This all means that we have to save the
-%D path.
-
-%D In \METAPOST\ there are three ways to handle a path $p$:
-%D
-%D \starttypen
-%D draw p; fill p; filldraw p;
-%D \stoptypen
-%D
-%D The last case outputs a \type{gsave fill grestore} before
-%D \type{stroke}. Handling the path outside the main loops
-%D saves about 40\% run time.\voetnoot{We can save some more by
-%D following the \METAPOST\ output routine, but for the moment
-%D we keep things simple.} Switching between the main loop and
-%D the path loop is done by means of the recursely called
-%D macro \type{\handleMPsequence}.
-
-\def\handleMPpath%
- {\chardef\finiMPpath=0
- \let\closeMPpath=\relax
- \let\flushMPpath=\flushnormalMPpath
- \resetMPstack
- \nofMPsegments=1
- \let\handleMPsequence=\dohandleMPpath
- \dohandleMPpath}
-
-%D Most paths are drawn with simple round pens. Therefore we've
-%D split up the routinein two.
-
-\def\flushnormalMPpath%
- {\scratchcounter=\nofMPsegments
- \nofMPsegments=1
- \loop
- \expandafter\ifcase\getMPkeyword{\the\nofMPsegments}\relax
- \pdfliteral{\gMPs1 \gMPs2 l}%
- \or
- \pdfliteral{\gMPs1 \gMPs2 \gMPs3 \gMPs4 \gMPs5 \gMPs6 c}%
- \or
- \pdfliteral{\lastMPmoveX\space \lastMPmoveY\space l S}%
- \or
- \edef\lastMPmoveX{\gMPs1}%
- \edef\lastMPmoveY{\gMPs2}%
- \pdfliteral{\lastMPmoveX\space \lastMPmoveY\space m}%
- \fi
- \advance\nofMPsegments by 1\relax
- \ifnum\nofMPsegments<\scratchcounter
- \repeat}
-
-\def\flushconcatMPpath%
- {\scratchcounter=\nofMPsegments
- \nofMPsegments=1
- \loop
- \expandafter\ifcase\getMPkeyword{\the\nofMPsegments}\relax
- \doMPconcat{\gMPs1}\a{\gMPs2}\b
- \pdfliteral{\a\space \b\space l}%
- \or
- \doMPconcat{\gMPs1}\a{\gMPs2}\b
- \doMPconcat{\gMPs3}\c{\gMPs4}\d
- \doMPconcat{\gMPs5}\e{\gMPs6}\f
- \pdfliteral{\a\space \b\space \c\space \d\space \e\space \f\space c}%
- \or
- \bgroup
- \noMPtranslate
- \doMPconcat\lastMPmoveX\a\lastMPmoveY\b
- \pdfliteral{\a\space \b\space l S}%
- \egroup
- \or
- \edef\lastMPmoveX{\gMPs1}%
- \edef\lastMPmoveY{\gMPs2}%
- \doMPconcat\lastMPmoveX\a\lastMPmoveY\b
- \pdfliteral{\a\space \b\space m}%
- \fi
- \advance\nofMPsegments by 1\relax
- \ifnum\nofMPsegments<\scratchcounter
- \repeat}
-
-%D The transformation of the coordinates is handled by one of
-%D the macros Tanmoy posted to the \PDFTEX\ mailing list.
-%D I rewrote and optimized the original macro to suit the other
-%D macros in this module.
-%D
-%D \starttypen
-%D \doMPconcat {x position} \xresult {y position} \yresult
-%D \stoptypen
-%D
-%D
-%D By setting the auxiliary \DIMENSIONS\ \type{\dimen0} upto
-%D \type{\dimen10} only once per path, we save over 20\% run
-%D time. Some more speed was gained by removing some parameter
-%D passing. These macros can be optimized a bit more by using
-%D more constants. There is however not much need for further
-%D optimization because penshapes usually are round and
-%D therefore need no transformation. Nevertheless we move the
-%D factor to the outer level and use bit different \type{pt}
-%D removal macro. Although the values represent base points,
-%D we converted them to pure points, simply because those can
-%D be converted back.
-
-\def\MPconcatfactor{256}
-
-\def\doMPreducedimen#1
- {\count0=\MPconcatfactor
- \advance\dimen#1 \ifdim\dimen#1>\!!zeropoint .5\else -.5\fi\count0
- \divide\dimen#1 \count0\relax}
-
-\def\doMPexpanddimen#1
- {\multiply\dimen#1 \MPconcatfactor\relax}
-
-\def\presetMPconcat%
- {\dimen 0=\gMPs1 pt \doMPreducedimen 0 % r_x
- \dimen 2=\gMPs2 pt \doMPreducedimen 2 % s_x
- \dimen 4=\gMPs3 pt \doMPreducedimen 4 % s_y
- \dimen 6=\gMPs4 pt \doMPreducedimen 6 % r_y
- \dimen 8=\gMPs5 pt \doMPreducedimen 8 % t_x
- \dimen10=\gMPs6 pt \doMPreducedimen10 } % t_y
-
-\def\noMPtranslate% use this one grouped
- {\dimen 8=\!!zeropoint % t_x
- \dimen10=\!!zeropoint} % t_y
-
-\def\doMPconcat#1#2#3#4%
- {\dimen12=#1 pt \doMPreducedimen12 % p_x
- \dimen14=#3 pt \doMPreducedimen14 % p_y
- %
- \dimen16 \dimen 0
- \multiply \dimen16 \dimen 6
- \dimen20 \dimen 2
- \multiply \dimen20 \dimen 4
- \advance \dimen16 -\dimen20
- %
- \dimen18 \dimen12
- \multiply \dimen18 \dimen 6
- \dimen20 \dimen14
- \multiply \dimen20 \dimen 4
- \advance \dimen18 -\dimen20
- \dimen20 \dimen 4
- \multiply \dimen20 \dimen10
- \advance \dimen18 \dimen20
- \dimen20 \dimen 6
- \multiply \dimen20 \dimen 8
- \advance \dimen18 -\dimen20
- %
- \multiply \dimen12 -\dimen 2
- \multiply \dimen14 \dimen 0
- \advance \dimen12 \dimen14
- \dimen20 \dimen 2
- \multiply \dimen20 \dimen 8
- \advance \dimen12 \dimen20
- \dimen20 \dimen 0
- \multiply \dimen20 \dimen10
- \advance \dimen12 -\dimen20
- %
- \doMPreducedimen16
- \divide \dimen18 \dimen16 \doMPexpanddimen18
- \divide \dimen12 \dimen16 \doMPexpanddimen12
- %
- \edef#2{\withoutpt{\the\dimen18}}% % p_x^\prime
- \edef#4{\withoutpt{\the\dimen12}}} % p_y^\prime
-
-%D The following explanation of the conversion process was
-%D posted to the \PDFTEX\ mailing list by Tanmoy. The original
-%D macro was part of a set of macro's that included sinus and
-%D cosinus calculation as well as scaling and translating. The
-%D \METAPOST\ to \PDF\ conversion however only needs
-%D transformation.
-
-%D \start \switchnaarkorps [ss]
-%D
-%D Given a point $(U_x, U_y)$ in user coordinates, the business
-%D of \POSTSCRIPT\ is to convert it to device space. Let us say
-%D that the device space coordinates are $(D_x, D_y)$. Then, in
-%D \POSTSCRIPT\ $(D_x, D_y)$ can be written in terms of
-%D $(U_x, U_y)$ in matrix notation, either as
-%D
-%D \plaatsformule
-%D \startformule
-%D \pmatrix{D_x&D_y&1\cr} = \pmatrix{U_x&U_y&1\cr}
-%D \pmatrix{s_x&r_x&0\cr
-%D r_y&s_y&0\cr
-%D t_x&t_y&1\cr}
-%D \stopformule
-%D
-%D or
-%D
-%D \plaatsformule
-%D \startformule
-%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x&r_y&t_x\cr
-%D r_x&s_y&t_y\cr
-%D 0 &0 &1 \cr}
-%D \pmatrix{U_x\cr
-%D U_y\cr
-%D 1 \cr}
-%D \stopformule
-%D
-%D both of which is a shorthand for the same set of equations:
-%D
-%D \plaatsformule
-%D \startformule
-%D D_x = s_x U_x + r_y U_y + t_x
-%D \stopformule
-%D
-%D \plaatsformule
-%D \startformule
-%D D_y = r_x U_x + s_y U_y + t_y
-%D \stopformule
-%D
-%D which define what is called an `affine transformation'.
-%D
-%D \POSTSCRIPT\ represents the `transformation matrix' as a
-%D six element matrix instead of a $3\times 3$ array because
-%D three of the elements are always~0, 0 and~1. Thus the above
-%D transformation is written in postscript as $[s_x\, r_x\,
-%D r_y\, s_y\, t_x\, t_y]$. However, when doing any
-%D calculations, it is useful to go back to the original
-%D matrix notation (whichever: I will use the second) and
-%D continue from there.
-%D
-%D As an example, if the current transformation matrix is
-%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$ and you say \typ{[a b
-%D c d e f] concat}, this means:
-%D
-%D \startsmaller
-%D Take the user space coordinates and transform them to an
-%D intermediate set of coordinates using array $[a\, b\, c\, d\,
-%D e\, f]$ as the transformation matrix.
-%D
-%D Take the intermediate set of coordinates and change them to
-%D device coordinates using array $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$
-%D as the transformation matrix.
-%D \stopsmaller
-%D
-%D Well, what is the net effect? In matrix notation, it is
-%D
-%D \plaatsformule
-%D \startformule
-%D \pmatrix{I_x\cr I_y\cr 1\cr} = \pmatrix{a&c&e\cr
-%D b&d&f\cr
-%D 0&0&1\cr}
-%D \pmatrix{U_x\cr
-%D U_y\cr
-%D 1 \cr}
-%D \stopformule
-%D
-%D \plaatsformule
-%D \startformule
-%D \pmatrix{D_y\cr D_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr
-%D r_x&s_y&t_y\cr
-%D 0 &0 &1 \cr}
-%D \pmatrix{I_x\cr
-%D I_y\cr
-%D 1 \cr}
-%D \stopformule
-%D
-%D where $(I_x, I_y)$ is the intermediate coordinate.
-%D
-%D Now, the beauty of the matrix notation is that when there is
-%D a chain of such matrix equations, one can always compose
-%D them into one matrix equation using the standard matrix
-%D composition law. The composite matrix from two matrices can
-%D be derived very easily: the element in the $i$\hoog{th}
-%D horizontal row and $j$\hoog{th} vertical column is
-%D calculated by`multiplying' the $i$\hoog{th} row of the first
-%D matrix and the $j$\hoog{th} column of the second matrix (and
-%D summing over the elements). Thus, in the above:
-%D
-%D \plaatsformule
-%D \startformule
-%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr
-%D r_x^\prime&s_y^\prime&t_y^\prime\cr
-%D 0 &0 &0 \cr}
-%D \pmatrix{U_x\cr
-%D U_y\cr
-%D 1 \cr}
-%D \stopformule
-%D
-%D with
-%D
-%D \plaatsformule
-%D \startformule
-%D \eqalign
-%D {s_x^\prime & = s_x a + r_y b \cr
-%D r_x^\prime & = r_x a + s_y b \cr
-%D r_y^\prime & = s_x c + r_y d \cr
-%D s_y^\prime & = r_x c + s_y d \cr
-%D t_x^\prime & = s_x e + r_y f + t_x \cr
-%D t_y^\prime & = r_x e + s_y f + t_y \cr}
-%D \stopformule
-
-%D In fact, the same rule is true not only when one is going
-%D from user coordinates to device coordinates, but whenever
-%D one is composing two `transformations' together
-%D (transformations are `associative'). Note that the formula
-%D is not symmetric: you have to keep track of which
-%D transformation existed before (i.e.\ the equivalent of
-%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$) and which was
-%D specified later (i.e.\ the equivalent of $[a\, b\, c\, d\,
-%D e\, f]$). Note also that the language can be rather
-%D confusing: the one specified later `acts earlier',
-%D converting the user space coordinates to intermediate
-%D coordinates, which are then acted upon by the pre||existing
-%D transformation. The important point is that order of
-%D transformation matrices cannot be flipped (transformations
-%D are not `commutative').
-%D
-%D Now what does it mean to move a transformation matrix
-%D before a drawing? What it means is that given a point
-%D $(P_x, P_y)$ we need a different set of coordinates
-%D $(P_x^\prime, P_y^\prime)$ such that if the transformation
-%D acts on $(P_x^\prime, P_y^\prime)$, they produce $(P_x,
-%D P_y)$. That is we need to solve the set of equations:
-%D
-%D \plaatsformule
-%D \startformule
-%D \pmatrix{P_x\cr P_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr
-%D r_x&s_y&t_y\cr
-%D 0 &0 &1 \cr}
-%D \pmatrix{P_x^\prime\cr
-%D P_y^\prime\cr
-%D 1 \cr}
-%D \stopformule
-%D
-%D Again matrix notation comes in handy (i.e. someone has
-%D already solved the problem for us): we need the inverse
-%D transformation matrix. The inverse transformation matrix can
-%D be calculated very easily: it is
-%D
-%D \plaatsformule
-%D \startformule
-%D \pmatrix{P_x^\prime\cr P_y^\prime\cr 1\cr} =
-%D \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr
-%D r_x^\prime&s_y^\prime&t_y^\prime\cr
-%D 0 &0 &1 \cr}
-%D \pmatrix{P_x\cr
-%D P_y\cr
-%D 1 \cr}
-%D \stopformule
-%D
-%D where, the inverse transformation matrix is given by
-%D
-%D \plaatsformule
-%D \startformule
-%D \eqalign
-%D {D & = s_x s_y - r_x r_y \cr
-%D s_x^\prime & = s_y / D \cr
-%D s_y^\prime & = s_x / D \cr
-%D r_x^\prime & = - r_x / D \cr
-%D r_y^\prime & = - r_y / D \cr
-%D t_x^\prime & = ( - s_y t_x + r_y t_y ) / D \cr
-%D t_y^\prime & = ( r_x t_x - s_x t_y ) / D \cr}
-%D \stopformule
-%D
-%D And you can see that when expanded out, this does
-%D give the formulas:
-%D
-%D \plaatsformule
-%D \startformule
-%D P_x^\prime = { { s_y(p_x-t_x) + r_y(t_y-p_y) } \over
-%D { s_x*s_y-r_x*r_y } }
-%D \stopformule
-%D
-%D \plaatsformule
-%D \startformule
-%D P_y^\prime = { { s_x(p_y-t_y) + r_x(t_x-p_x) } \over
-%D { s_x*s_y-r_x*r_y } }
-%D \stopformule
-%D
-%D The code works by representing a real number by converting
-%D it to a dimension to be put into a \DIMENSION\ register: 2.3 would
-%D be represented as 2.3pt for example. In this scheme,
-%D multiplying two numbers involves multiplying the \DIMENSION\
-%D registers and dividing by 65536. Accuracy demands that the
-%D division be done as late as possible, but overflow
-%D considerations need early division.
-%D
-%D Division involves dividing the two \DIMENSION\ registers and
-%D multiplying the result by 65536. Again, accuracy would
-%D demand that the numerator be multiplied (and|/|or the
-%D denominator divided) early: but that can lead to overflow
-%D which needs to be avoided.
-%D
-%D If nothing is known about the numbers to start with (in
-%D concat), I have chosen to divide the 65536 as a 256 in each
-%D operand. However, in the series calculating the sine and
-%D cosine, I know that the terms are small (because I never
-%D have an angle greater than 45 degrees), so I chose to
-%D apportion the factor in a different way.
-%D
-%D \stop
-%D
-%D The path is output using the values saved on the stack. If
-%D needed, all coordinates are recalculated.
-
-\def\processMPpath%
- {\flushMPpath
- \closeMPpath
- \pdfliteral{\ifcase\finiMPpath W n\or S\or f\or B\fi}%
- \let\handleMPsequence=\dohandleMPsequence
- \resetMPstack
- \nofMPsegments=0
- \handleMPsequence}
-
-%D In \PDF\ the \type{cm} operator must precede the path
-%D specification. We therefore can output the \type{cm} at
-%D the moment we encounter it.
-
-\def\handleMPpathconcat%
- {\presetMPconcat
- \pdfliteral{\gMPs1 \gMPs2 \gMPs3 \gMPs4 \gMPs5 \gMPs6 cm}%
- \resetMPstack}
-
-%D This macro interprets the path and saves it as compact as
-%D possible.
-
-\def\dohandleMPpath#1#2 %
- {\ifnum\lccode`#1=0
- \setMPargument{#1#2}%
- \else
- \def\somestring{#1#2}%
- \ifx\somestring\PSlineto
- \setMPkeyword0
- \else\ifx\somestring\PScurveto
- \setMPkeyword1
- \else\ifx\somestring\PSrlineto
- \setMPkeyword2
- \else\ifx\somestring\PSmoveto
- \setMPkeyword3
- \else\ifx\somestring\PSclip
- \let\handleMPsequence=\processMPpath
- \else\ifx\somestring\PSgsave
- \chardef\finiMPpath=3
- \else\ifx\somestring\PSgrestore
- \else\ifx\somestring\PSfill
- \ifnum\finiMPpath=0
- \chardef\finiMPpath=2
- \let\handleMPsequence=\processMPpath
- \fi
- \else\ifx\somestring\PSstroke
- \ifnum\finiMPpath=0
- \chardef\finiMPpath=1
- \fi
- \let\handleMPsequence=\processMPpath
- \else\ifx\somestring\PSclosepath
- \def\closeMPpath{\pdfliteral{h}}%
- \else\ifx\somestring\PSconcat
- \let\flushMPpath=\flushconcatMPpath
- \handleMPpathconcat
- \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
- \fi
- \handleMPsequence}
-
-%D The main conversion command is
-%D
-%D \starttypen
-%D \convertMPtoPDF {filename} {x scale} {y scale}
-%D \stoptypen
-%D
-%D The dimensions are derived from the bounding box. So we
-%D only have to say:
-%D
-%D \starttypen
-%D \convertMPtoPDF{mp-pra-1.eps}{1}{1}
-%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5}
-%D \stoptypen
-
-\def\convertMPtoPDF#1#2#3%
- {\bgroup
- \message{[MP to PDF #1]}%
- \setMPspecials
- \startMPscanning
- \def\do{}%
- \edef\MPxscale{#2}%
- \edef\MPyscale{#3}%
- \setbox0=\vbox\bgroup
- \forgetall
- \offinterlineskip
- \pdfliteral{q}%
- \let\handleMPsequence=\dohandleMPsequence
- \catcode`\^^M=\@@endofline
- \input #1\relax}
-
-\def\finishMPgraphic%
- {\pdfliteral{Q}%
- \egroup
- \wd0=\MPwidth
- \vbox to \MPheight
- {\forgetall
- \vfill
- \pdfliteral{q \MPxscale\space 0 0 \MPyscale\space
- \MPxoffset\space \MPyoffset\space cm}%
- \box0
- \pdfliteral{Q}}%
- \egroup}
-
-%D This kind of conversion is possible because \METAPOST\
-%D does all the calculations. Converting other \POSTSCRIPT\
-%D files would drive both me and \TEX\ crazy.
-
-\protect
-
-\endinput
-
\ No newline at end of file +%D \module +%D [ file=supp-pdf, +%D version=1998.10.15, +%D title=\CONTEXT\ Support Macros, +%D subtitle=\METAPOST\ to \PDF\ conversion, +%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. Non||commercial use is +%C granted. + +%D These macros are written as generic as possible. Some +%D general support macro's are loaded from a small module +%D especially made for non \CONTEXT\ use. In this module I +%D use a matrix transformation macro written by Tanmoy +%D Bhattacharya. Thanks to extensive testing of Sebastian +%D Ratz I was able to complete this module within reasonable +%D time. First we take care of non||\CONTEXT\ use: + +\ifx \undefined \writestatus \input supp-mis.tex \relax \fi +\ifx \undefined \convertPDFtoPDF \else \expandafter \endinput \fi + +%D This module handles some \PDF\ conversion and insertions +%D topics. By default, the macros use the \PDFTEX\ primitive +%D \type{\pdfliteral} when available. + +\writestatus{loading}{Context Support Macros / PDF} + +\unprotect + +\ifx\pdfliteral\undefined + \def\PDFcode#1{\message{[ignored pdfliteral: #1]}} +\else + \let\PDFcode=\pdfliteral +\fi + +%D \macros +%D {convertPDFtoPDF} +%D +%D \PDFTEX\ supports verbatim inclusion of \PDF\ code. The +%D following macro takes care of inserting externally defined +%D illustrations in \PDF\ format. According to a suggestion +%D Tanmoy Bhattacharya posted to the \PDFTEX\ mailing list, we +%D first skip lines until \type{stream} is reached and then +%D copy lines until \type{endstream} is encountered. This +%D scheme only works with vectorized graphics in which no +%D indirect references to objects are used. Bitmaps also don't +%D work. Interpreting their specifications is beyond the +%D current implementation. +%D +%D \starttypen +%D \convertPDFtoPDF +%D {filename} +%D {x scale} {y scale} +%D {x offset } {y offset} +%D {width} {height} +%D \stoptypen +%D +%D When the scales are set to~1, the last last four values +%D are the same as the bounding box, e.g. +%D +%D \starttypen +%D \convertPDFtoPDF{mp-pra-1.pdf} {1} {1}{-1bp}{-1bp}{398bp}{398bp} +%D \convertPDFtoPDF{mp-pra-1.pdf}{.5}{.5} {0bp} {0bp}{199bp}{199bp} +%D \stoptypen +%D +%D Keep in mind, that this kind of copying only works for +%D pure and valid pdf code (without fonts). + +%D The scanning and copying is straightforward and quite fast. +%D To speed up things we use two constants. + +\def\@@PDFstream@@ {stream} +\def\@@PDFendstream@@ {endstream} + +%D \macros +%D {PDFmediaboxprefered} +%D +%D If needed, the macros can scan for the mediabox that +%D specifies the dimensions and offsets of the graphic. When +%D we say: +%D +%D \starttypen +%D \PDFmediaboxpreferedtrue +%D \stoptypen +%D +%D the mediabox present in the file superseded the user +%D specified, already scaled and calculated offset and +%D dimensions. Beware: the user supplied values are not the +%D bounding box ones! + +\newif\ifPDFmediaboxprefered + +\def\setPDFboundingbox#1#2#3#4#5#6% + {\dimen0=#1\dimen0=#5\dimen0 + \ScaledPointsToBigPoints{\number\dimen0}\PDFxoffset + \dimen0=#3\dimen0=#5\dimen0 + \xdef\PDFwidth{\the\dimen0}% + \dimen0=#2\dimen0=#6\dimen0 + \ScaledPointsToBigPoints{\number\dimen0}\PDFyoffset + \dimen0=#4\dimen0=#6\dimen0 + \xdef\PDFheight{\the\dimen0}% + \global\let\PDFxoffset=\PDFxoffset + \global\let\PDFyoffset=\PDFyoffset} + +\def\setPDFmediabox#1[#2 #3 #4 #5]#6\done% + {\dimen2=#2bp\dimen2=-\dimen2 + \dimen4=#3bp\dimen4=-\dimen4 + \dimen6=#4bp\advance\dimen6 by \dimen2 + \dimen8=#5bp\advance\dimen8 by \dimen4 + \setPDFboundingbox{\dimen2}{\dimen4}{\dimen6}{\dimen8}\PDFxscale\PDFyscale} + +\def\checkPDFmediabox#1/MediaBox#2#3\done% + {\ifx#2\relax \else + \message{mediabox}% + \setPDFmediabox#2#3\done + \fi} + +%D We use the general macro \type{\doprocessfile} and feed this +%D with a line handling macro that changed it's behavior when +%D the stream operators are encountered. + +\def\handlePDFline% + {\ifx\@@PDFstream@@\fileline + \let\doprocessPDFline=\copyPDFobject + \startPDFtoPDF + \else\ifPDFmediaboxprefered + \expandafter\checkPDFmediabox\fileline/MediaBox\relax\done + \fi\fi} + +\def\copyPDFobject% + {\ifx\@@PDFendstream@@\fileline + \ifPDFmediaboxprefered + \let\doprocessPDFline=\findPDFmediabox + \else + \let\doprocessPDFline=\relax + \fi + \else + \advance\scratchcounter by 1 + \PDFcode{\fileline}% + \fi} + +\def\findPDFmediabox% + {\expandafter\checkPDFmediabox\fileline/MediaBox\relax\done} + +%D The main conversion macro wraps the \PDF\ codes in a box +%D that is output as an object. The graphics are embedded +%D in~\type{q} and~\type{Q} and are scaled and positioned using +%D one transform call (\type{cm}). This saves some additional +%D scaling. + +%D \starttypen +%D \def\startPDFtoPDF% +%D {\setbox0=\vbox\bgroup +%D \message{[PDF to PDF \PDFfilename}% +%D \forgetall +%D \scratchcounter=0 +%D \let\stopPDFtoPDF=\dostopPDFtoPDF} +%D +%D \def\dostopPDFtoPDF% +%D {\ifnum\scratchcounter<0 \scratchcounter=1 \fi +%D \message{(\the\scratchcounter\space lines)]}% +%D \egroup +%D \wd0=\PDFwidth +%D \vbox to \PDFheight +%D {\forgetall +%D \vfill +%D \PDFcode{q}% +%D \PDFcode{1 0 0 1 \PDFxoffset\space \PDFyoffset\space cm}% +%D \PDFcode{\PDFxscale\space 0 0 \PDFyscale\space 0 0 cm}% +%D \box0 +%D \PDFcode{Q}}} +%D +%D \def\stopPDFtoPDF% +%D {\message{[PDF to PDF \PDFfilename\space not found]}} +%D +%D \def\convertPDFtoPDF#1#2#3#4#5#6#7% +%D {\bgroup +%D \def\PDFfilename{#1}% +%D \def\PDFxscale {#2}% +%D \def\PDFyscale {#3}% +%D \setPDFboundingbox{#4}{#5}{#6}{#7}{1}{1}% +%D \uncatcodespecials +%D \endlinechar=-1 +%D \let\doprocessPDFline=\handlePDFline +%D \doprocessfile\scratchread\PDFfilename\doprocessPDFline +%D \stopPDFtoPDF +%D \egroup} + +\def\convertPDFtoPDF#1#2#3#4#5#6#7% + {\message{[PDF to PDF use \string\PDFcode instead]}% + \vbox{use the direct method instead}} + +%D \macros +%D {dogetPDFmediabox} +%D +%D The next macro can be used to find the mediabox of a \PDF\ +%D illustration. +%D +%D \starttypen +%D \dogetPDFmediabox +%D {filename} +%D {new dimen}{new dimen}{new dimen}{new dimen} +%D \stoptypen +%D +%D Beware of dimen clashes: this macro uses the 5~default +%D scratch registers! When no file or mediabox is found, the +%D dimensions are zeroed. + +\def\dogetPDFmediabox#1#2#3#4#5% + {\bgroup + \def\PDFxscale{1}% + \def\PDFyscale{1}% + \uncatcodespecials + \endlinechar=-1 + \def\checkPDFtypepage##1/Type /Page##2##3\done% + {\ifx##2\relax + \else\if##2s% accept /Page and /Pages + \let\doprocessPDFline=\findPDFmediabox + \else + \let\doprocessPDFline=\findPDFmediabox + \fi\fi}% + \def\findPDFtypepage% + {\expandafter\checkPDFtypepage\fileline/Type /Page\relax\done}% + \def\checkPDFmediabox##1/MediaBox##2##3\done% + {\ifx##2\relax \else + \setPDFmediabox##2##3\done + \fileprocessedtrue + \fi}% + \def\findPDFmediabox% + {\expandafter\checkPDFmediabox\fileline/MediaBox\relax\done}% + \let\doprocessPDFline=\findPDFtypepage + \doprocessfile\scratchread{#1}\doprocessPDFline + \egroup + \ifx\PDFxoffset\undefined + #2=\!!zeropoint #3=\!!zeropoint #4=\!!zeropoint #5=\!!zeropoint + \else + #2=\PDFxoffset bp #3=\PDFyoffset bp #4=\PDFwidth #5=\PDFheight + \fi} + +%D \macros +%D {convertMPtoPDF} +%D +%D The next set of macros implements \METAPOST\ to \PDF\ +%D conversion. Because we want to test as fast as possible, we +%D first define the \POSTSCRIPT\ operators that \METAPOST\ +%D uses. We don't define irrelevant ones, because these are +%D skipped anyway. + +\def \PScurveto {curveto} +\def \PSlineto {lineto} +\def \PSmoveto {moveto} +\def \PSshowpage {showpage} +\def \PSnewpath {newpath} +\def \PSfshow {fshow} +\def \PSclosepath {closepath} +\def \PSfill {fill} +\def \PSstroke {stroke} +\def \PSclip {clip} +\def \PSrlineto {rlineto} +\def \PSsetlinejoin {setlinejoin} +\def \PSsetlinecap {setlinecap} +\def \PSsetmiterlimit {setmiterlimit} +\def \PSsetgray {setgray} +\def \PSsetrgbcolor {setrgbcolor} +\def \PSsetcmykcolor {setcmykcolor} +\def \PSsetdash {setdash} +\def \PSgsave {gsave} +\def \PSgrestore {grestore} +\def \PStranslate {translate} +\def \PSscale {scale} +\def \PSconcat {concat} +\def \PSdtransform {dtransform} + +\def \PSnfont {nfont} + +\def \PSBoundingBox {BoundingBox:} +\def \PSHiResBoundingBox {HiResBoundingBox:} +\def \PSExactBoundingBox {ExactBoundingBox:} +\def \PSPage {Page:} + +%D By the way, the \type {setcmykcolor} operator is not +%D output by \METAPOST\ but can result from converting the +%D \kap{RGB} color specifications, as implemented in +%D \type{supp-mps}. + +%D In \POSTSCRIPT\ arguments precede the operators. Due to the +%D fact that in some translations we need access to those +%D arguments, as well as that sometimes we have to skip them, +%D we stack them up. The stack is one||dimensional for non path +%D operators and two||dimensional for operators inside a path. +%D This is because we have to save the whole path for +%D (optional) postprocessing. Values are pushed onto the stack +%D by: +%D +%D \starttypen +%D \setMPargument {value} +%D \stoptypen +%D +%D They can be retrieved by the short named macros: +%D +%D \starttypen +%D \gMPa {number} +%D \sMPa {number} +%D \stoptypen +%D +%D When scanning a path specification, we also save the +%D operator, using +%D +%D \starttypen +%D \setMPkeyword {n} +%D \stoptypen +%D +%D The path drawing operators are coded for speed: \type{clip}, +%D \type{stroke}, \type{fill} and \type{fillstroke} become +%D 1, 2, 3 and~4. +%D +%D When processing the path this code can be retrieved +%D using +%D +%D \starttypen +%D \getMPkeyword{n} +%D \stoptypen +%D +%D When setting an argument, the exact position on the stack +%D depend on the current value of the \COUNTERS\ +%D \type{\nofMPsegments} and \type{\nofMParguments}. + +\newcount\nofMPsegments +\newcount\nofMParguments + +%D These variables hold the coordinates. The argument part of +%D the stack is reset by: +%D +%D \starttypen +%D \resetMPstack +%D \stoptypen +%D +%D We use the prefix \type{@@MP} to keep the stack from +%D conflicting with existing macros. To speed up things bit +%D more, we use the constant \type{\@@MP}. + +\def\@@MP{@@MP} + +\def\setMPargument#1% + {\advance\nofMParguments by 1 + \expandafter\def + \csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname% + {\do#1}} + +\def\gMPa#1% + {\csname\@@MP0#1\endcsname} + +\def\gMPs#1% + {\csname\@@MP\the\nofMPsegments#1\endcsname} + +\def\setMPkeyword#1 + {\expandafter\def\csname\@@MP\the\nofMPsegments0\endcsname{#1}% + \advance\nofMPsegments by 1 + \nofMParguments=0\relax} + +\def\getMPkeyword#1% + {\csname\@@MP#10\endcsname} + +%D When we reset the stack, we can assume that all further +%D comment is to be ignored as well as handled in strings. +%D By redefining the reset macro after the first call, we +%D save some run time. + +\def\resetMPstack% + {\catcode`\%=\@@active + \let\handleMPgraphic=\handleMPendgraphic + \def\resetMPstack{\nofMParguments=0 }% + \resetMPstack} + +%D The arguments are saved with the preceding command +%D \type{\do}. By default this command expands to nothing, but +%D when we deal with strings it's used to strip off the +%D \type{(} and \type{)}. +%D +%D Strings are kind of tricky, because characters can be +%D passed verbatim \type{(hello)}, by octal number +%D \type{(\005)} or as command \type{(\()}. We therefore +%D cannot simply ignore \type{(} and \type{)}, the way we do +%D with \type{[} and \type{]}. Another complication is that +%D strings may contain characters that normally have a +%D special meaning in \TEX, like \type{$} and \type{{}}. +%D +%D A previous solution made \type{\} an active character and +%D let it look ahead for a number or character. W ehad to +%D abandon this scheme because of the need for verbatim +%D support. The next solution involved some \CATCODE\ +%D trickery but works well. + +\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\ignoreMPspecials| + B\def%BE| + \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`\%=\@@active + \catcode`\[=\@@active + \catcode`\]=\@@active + \catcode`\{=\@@active + \catcode`\}=\@@active + \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 We use the comment symbol as a sort of trigger: + +\bgroup +\catcode`\%=\@@active +\gdef\startMPscanning{\let%=\startMPconversion} +\egroup + +%D In earlier versions we used the sequence +%D +%D \starttypen +%D \expandafter\handleMPsequence\input filename\relax +%D \stoptypen +%D +%D Persistent problems in \LATEX\ however forced us to use a +%D different scheme. Every \POSTSCRIPT\ file starts with a +%D \type{%}, so we temporary make this an active character +%D that starts the scanning and redefines itself. (The problem +%D originates in the redefinition by \LATEX\ of the +%D \type{\input} primitive.) + +\def\startMPconversion% + {\catcode`\%=\@@ignore + \ignoreMPspecials + \handleMPsequence} + +%D Here comes the main loop. Most arguments are numbers. This +%D means that they can be recognized by their \type{\lccode}. +%D This method saves a lot of processing time. We could +%D speed up the conversion by handling the \type{path} +%D seperately. + +\def\dohandleMPsequence#1#2 % + {\ifdone + \ifnum\lccode`#1=0 + \setMPargument{#1#2}% + \else + \edef\somestring{#1#2}% + \ifx\somestring\PSmoveto + \edef\lastMPmoveX{\gMPa1}% + \edef\lastMPmoveY{\gMPa2}% + \pdfliteral{\!MP{\gMPa1} \!MP{\gMPa2} m}% + \resetMPstack + \else\ifx\somestring\PSnewpath + \let\handleMPsequence=\handleMPpath + \else\ifx\somestring\PSgsave + \pdfliteral{q}% + \resetMPstack + \else\ifx\somestring\PSgrestore + \pdfliteral{Q}% + \resetMPstack + \else\ifx\somestring\PSdtransform % == setlinewidth + \let\handleMPsequence=\handleMPdtransform + \else\ifx\somestring\PSconcat + \pdfliteral{\gMPa1 \gMPa2 \gMPa3 \gMPa4 \gMPa5 \gMPa6 cm}% + \resetMPstack + \else\ifx\somestring\PSsetrgbcolor + \pdfliteral{\!MP{\gMPa1} \!MP{\gMPa2} \!MP{\gMPa3} rg + \!MP{\gMPa1} \!MP{\gMPa2} \!MP{\gMPa3} RG}% + \resetMPstack + \else\ifx\somestring\PSsetcmykcolor + \pdfliteral{\!MP{\gMPa1} \!MP{\gMPa2} \!MP{\gMPa3} \!MP{\gMPa4} k + \!MP{\gMPa1} \!MP{\gMPa2} \!MP{\gMPa3} \!MP{\gMPa4} K}% + \resetMPstack + \else\ifx\somestring\PSsetgray + \pdfliteral{\!MP{\gMPa1} g \!MP{\gMPa1} G}% + \resetMPstack + \else\ifx\somestring\PStranslate + \pdfliteral{1 0 0 1 \gMPa1 \gMPa2 cm}% + \resetMPstack + \else\ifx\somestring\PSsetdash + \handleMPsetdash + \resetMPstack + \else\ifx\somestring\PSsetlinejoin + \pdfliteral{\gMPa1 j}% + \resetMPstack + \else\ifx\somestring\PSsetmiterlimit + \pdfliteral{\gMPa1 M}% + \resetMPstack + \else\ifx\somestring\PSfshow + \handleMPfshow + \resetMPstack + \else\ifx\somestring\PSsetlinecap + \pdfliteral{\gMPa1 J}% + \resetMPstack + \else\ifx\somestring\PSrlineto + \pdfliteral{\!MP{\lastMPmoveX} \!MP{\lastMPmoveY} l S}% + \resetMPstack + \else\ifx\somestring\PSscale + \pdfliteral{\gMPa1 0 0 \gMPa2 0 0 cm}% + \resetMPstack + \else + \handleMPgraphic{#1#2}% + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi + \else + \edef\somestring{#1#2}% + \handleMPgraphic{#1#2}% + \fi + \handleMPsequence} + +%D Beginning and ending the graphics is taken care of by the +%D macro \type{\handleMPgraphic}, which is redefined when +%D the first graphics operator is met. + +\def\handleMPendgraphic#1% + {\ifx\somestring\PSshowpage + \let\handleMPsequence=\finishMPgraphic + \else + \setMPargument{#1}% + \fi} + +\def\handleMPbegingraphic#1% + {\ifx\somestring\PSBoundingBox + \def\handleMPsequence{\handleMPboundingbox1}% + \else\ifx\somestring\PSHiResBoundingBox + \def\handleMPsequence{\handleMPboundingbox2}% + \else\ifx\somestring\PSExactBoundingBox + \def\handleMPsequence{\handleMPboundingbox3}% + \else\ifx\somestring\PSshowpage + \let\handleMPsequence=\finishMPgraphic + \else\ifx\somestring\PSPage + \let\handleMPsequence=\handleMPpage + \else + \setMPargument{#1}% kan weg + \fi\fi\fi\fi\fi} + +\let\handleMPgraphic=\handleMPbegingraphic + +%D We check for three kind of bounding boxes: the normal one +%D and two high precission ones: +%D +%D \starttypen +%D BoundingBox: llx lly ucx ucy +%D HiResBoundingBox: llx lly ucx ucy +%D ExactBoundingBox: llx lly ucx ucy +%D \stoptypen +%D +%D The original as well as the recalculated dimensions are +%D saved for later use. + +\newif\ifskipemptyMPgraphic \skipemptyMPgraphicfalse + +\chardef\currentMPboundingbox=0 + +\def\handleMPboundingbox#1#2 #3 #4 #5 + {\ifnum#1>\currentMPboundingbox + \xdef\MPllx{#2}\xdef\MPlly{#3}% + \xdef\MPurx{#4}\xdef\MPury{#5}% + \dimen0=#2pt\dimen0=-\MPxscale\dimen0 + \dimen2=#3pt\dimen2=-\MPyscale\dimen2 + \xdef\MPxoffset{\withoutpt{\the\dimen0}}% + \xdef\MPyoffset{\withoutpt{\the\dimen2}}% + \dimen0=#2bp\dimen0=-\dimen0 + \dimen2=#3bp\dimen2=-\dimen2 + \advance\dimen0 by #4bp + \dimen0=\MPxscale\dimen0 + \xdef\MPwidth{\the\dimen0}% + \advance\dimen2 by #5bp + \dimen2=\MPyscale\dimen2 + \xdef\MPheight{\the\dimen2}% + \chardef\currentMPboundingbox=#1\relax + \fi + \nofMParguments=0 + \let\handleMPsequence=\dohandleMPsequence + \let\next=\handleMPsequence + \ifskipemptyMPgraphic + \ifdim\MPheight=\!!zeropoint\relax\ifdim\MPwidth=\!!zeropoint\relax + \def\next{\endinput\finishMPgraphic}% + \fi\fi + \fi + \next} + +%D We use the \type{page} comment as a signal that +%D stackbuilding can be started. + +\def\handleMPpage #1 #2 + {\nofMParguments=0 + \donetrue + \let\handleMPsequence=\dohandleMPsequence + \handleMPsequence} + +%D \METAPOST\ draws it dots by moving to a location and +%D invoking \type{0 0 rlineto}. This operator is not +%D available in \PDF. Our solution is straightforward: we draw +%D a line from $(current\_x, current\_y)$ to itself. This +%D means that the arguments of the preceding \type{moveto} have +%D to be saved. + +\def\lastMPmoveX{0} +\def\lastMPmoveY{0} + +%D These saved coordinates are also used when we handle the +%D texts. Text handling proved to be a bit of a nuisance, but +%D finaly I saw the light. It proved that we also had to +%D take care of \type{(split arguments)}. + +\def\handleMPfshow% + {\setbox0=\hbox + {\obeyMPspecials + \edef\size{\gMPa{\the\nofMParguments}}% + \ifx\size\PSnfont % round font size (to pt) + \advance\nofMParguments by -1 + \expandafter\scratchdimen\gMPa{\the\nofMParguments}pt + \ifdim\scratchdimen<1pt + \def\size{1pt}% + \else + \advance\scratchdimen by .5pt + \def\size##1.##2\relax{\def\size{##1pt}}% + \expandafter\size\the\scratchdimen\relax + \fi + \else + \edef\size{\size bp}% + \fi + \advance\nofMParguments by -1 + \font\temp=\gMPa{\the\nofMParguments} at \size + \advance\nofMParguments by -1 + \temp + \ifnum\nofMParguments=1 + \def\do(##1){##1}% + \gMPa1% + \else + \scratchcounter=1 + \def\do(##1{\if##1 \char32\else##1\fi}% + \gMPa{\the\scratchcounter}\space + \def\do{}% + \loop + \advance\scratchcounter by 1 + \ifnum\scratchcounter<\nofMParguments + \gMPa{\the\scratchcounter}\space + \repeat + \def\do##1){\if##1 \char32\else##1\fi}% + \gMPa{\the\scratchcounter}% + \fi + \unskip}% + \dimen0=\lastMPmoveY bp + \advance\dimen0 by \ht0 + \ScaledPointsToBigPoints{\number\dimen0}\lastMPmoveY + \PDFcode{n q 1 0 0 1 \lastMPmoveX\space\lastMPmoveY\space cm}% + \dimen0=\ht0 + \advance\dimen0 by \dp0 + \box0 + \vskip-\dimen0 + \PDFcode{Q}} + +%D Most operators are just converted and keep their +%D arguments. Dashes however need a bit different treatment, +%D otherwise \PDF\ viewers complain loudly. Another +%D complication is that one argument comes after the \type{]}. +%D When reading the data, we simple ignore the array boundary +%D characters. We save ourselves some redundant newlines and +%D at the same time keep the output readable by packing the +%D literals. + +\def\handleMPsetdash% + {\bgroup + \def\somestring{[}% + \scratchcounter=1 + \loop + \ifnum\scratchcounter<\nofMParguments + \edef\somestring{\somestring\space\gMPa{\the\scratchcounter}}% + \advance\scratchcounter by 1 + \repeat + \edef\somestring{\somestring]\gMPa{\the\scratchcounter} d}% + \PDFcode{\somestring}% + \egroup} + +%D The \type{setlinewidth} commands look a bit complicated. There are +%D two alternatives, that alsways look the same. As John Hobby +%D says: +%D +%D \startsmaller +%D \starttypen +%D x 0 dtransform exch truncate exch idtransform pop setlinewidth +%D 0 y dtransform truncate idtransform setlinewidth pop +%D \stoptypen +%D +%D These are just fancy versions of \type{x setlinewidth} and +%D \type{y setlinewidth}. The \type{x 0 ...} form is used if +%D the path is {\em primarily vertical}. It rounds the width +%D so that vertical lines come out an integer number of pixels +%D wide in device space. The \type{0 y ...} form does the same +%D for paths that are {\em primarily horizontal}. The reason +%D why I did this is Knuth insists on getting exactly the +%D widths \TEX\ intends for the horizontal and vertical rules +%D in \type{btex...etex} output. (Note that PostScript scan +%D conversion rules cause a horizontal or vertical line of +%D integer width $n$ in device space to come out $n+1$ pixels +%D wide, regardless of the phase relative to the pixel grid.) +%D \stopsmaller +%D +%D The common operator in these sequences is \type{dtransform}, +%D so we can use this one to trigger setting the linewidth. + +\def\handleMPdtransform% + {\ifdim\gMPa1pt>\!!zeropoint + \PDFcode{\gMPa1 w}% + \def\next##1 ##2 ##3 ##4 ##5 ##6 {\handleMPsequence}% + \else + \PDFcode{\gMPa2 w}% + \def\next##1 ##2 ##3 ##4 {\handleMPsequence}% + \fi + \let\handleMPsequence=\dohandleMPsequence + \resetMPstack + \next} + +%D The most complicated command is \type{concat}. \METAPOST\ +%D applies this operator to \type{stoke}. At that moment the +%D points set by \type{curveto} and \type{moveto}, are already +%D fixed. In \PDF\ however the \type{cm} operator affects the +%D points as well as the pen (stroke). Like more \PDF\ +%D operators, \type{cm} is a defined in a bit ambiguous way. +%D The only save route for non||circular penshapes, is saving +%D teh path, recalculating the points and applying the +%D transformation matrix in such a way that we can be sure +%D that its behavior is well defined. This comes down to +%D inverting the path and applying \type{cm} to that path as +%D well as the pen. This all means that we have to save the +%D path. + +%D In \METAPOST\ there are three ways to handle a path $p$: +%D +%D \starttypen +%D draw p; fill p; filldraw p; +%D \stoptypen +%D +%D The last case outputs a \type{gsave fill grestore} before +%D \type{stroke}. Handling the path outside the main loops +%D saves about 40\% run time.\voetnoot{We can save some more by +%D following the \METAPOST\ output routine, but for the moment +%D we keep things simple.} Switching between the main loop and +%D the path loop is done by means of the recursely called +%D macro \type{\handleMPsequence}. + +\def\handleMPpath% + {\chardef\finiMPpath=0 + \let\closeMPpath=\relax + \let\flushMPpath=\flushnormalMPpath + \resetMPstack + \nofMPsegments=1 + \let\handleMPsequence=\dohandleMPpath + \dohandleMPpath} + +%D Most paths are drawn with simple round pens. Therefore we've +%D split up the routinein two. + +\def\flushnormalMPpath% + {\scratchcounter=\nofMPsegments + \nofMPsegments=1 + \loop + \expandafter\ifcase\getMPkeyword{\the\nofMPsegments}\relax + \pdfliteral{\!MP{\gMPs1} \!MP{\gMPs2} l}% + \or + \pdfliteral{\!MP{\gMPs1} \!MP{\gMPs2} \!MP{\gMPs3} \!MP{\gMPs4} \!MP{\gMPs5} \!MP{\gMPs6} c}% + \or + \pdfliteral{\!MP{\lastMPmoveX} \!MP{\lastMPmoveY} l S}% + \or + \edef\lastMPmoveX{\gMPs1}% + \edef\lastMPmoveY{\gMPs2}% + \pdfliteral{\!MP{\lastMPmoveX} \!MP{\lastMPmoveY} m}% + \fi + \advance\nofMPsegments by 1\relax + \ifnum\nofMPsegments<\scratchcounter + \repeat} + +\def\flushconcatMPpath% + {\scratchcounter=\nofMPsegments + \nofMPsegments=1 + \loop + \expandafter\ifcase\getMPkeyword{\the\nofMPsegments}\relax + \doMPconcat{\gMPs1}\a{\gMPs2}\b% + \pdfliteral{\!MP{\a} \!MP{\b} l}% + \or + \doMPconcat{\gMPs1}\a{\gMPs2}\b% + \doMPconcat{\gMPs3}\c{\gMPs4}\d% + \doMPconcat{\gMPs5}\e{\gMPs6}\f% + \pdfliteral{\!MP{\a} \!MP{\b} \!MP{\c} \!MP{\d} \!MP{\e} \!MP{\f} c}% + \or + \bgroup + \noMPtranslate + \doMPconcat\lastMPmoveX\a\lastMPmoveY\b% + \pdfliteral{\!MP{\a} \!MP{\b} l S}% + \egroup + \or + \edef\lastMPmoveX{\gMPs1}% + \edef\lastMPmoveY{\gMPs2}% + \doMPconcat\lastMPmoveX\a\lastMPmoveY\b% + \pdfliteral{\!MP{\a} \!MP{\b} m}% + \fi + \advance\nofMPsegments by 1\relax + \ifnum\nofMPsegments<\scratchcounter + \repeat} + +%D The transformation of the coordinates is handled by one of +%D the macros Tanmoy posted to the \PDFTEX\ mailing list. +%D I rewrote and optimized the original macro to suit the other +%D macros in this module. +%D +%D \starttypen +%D \doMPconcat {x position} \xresult {y position} \yresult +%D \stoptypen +%D +%D By setting the auxiliary \DIMENSIONS\ \type{\dimen0} upto +%D \type{\dimen10} only once per path, we save over 20\% run +%D time. Some more speed was gained by removing some parameter +%D passing. These macros can be optimized a bit more by using +%D more constants. There is however not much need for further +%D optimization because penshapes usually are round and +%D therefore need no transformation. Nevertheless we move the +%D factor to the outer level and use bit different \type{pt} +%D removal macro. Although the values represent base points, +%D we converted them to pure points, simply because those can +%D be converted back. + +\def\MPconcatfactor{256} + +\def\doMPreducedimen#1 + {\count0=\MPconcatfactor + \advance\dimen#1 \ifdim\dimen#1>\!!zeropoint .5\else -.5\fi\count0 + \divide\dimen#1 \count0\relax} + +\def\doMPexpanddimen#1 + {\multiply\dimen#1 \MPconcatfactor\relax} + +\def\presetMPconcat% + {\dimen 0=\gMPs1 pt \doMPreducedimen 0 % r_x + \dimen 2=\gMPs2 pt \doMPreducedimen 2 % s_x + \dimen 4=\gMPs3 pt \doMPreducedimen 4 % s_y + \dimen 6=\gMPs4 pt \doMPreducedimen 6 % r_y + \dimen 8=\gMPs5 pt \doMPreducedimen 8 % t_x + \dimen10=\gMPs6 pt \doMPreducedimen10 } % t_y + +\def\presetMPscale% + {\dimen 0=\gMPs1 pt \doMPreducedimen 0 + \dimen 2=\!!zeropoint + \dimen 4=\!!zeropoint + \dimen 6=\gMPs2 pt \doMPreducedimen 6 + \dimen 8=\!!zeropoint + \dimen10=\!!zeropoint} + +\def\noMPtranslate% use this one grouped + {\dimen 8=\!!zeropoint % t_x + \dimen10=\!!zeropoint} % t_y + +\def\doMPconcat#1#2#3#4% + {\dimen12=#1 pt \doMPreducedimen12 % p_x + \dimen14=#3 pt \doMPreducedimen14 % p_y + % + \dimen16 \dimen 0 + \multiply \dimen16 \dimen 6 + \dimen20 \dimen 2 + \multiply \dimen20 \dimen 4 + \advance \dimen16 -\dimen20 + % + \dimen18 \dimen12 + \multiply \dimen18 \dimen 6 + \dimen20 \dimen14 + \multiply \dimen20 \dimen 4 + \advance \dimen18 -\dimen20 + \dimen20 \dimen 4 + \multiply \dimen20 \dimen10 + \advance \dimen18 \dimen20 + \dimen20 \dimen 6 + \multiply \dimen20 \dimen 8 + \advance \dimen18 -\dimen20 + % + \multiply \dimen12 -\dimen 2 + \multiply \dimen14 \dimen 0 + \advance \dimen12 \dimen14 + \dimen20 \dimen 2 + \multiply \dimen20 \dimen 8 + \advance \dimen12 \dimen20 + \dimen20 \dimen 0 + \multiply \dimen20 \dimen10 + \advance \dimen12 -\dimen20 + % + \doMPreducedimen16 + \divide \dimen18 \dimen16 \doMPexpanddimen18 + \divide \dimen12 \dimen16 \doMPexpanddimen12 + % + \edef#2{\withoutpt{\the\dimen18}}% % p_x^\prime + \edef#4{\withoutpt{\the\dimen12}}} % p_y^\prime + +%D The following explanation of the conversion process was +%D posted to the \PDFTEX\ mailing list by Tanmoy. The original +%D macro was part of a set of macro's that included sinus and +%D cosinus calculation as well as scaling and translating. The +%D \METAPOST\ to \PDF\ conversion however only needs +%D transformation. + +%D \start \switchnaarkorps [ss] +%D +%D Given a point $(U_x, U_y)$ in user coordinates, the business +%D of \POSTSCRIPT\ is to convert it to device space. Let us say +%D that the device space coordinates are $(D_x, D_y)$. Then, in +%D \POSTSCRIPT\ $(D_x, D_y)$ can be written in terms of +%D $(U_x, U_y)$ in matrix notation, either as +%D +%D \plaatsformule +%D \startformule +%D \pmatrix{D_x&D_y&1\cr} = \pmatrix{U_x&U_y&1\cr} +%D \pmatrix{s_x&r_x&0\cr +%D r_y&s_y&0\cr +%D t_x&t_y&1\cr} +%D \stopformule +%D +%D or +%D +%D \plaatsformule +%D \startformule +%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x&r_y&t_x\cr +%D r_x&s_y&t_y\cr +%D 0 &0 &1 \cr} +%D \pmatrix{U_x\cr +%D U_y\cr +%D 1 \cr} +%D \stopformule +%D +%D both of which is a shorthand for the same set of equations: +%D +%D \plaatsformule +%D \startformule +%D D_x = s_x U_x + r_y U_y + t_x +%D \stopformule +%D +%D \plaatsformule +%D \startformule +%D D_y = r_x U_x + s_y U_y + t_y +%D \stopformule +%D +%D which define what is called an `affine transformation'. +%D +%D \POSTSCRIPT\ represents the `transformation matrix' as a +%D six element matrix instead of a $3\times 3$ array because +%D three of the elements are always~0, 0 and~1. Thus the above +%D transformation is written in postscript as $[s_x\, r_x\, +%D r_y\, s_y\, t_x\, t_y]$. However, when doing any +%D calculations, it is useful to go back to the original +%D matrix notation (whichever: I will use the second) and +%D continue from there. +%D +%D As an example, if the current transformation matrix is +%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$ and you say \typ{[a b +%D c d e f] concat}, this means: +%D +%D \startsmaller +%D Take the user space coordinates and transform them to an +%D intermediate set of coordinates using array $[a\, b\, c\, d\, +%D e\, f]$ as the transformation matrix. +%D +%D Take the intermediate set of coordinates and change them to +%D device coordinates using array $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$ +%D as the transformation matrix. +%D \stopsmaller +%D +%D Well, what is the net effect? In matrix notation, it is +%D +%D \plaatsformule +%D \startformule +%D \pmatrix{I_x\cr I_y\cr 1\cr} = \pmatrix{a&c&e\cr +%D b&d&f\cr +%D 0&0&1\cr} +%D \pmatrix{U_x\cr +%D U_y\cr +%D 1 \cr} +%D \stopformule +%D +%D \plaatsformule +%D \startformule +%D \pmatrix{D_y\cr D_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr +%D r_x&s_y&t_y\cr +%D 0 &0 &1 \cr} +%D \pmatrix{I_x\cr +%D I_y\cr +%D 1 \cr} +%D \stopformule +%D +%D where $(I_x, I_y)$ is the intermediate coordinate. +%D +%D Now, the beauty of the matrix notation is that when there is +%D a chain of such matrix equations, one can always compose +%D them into one matrix equation using the standard matrix +%D composition law. The composite matrix from two matrices can +%D be derived very easily: the element in the $i$\hoog{th} +%D horizontal row and $j$\hoog{th} vertical column is +%D calculated by`multiplying' the $i$\hoog{th} row of the first +%D matrix and the $j$\hoog{th} column of the second matrix (and +%D summing over the elements). Thus, in the above: +%D +%D \plaatsformule +%D \startformule +%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr +%D r_x^\prime&s_y^\prime&t_y^\prime\cr +%D 0 &0 &0 \cr} +%D \pmatrix{U_x\cr +%D U_y\cr +%D 1 \cr} +%D \stopformule +%D +%D with +%D +%D \plaatsformule +%D \startformule +%D \eqalign +%D {s_x^\prime & = s_x a + r_y b \cr +%D r_x^\prime & = r_x a + s_y b \cr +%D r_y^\prime & = s_x c + r_y d \cr +%D s_y^\prime & = r_x c + s_y d \cr +%D t_x^\prime & = s_x e + r_y f + t_x \cr +%D t_y^\prime & = r_x e + s_y f + t_y \cr} +%D \stopformule + +%D In fact, the same rule is true not only when one is going +%D from user coordinates to device coordinates, but whenever +%D one is composing two `transformations' together +%D (transformations are `associative'). Note that the formula +%D is not symmetric: you have to keep track of which +%D transformation existed before (i.e.\ the equivalent of +%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$) and which was +%D specified later (i.e.\ the equivalent of $[a\, b\, c\, d\, +%D e\, f]$). Note also that the language can be rather +%D confusing: the one specified later `acts earlier', +%D converting the user space coordinates to intermediate +%D coordinates, which are then acted upon by the pre||existing +%D transformation. The important point is that order of +%D transformation matrices cannot be flipped (transformations +%D are not `commutative'). +%D +%D Now what does it mean to move a transformation matrix +%D before a drawing? What it means is that given a point +%D $(P_x, P_y)$ we need a different set of coordinates +%D $(P_x^\prime, P_y^\prime)$ such that if the transformation +%D acts on $(P_x^\prime, P_y^\prime)$, they produce $(P_x, +%D P_y)$. That is we need to solve the set of equations: +%D +%D \plaatsformule +%D \startformule +%D \pmatrix{P_x\cr P_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr +%D r_x&s_y&t_y\cr +%D 0 &0 &1 \cr} +%D \pmatrix{P_x^\prime\cr +%D P_y^\prime\cr +%D 1 \cr} +%D \stopformule +%D +%D Again matrix notation comes in handy (i.e. someone has +%D already solved the problem for us): we need the inverse +%D transformation matrix. The inverse transformation matrix can +%D be calculated very easily: it is +%D +%D \plaatsformule +%D \startformule +%D \pmatrix{P_x^\prime\cr P_y^\prime\cr 1\cr} = +%D \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr +%D r_x^\prime&s_y^\prime&t_y^\prime\cr +%D 0 &0 &1 \cr} +%D \pmatrix{P_x\cr +%D P_y\cr +%D 1 \cr} +%D \stopformule +%D +%D where, the inverse transformation matrix is given by +%D +%D \plaatsformule +%D \startformule +%D \eqalign +%D {D & = s_x s_y - r_x r_y \cr +%D s_x^\prime & = s_y / D \cr +%D s_y^\prime & = s_x / D \cr +%D r_x^\prime & = - r_x / D \cr +%D r_y^\prime & = - r_y / D \cr +%D t_x^\prime & = ( - s_y t_x + r_y t_y ) / D \cr +%D t_y^\prime & = ( r_x t_x - s_x t_y ) / D \cr} +%D \stopformule +%D +%D And you can see that when expanded out, this does +%D give the formulas: +%D +%D \plaatsformule +%D \startformule +%D P_x^\prime = { { s_y(p_x-t_x) + r_y(t_y-p_y) } \over +%D { s_x*s_y-r_x*r_y } } +%D \stopformule +%D +%D \plaatsformule +%D \startformule +%D P_y^\prime = { { s_x(p_y-t_y) + r_x(t_x-p_x) } \over +%D { s_x*s_y-r_x*r_y } } +%D \stopformule +%D +%D The code works by representing a real number by converting +%D it to a dimension to be put into a \DIMENSION\ register: 2.3 would +%D be represented as 2.3pt for example. In this scheme, +%D multiplying two numbers involves multiplying the \DIMENSION\ +%D registers and dividing by 65536. Accuracy demands that the +%D division be done as late as possible, but overflow +%D considerations need early division. +%D +%D Division involves dividing the two \DIMENSION\ registers and +%D multiplying the result by 65536. Again, accuracy would +%D demand that the numerator be multiplied (and|/|or the +%D denominator divided) early: but that can lead to overflow +%D which needs to be avoided. +%D +%D If nothing is known about the numbers to start with (in +%D concat), I have chosen to divide the 65536 as a 256 in each +%D operand. However, in the series calculating the sine and +%D cosine, I know that the terms are small (because I never +%D have an angle greater than 45 degrees), so I chose to +%D apportion the factor in a different way. +%D +%D \stop +%D +%D The path is output using the values saved on the stack. If +%D needed, all coordinates are recalculated. + +\def\processMPpath% + {\flushMPpath + \closeMPpath + \PDFcode{\ifcase\finiMPpath W n\or S\or f\or B\fi}% + \let\handleMPsequence=\dohandleMPsequence + \resetMPstack + \nofMPsegments=0 + \handleMPsequence} + +%D In \PDF\ the \type{cm} operator must precede the path +%D specification. We therefore can output the \type{cm} at +%D the moment we encounter it. + +\def\handleMPpathconcat% + {\presetMPconcat + \PDFcode{\gMPs1 \gMPs2 \gMPs3 \gMPs4 \gMPs5 \gMPs6 cm}% + \resetMPstack} + +\def\handleMPpathscale% + {\presetMPscale + \PDFcode{\gMPs1 0 0 \gMPs2 0 0 cm}% + \resetMPstack} + +%D This macro interprets the path and saves it as compact as +%D possible. + +\def\dohandleMPpath#1#2 % + {\ifnum\lccode`#1=0 + \setMPargument{#1#2}% + \else + \def\somestring{#1#2}% + \ifx\somestring\PSlineto + \setMPkeyword0 + \else\ifx\somestring\PScurveto + \setMPkeyword1 + \else\ifx\somestring\PSrlineto + \setMPkeyword2 + \else\ifx\somestring\PSmoveto + \setMPkeyword3 + \else\ifx\somestring\PSclip + \let\handleMPsequence=\processMPpath + \else\ifx\somestring\PSgsave + \chardef\finiMPpath=3 + \else\ifx\somestring\PSgrestore + \else\ifx\somestring\PSfill + \ifnum\finiMPpath=0 + \chardef\finiMPpath=2 + \let\handleMPsequence=\processMPpath + \fi + \else\ifx\somestring\PSstroke + \ifnum\finiMPpath=0 + \chardef\finiMPpath=1 + \fi + \let\handleMPsequence=\processMPpath + \else\ifx\somestring\PSclosepath + \def\closeMPpath{\PDFcode{h}}% + \else\ifx\somestring\PSconcat + \let\flushMPpath=\flushconcatMPpath + \handleMPpathconcat + \else\ifx\somestring\PSscale + \let\flushMPpath=\flushconcatMPpath + \handleMPpathscale + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi + \handleMPsequence} + +%D The main conversion command is +%D +%D \starttypen +%D \convertMPtoPDF {filename} {x scale} {y scale} +%D \stoptypen +%D +%D The dimensions are derived from the bounding box. So we +%D only have to say: +%D +%D \starttypen +%D \convertMPtoPDF{mp-pra-1.eps}{1}{1} +%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5} +%D \stoptypen + +\def\processMPtoPDFfile% file xscale yscale + {\bgroup + \let\finishMPgraphic=\egroup + \doprocessMPtoPDFfile} + +\ifx\deleteMPgraphic\undefined + \def\deleteMPgraphic#1{} +\fi + +\def\doprocessMPtoPDFfile#1#2#3% file xscale yscale + {\setMPspecials + \catcode`\^^M=\@@endofline + \startMPscanning + \let\do=\empty + \xdef\MPxscale{#2}% + \xdef\MPyscale{#3}% + \donefalse + \let\handleMPsequence=\dohandleMPsequence + \message{[MP to PDF #1]}% + \input#1\relax + \deleteMPgraphic{#1}} + +\def\convertMPtoPDF#1#2#3% + {\bgroup + \setbox0=\vbox\bgroup + \forgetall + \offinterlineskip + \PDFcode{q}% + \doprocessMPtoPDFfile{#1}{#2}{#3}} + +\def\finishMPgraphic% + {\PDFcode{Q}% + \egroup + \wd0=\MPwidth + \vbox to \MPheight + {\forgetall + \vfill + \PDFcode{q \MPxscale\space 0 0 \MPyscale\space + \MPxoffset\space \MPyoffset\space cm}% + \box0 + \PDFcode{Q}}% + \egroup} + +%D \macros +%D {twodigitMPoutput} +%D +%D We can limit the precission to two digits after the comma +%D by saying: +%D +%D \starttypen +%D \twodigitMPoutput +%D \stoptypen +%D +%D This option only works in \CONTEXT\ combined with \ETEX. + +\def\twodigitMPoutput% + {\let\!MP\twodigitrounding} + +\def\!MP#1{#1} + +%D This kind of conversion is possible because \METAPOST\ +%D does all the calculations. Converting other \POSTSCRIPT\ +%D files would drive both me and \TEX\ crazy. + +\protect + +\endinput |