diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/exptl/graphicp |
Initial commit
Diffstat (limited to 'macros/latex/exptl/graphicp')
23 files changed, 6283 insertions, 0 deletions
diff --git a/macros/latex/exptl/graphicp/descend.1 b/macros/latex/exptl/graphicp/descend.1 new file mode 100644 index 0000000000..68d10eee40 --- /dev/null +++ b/macros/latex/exptl/graphicp/descend.1 @@ -0,0 +1,23 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: -6 -29 29 29 +%%Creator: MetaPost +%%CreationDate: 2002.12.24:2244 +%%Pages: 1 +%%EndProlog +%%Page: 1 1 +%%HiResBoundingBox: -5.25 -28.25 28.59645 28.25 + 0 0.5 dtransform truncate idtransform setlinewidth pop [] 0 setdash + 1 setlinejoin 10 setmiterlimit +newpath -5 -28 moveto +28.34645 -28 lineto +-5 28 lineto + closepath stroke + 1 setlinecap +newpath 11.67323 -28 moveto +-5 28 lineto stroke +newpath 11.67322 0 moveto +-5 -28 lineto stroke +newpath -5 0 moveto +28.34645 -28 lineto stroke +showpage +%%EOF diff --git a/macros/latex/exptl/graphicp/descend.mp b/macros/latex/exptl/graphicp/descend.mp new file mode 100644 index 0000000000..193612a443 --- /dev/null +++ b/macros/latex/exptl/graphicp/descend.mp @@ -0,0 +1,34 @@ +% +% descend.mp -- a MetaPost figure that descends far below the baseline +% by pts@fazekas.hu at Wed Feb 5 00:28:41 CET 2003 +% + +% input plain; + +% message jobname; + +extra_endfig := extra_endfig + & "special (" + & ditto & "%%HiResBoundingBox: " & ditto + & "&decimal xpart llcorner currentpicture &" & ditto & " " & ditto + & "&decimal ypart llcorner currentpicture &" & ditto & " " & ditto + & "&decimal xpart urcorner currentpicture &" & ditto & " " & ditto + & "&decimal ypart urcorner currentpicture );"; + +prologues:=2; % 2 == TeX + +%beginfig(-1) +beginfig(1) +%string extra_endfig; + %boxit a (btex Essai etex); + %fill bpath a witchcolor .5[red,white]; + %drawboxed(a); + pair A, B, C; + A:=(-5bp,-28bp); B:=(1cm,-28bp); C:=(-5bp,28bp); + draw A--B--C--cycle; + draw 1/2[A,B] -- C; + draw 1/2[B,C] -- A; + draw 1/2[C,A] -- B; +endfig; + +end; diff --git a/macros/latex/exptl/graphicp/div16b.sty b/macros/latex/exptl/graphicp/div16b.sty new file mode 100644 index 0000000000..523fa75026 --- /dev/null +++ b/macros/latex/exptl/graphicp/div16b.sty @@ -0,0 +1,490 @@ +% +% div16.tex -- perform 16.16 bit fixed point division +% by pts@fazekas.hu at Fri Dec 27 22:40:52 CET 2002 --- ... +% +% This .tex file contains TeX macros for double precision multiplication, +% division of integer and real numbers and image size scaling. The most +% remarkable macro in this file is \@@muldivletposdim (see the comments in +% front of it for detailed documentation). +% +% If you process this file with +% Plain TeX, the unit regression testsuite will be run, and the results of +% the operations issued at the end of this file will be printed to the +% terminal and into the .log file. +% +% The documentation of this macro package is scattered through this file as +% embedded TeX comments. +% +% History +% ~~~~~~~ +% started at Fri Dec 27 22:40:52 CET 2002 +% --- Sat Dec 28 01:26:52 CET 2002 +% 31.31 bit arithmetic: Tue Jan 7 18:12:53 CET 2003 +% skippable, partial \@@muldivpos at Tue Jan 7 21:00:17 CET 2003 +% skippable, finished, doesn't work at Tue Jan 7 21:43:25 CET 2003 +% first successful test case at Tue Jan 7 22:34:32 CET 2003 +% all test cases OK at Tue Jan 7 23:30:32 CET 2003 +% Fri Jan 24 12:56:23 CET 2003 +% uses laemu.sty +% + +\expandafter\ifx\csname ifLaTeX\endcsname\relax\input laemu.sty\relax\fi% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{div16b}[2003/01/24 v0.0 high precision div and mul] + +% +% SUXX: `\count0=2\count1' and `\advance\count0 by 2\count1' disallowed +% Dat: `\count0=-\count1' and `\advance\count0 by -\count1' OK +% +% Imp: @@ namespace +% + +% \def\@empty{} % from laemu.sty +% \catcode`\@=11 % \makeatletter + +%\def\loop#1\repeat{% +% \def\iterate{#1\relax\expandafter\iterate\fi}% +% \iterate \let\iterate\relax% +%}% +%\let\repeat\fi% + +% vvv so we can nest a \@@loop inside \loop or vica versa +\def\@@loop#1\@@repeat{% + \def\@@iterate{#1\relax\expandafter\@@iterate\fi}% + \@@iterate \let\@@iterate\relax% +}% +\let\@@repeat\fi% + +%\repeat +%alma +%\iftrue +%korte +%\loop + +\def\@@gobbleend#1\end{}% + +%** `\@@aftergroupbegin ... \end' types `...' token-by-token \aftergroup +%** Argument of \@@aftergroupbegin must not contain \end, {, or } +\def\@@aftergroupbegin#1{% + \ifx#1\end% + %\message{done} + \else% + %\message{\string#1}% + \aftergroup#1% + \expandafter\@@aftergroupbegin% + \fi% +}% + +%** Doesn't make a \global assignment to #1, but keeps its value after the +%** the next `}'. +%** @param #1 name of a \count, \dimen or \skip register (i.e \count0 or +%** \jot) +\def\@@noresetaftergroup#1{% + \@@aftergroupbegin#1=\end% + \expandafter\@@aftergroupbegin\the#1 \end% + % ^^^ The space before \end is required, because in LaTeX, \end is expandable + \aftergroup\relax% finish assignment +}% +%** Doesn't work if the definition of #1 contains strange tokens +%** @param #1 a macro \cs name +\def\@@keepdefaftergroup#1{% + \aftergroup\def% + \aftergroup#1% + \aftergroup{% + \expandafter\@@aftergroupbegin#1\end% + \aftergroup}% +}% + +%** Performs the `#1 := #2' assignment, avoids `Dimension too large' error if +%** both #1 and #2 are \counts. +%** @param #1 a \count or \dimen register specification +%** @param #2 a \count or \dimen register specification, an integer, a real +%** number or a dimension. Numbers are assumed to have unit `sp'. +\def\@@letdimcount#1#2{{% + \afterassignment\@@letdimcount@a\count0=#2 \end% + % Dat: now \@@letdimcount@c contains any of "", "sp", ".45", ".45pt" + \afterassignment\@@gobbleend\dimen0=1\@@letdimcount@c sp \end% "1", "1sp" "1.45sp" "1.45pt" + % Dat: 1.99999999sp == 1sp + \ifdim\dimen0=1sp% + %\showthe\count0 \message{\the\count0-sp}% + \afterassignment\@@gobbleend#1=\count0 sp \end% + \else% + \afterassignment\@@gobbleend\dimen0=#2 sp \end% + \afterassignment\@@gobbleend#1=\dimen0 sp \end% + \fi% + \@@noresetaftergroup{#1}% return(\T) +}}% +\def\@@letdimcount@a#1\end{\def\@@letdimcount@c{#1}}% +%** Performs the `#1 := #2' assignment, doesn't avoid `Dimension too large' +%** error if both #1 and #2 are \counts. +%** `\@@letdimcount#1#2' is the same as `\@@letdimcountany#1#2{sp}', but +%** \@@letdimcount avoids the error. +%** @param #1 a \count or \dimen register specification +%** @param #2 a \count or \dimen register specification, an integer, a real +%** number or a dimension. Numbers are assumed to have unit `#3'. +%** @param #3 default metric unit +\def\@@letdimcountany#1#2#3{{% + \afterassignment\@@letdimcount@a\dimen0=#2 #3 bp\end% + #1=\dimen0% + \@@noresetaftergroup{#1}% return(\T) +}}% + +\iffalse +% Regression test for \@@letdimcount: +\@@letdimcount{\count0}{2147483647} \message{\the\count0} +\@@letdimcount{\count0}{2147483647sp} \message{\the\count0} +\@@letdimcount{\count0}{2147483647.0sp} \message{\the\count0} +\@@letdimcount{\count0}{2147483647.999999sp} \message{\the\count0} +\@@letdimcount{\count0}{16383.99999pt} \message{\the\count0} +\@@letdimcount{\dimen0}{16383.99999pt} \message{\the\dimen0} +%\@@letdimcount{\count0}{16384pt} % Dimension too large. +%\@@letdimcount{\dimen0}{2000000000} % Dimension too large. +\@@letdimcount{\dimen0}{\count0} \message{\the\dimen0} +\fi + +% --- + +% !! why no \space in \write? +%** Performs the assignment `#1 := \dimen0 / \dimen1', +%** @param #1 is a name of a TeX dimen/count register (i.e \jot or \count7). +%** If dimen, then it contains quotient in dimension `pt' (i.e 1in / 1cm +%** is 2.54pt). If count, then its value divided by 65536 is the quotient +%** (so this is 16.16 bit fixed-point notation). +%** \dimen0 must not be negative. \dimen1 must be positive. +%** Overwrites \dimen2. +\def\@@divletpos#1{% + \dimen2=1pt\relax% + \multiply#1 0% `#1 := 0' works for both \dimen and \count registers + \loop\ifdim\dimen0>0pt% + \immediate\write16{0 a=\the\dimen0:b=\the\dimen1:m=\the\dimen2:q=\the#1} + \@@loop\ifdim\dimen1<0.5\dimen0% + \advance\dimen1\dimen1% + \advance\dimen2\dimen2% + % ^^^ this is the only statement where an arithmetic overflow can occur. + % an arithmetic overflow means that the divisor is zero is very + % small positive, so the result will be a ``dimen too large'' + \@@repeat% + \immediate\write16{1 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1} + \@@loop\ifdim\dimen1>\dimen0% + \divide\dimen1 2% + \divide\dimen2 2% + \ifdim\dimen2=0pt% + \dimen0\dimen2% + \dimen1\dimen2% + \fi% + \@@repeat% + \immediate\write16{2 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1} + \ifdim\dimen0>0pt% + \@@loop\ifdim\dimen0<8192pt% + \multiply\dimen0 2% + \multiply\dimen1 2% + \@@repeat% + \fi% + \immediate\write16{3 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1} + \advance\dimen0-\dimen1% + \advance#1\dimen2% + % ^^^ Dat: because of this, \dimen2 must be a dimen (and not a count) + \immediate\write16{4 a=\the\dimen0\space b=\the\dimen1\space m=\the\dimen2\space q=\the#1} + \repeat% + %\ifdim\dimen0>0pt \message{SUXX}\fi% +}% + +%** The same as \@@divletpos, except for #2 and #3 may be either positive or +%** negative, and they might be either dimen or count registers. (A count is +%** measured in sp.) +%** Please don't pass \dimen0, \dimen1 or \dimen2 as argument. +%** @param #1 is a name of a TeX dimen/count register (i.e \jot or \count7). +%** If dimen, then it contains quotient in dimension `pt' (i.e 1in / 1cm +%** is 2.54pt). If count, then its value divided by 65536 is the quotient +%** (so this is 16.16 bit fixed-point notation). +%** @param #2 and #3 are token lists +%** containing a _positive_ integer or floating point value +%** (measured in sp, must be specified explicitly), or a dimen such as `2.54cm'. +\def\@@divletdim#1#2#3{{% + \afterassignment\@@gobbleend\dimen0=#2 sp\end% \dimen0 := #1, convert count -> sp + \afterassignment\@@gobbleend\dimen1=#3 sp\end% + \ifdim\dimen1=0pt% + \divide\dimen0 by0% trigger a TeX division-by-zero error + \else% + \ifdim\dimen1<0pt% + \dimen1-\dimen1% + \ifdim\dimen0<0pt% + \dimen0-\dimen0% + \@@divletpos{#1}% + \else + \@@divletpos{#1}% + #1-#1% + \fi% + \else% + \ifdim\dimen0<0pt% + \dimen0-\dimen0% + \@@divletpos{#1}% + #1-#1% + \else + \@@divletpos{#1}% + \fi% + \fi% + \fi% + % Imp: round to nearest integer + \@@noresetaftergroup{#1}% +}}% + +% --- Dobule (high) precision multiplication and division. + +% The type co31.31 denotes two \count registers, representing a nonnegative +% value in 31.31 bit fixed point notation. The sign bits of the registers +% are unused. + +%** Subtracts #3#4 from #1#2, modifies #1#2 in place +%** @param #1 \control-sequence on less +%** @param #2 \control-sequence on greater-or-equal +%** @param #3#4 co31.31 +%** @param #5#6 co31.31 +\def\@@dolt#1#2#3#4#5#6{% + \ifnum#3<#5% + \expandafter#1% + \else% + \ifnum#3>#5% + \expandafter#2% + \else% + \ifnum#4<#6% + \expandafter#1% + \else% + \expandafter#2% + \fi% + \fi% + \fi% +}% + +%** Subtracts #3#4 from #1#2, modifies #1#2 in place +%** @param #1#2 co31.31 +%** @param #3#4 co31.31 +\def\@@letsub#1#2#3#4#5{% + \ifnum#2<#4% + \advance#1-1% + \advance#2-#4% + \advance#2-#5% #2 += 0x80000000 + \else% + \advance#2-#4% + \fi% + \advance#1-#3% +}% + +%** Adds #3#4 to #1#2, modifies #1#2 in place +%** @param #1#2 co31.31 +%** @param #3#4 co31.31 +%** @param #5 \countx, whose value is -0x80000000 (-2147483648) +\def\@@letadd#1#2#3#4#5{% + % \message{add:\the#3:\the#4}% + \advance#2#5% #2 -= 0x80000000 + \ifnum#2<-#4% orig#2-0x80000000<-#4 <=> orig#2+#4 < 0x80000000 + \advance#2-#5% #2 += 0x80000000 + \else% + \advance#1 1% + \fi% + \advance#2#4% + \advance#1#3% +}% + +%** Multiplies #1#2 by two, modifies #1#2 in place +%** @param #1#2 co31.31 +\def\@@lettwice#1#2{% + \advance#1#1% + \ifnum#2>1073741823% + \advance#1 1% + \advance#2-1073741824% + \fi% + \advance#2#2% +}% + +%** Divides #1#2 by two, discards LSB, modifies #1#2 in place +%** @param #1#2 co31.31 +\def\@@lethalf#1#2{% + \divide#2 2% + \ifodd#1% + \advance#2 1073741824% + \fi% + \divide#1 2% +}% + +% vvv SUXX: \newif is `\outer' +\newif\ifLOOP +% \def\x{ \expandafter\newif\csname ifLOOP\endcsname}% + +%** `\@@muldivletposdim#1#2#3#4' performs the assignment `#1 := #2 * #3 / #4'. +%** `\@@muldivletposdim#1{1pt}#3#4' performs the assignment `#1 := #3 / #4'. +%** `\@@muldivletposdim#1#2#3{1pt}' performs the assignment `#1 := #2 * #3'. +%** +%** All source arguments (#2, #3, #4) can be valid TeX dimen/count values, or +%** \dimen / \count register specifications. Input values may be negative or +%** positive or zero. +%** +%** -- Before each multiplication and division, the arguments are converted +%** to `pt' (if the argument is a bare number or a \count register, it is +%** treated as being a dimension in `sp'), the operation is performed on +%** the numbers, and `pt' is added +%** to the resulting number, so the result will be a dimension. +%** -- The default unit of measure is `sp'. That is, all bare numbers and +%** \count registers are treated as being a dimension in `sp'. This +%** applies to both source and target argument. (You may notice that 1pt +%** == 65536sp. So the operations are performed in a fixed-point +%** arithmetic with 16 bits in the fraction.) +%** -- The multiplication is performed exactly (i.e without loss of +%** precision). However, the division and the 31.31 -> 15.16 rounding +%** after the division may degrade precision. Internal calculations are +%** performed in fixed-point arithmetic with 31 bits in the fraction. +%** -- The following constants are valid source arguments, and represent the +%** same number (one and a half): `1.5pt', `98304sp', `98304 sp', +%** `98304', `98304.1sp', `98304.9sp'. +%** -- To specify the real number `1.5', please specify `1.5 pt'. +%** -- To specify the integer `42', please specify `42 pt'. +%** -- If you do only division, set #2 := `1pt'. In that special case you may +%** specify bare integers (or `... sp') for _both_ #3 and #4. +%** -- The following are valid arguments: `\count0', +%** `\dimen7', `\jot', `\interdisplaylinepenalty' +%** -- Due to a limitation of TeX's fixed-precision arithmetic, it is +%** impossible to specify exactly `1.5pt' in inches. `0.02075958251953in' +%** is `1.49974pt', and `0.02075958251954in' is `1.50084pt'. (Of course, +%** `1.5pt' is `1.5pt'.) That's because TeX converts the real constant +%** 0.02075958251953 to the fraction `1360/65536' and +%** 0.02075958251954 to the fraction `1361/65536', before multiplying. +%** -- If you specify >=2 of \dimen0, \dimen1 and \dimen2 as input, please +%** specify them in this order. +%** +%** @param #1 target, must be a \dimen or \count register +%** specification (including `\count0' and `\jot'). If a \dimen register, +%** its maximum will be 1073741823sp. If a \count register, its maximum +%** will be 2147483647. +%** @param #2 must be >=0 +%** @param #3 must be >=0 +%** @param #4 must be >0 +%** +\def\@@muldivletposdim#1#2#3#4{{% + %\afterassignment\@@gobbleend\dimen0=#2 sp\end% \dimen0 := #1, convert count -> sp + %\afterassignment\@@gobbleend\dimen1=#3 sp\end% + %\afterassignment\@@gobbleend\dimen2=#4 sp\end% + \countdef\Y 2 \@@letdimcount\Y{#4}% + \countdef\F 14 \ifnum\Y<0 \Y-\Y \F-1 \else \F1 \fi% +% \showthe\Y% + \ifnum0=\Y % SUXX: \ifnum\Y=0 doesn't work + \divide\Y0% trigger a TeX division-by-zero error (`arithmetic overflow') + \else% + % vvv declare my input arguments as local variables + \countdef\XA 0 \@@letdimcount\XA{#2}% treat dimen as in `sp' + \ifnum\XA<0 \XA-\XA \F-\F\fi% + \countdef\XB 1 \@@letdimcount\XB{#3}% + \ifnum\XB<0 \XB-\XB \F-\F\fi% + %\countdef\XA 0 \XA\dimen0% treat dimen as in `sp' + %\countdef\XB 1 \XB\dimen1% + %\countdef\Y 2 \Y \dimen2% + % vvv declare local variables + \countdef\C 3% + \countdef\B 4% + \countdef\R 5% + \countdef\S 6% + \countdef\T 7% + \countdef\U 8% + \countdef\D 9% + \countdef\A 10% + \countdef\L 11% + \countdef\M 12% + % vvv ++++ comment out the line below to get rid of the error ++++ + \countdef\G 13 \relax \G-1073741824 \advance\G\G% G := -0x80000000 + % + % Imp: support negative numbers here + \ifnum\XB=\Y% shortcut + \T\XA% + \else% + \ifnum\XA=\Y% shortcut + \T\XB% + \else% really multiply and divide + \@@muldivpos% + % + % vvv convert (round) \T\U: co31.31 -> \T: dimen15.16 + % return (\U>=0x7fffc000) ? ((\T+1)<<16) : (\T<<16)+((\U+0x4000)>>15) + \multiply\T65536% result too large + \ifnum\U<2147467264% 0x80000000-0x4000 + \advance\U16384% + \divide\U32768% + \advance\T\U% + \else% + \advance\T65536% + \fi% + \fi% + \fi% + \ifnum\F<0 \T-\T\fi% + %\afterassignment\@@gobbleend#1=\T sp\end% works if #1 is a dimen/count + \@@letdimcount{#1}\T% + \@@noresetaftergroup{#1}% return(\T) + \fi% else of division-by-zero +}}% + +%** Performs the assignment `\T\U := \XA * \XB / \Y'. Destroys contents of +%** \XA \XB \Y \C \B \R \S \T \U \D \A \L and \M during operations. All +%** control sequences mentioned in this paragraph must be predefined \count +%** registers. +%** Assumes \newif\LOOP, sets \LOOPfalse upon return +%** Inputs are: \XA \XB \Y and \G. \XA \XB \Y must be in 15.16 bit +%** fixed-point notation (i.e dimension in `pt' converted to a \count). +%** \G must be -0x80000000. +%** Outputs are \T and \U. \T\U is a real number in 31.31 bit fixed-point +%** notation (the sign bits are unused). +%** This is helper routine called by \@@muldivletposdim. +\def\@@muldivpos{% + %\message{A}% + \R\XA \divide\R65536 \S-\R \multiply\S65536 \advance\S\XA% my(\R,\S)=(( \XA >>16), \XA &0xffff); + %\message{A.S=\the\S,R=\the\XA}% + \T\XB \divide\T65536 \U-\T \multiply\U65536 \advance\U\XB% my(\T,\U)=(( \XB >>16), \XB &0xffff); + \D0 \A\Y \divide\A65536 \multiply\A32768 % my (\D,\A)=(0, ((( \Y >>16)&0xffff)<<15)); % round() final result + \L\R \advance\L\L \multiply\L\T \M0 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), ((\R*\T)<<1, 0) + \L\R \multiply\L\U \M\L \divide\L32768 \multiply\L32768 \advance\M-\L \divide\L32768 \multiply\M65536 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), ((\R*\U)>>15, ((\R*\U)&0x7fff)<<16) + \L\S \multiply\L\T \M\L \divide\L32768 \multiply\L32768 \advance\M-\L \divide\L32768 \multiply\M65536 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), ((\S*\T)>>15, ((\S*\T)&0x7fff)<<16) + \ifnum\S>32767 % + \L0 \M\U \multiply\M32768 \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), (0, \U<<15) + \advance\S-32768% + \fi% + %\message{B.S=\the\S,U=\the\U}% + \L0 \M\S \multiply\M\U \@@letadd\D\A\L\M\G% \@@letadd( (\D,\A), (0, \S*\U) + \C\Y \divide\C 32768 \B-\C \multiply\B32768 \advance\B\Y \multiply\B65536 % my(\C,\B)=(( \Y >>15),(( \Y &0x7fff)<<16)); + \L1 \M0 \T0 \U0% my (\L,\M)=(1,0); (\T,\U)=(0,0); + %\showthe\D \showthe\A \showthe\C \showthe\B + %\message{C}% + \loop% vvv while (\D!=0 or \A!=0) % DA != 0 % \D!=0 <=> \D>0 + %\message{if}% + \LOOPfalse% + \ifnum\D>0 \LOOPtrue \fi% Dat: must have a space after `>0' + \ifnum\A>0 \LOOPtrue \fi% + \ifLOOP% loop condition + \R\D \S\A \@@lethalf\R\S% (\R,\S)=(\D,\A); _Half(\R,\S); + \@@loop% vvv while (_lt((\C,\B),(\R,\S))) % while (CB<DA/2) + %\message{ina}% + \@@dolt\LOOPtrue\LOOPfalse\C\B\R\S% + \ifLOOP% loop condition + \@@lettwice\C\B% + \ifnum\L=1073741824% Dat: \L\M is a power of 2 + \divide\L0% die "overflow or division by 0" if \L<0 + \fi% + \@@lettwice\L\M% + \@@repeat% + \@@loop% vvv while (_lt((\D,\A),(\C,\B))) + %\immediate\write16{D=\the\D:A=\the\A:C=\the\C:B=\the\B}% + %\message{inb}% + \@@dolt\LOOPtrue\LOOPfalse\D\A\C\B% + \ifLOOP% loop condition + \ifnum\D<1073741824 \@@lettwice\D\A \else \@@lethalf\C\B \fi% + \@@lethalf\L\M% + \ifnum0=\L \ifnum0=\M % + \D0 \A0% (\D,\A)=(0,0) if \L==0 and \M==0; + \B0 \C0% + \fi\fi% + \@@repeat% + \@@letsub\D\A\C\B\G% + \@@letadd\T\U\L\M\G% + \repeat% + \ifnum\T>32767\divide\T0\fi% die "overflow2 or division by 0" if \T>=0x8000 + % ^^^ !! Imp: more meaningful overflow error message (here and at other places) + % return value: \T\U: co31.31 + % to convert it to \dimen, do: (\U>=0x7fffc000) ? ((\T+1)<<16) : (\T<<16)+((\U+0x4000)>>15) +}% + +\endinput% diff --git a/macros/latex/exptl/graphicp/epstopdf b/macros/latex/exptl/graphicp/epstopdf new file mode 100755 index 0000000000..f7b5b1675c --- /dev/null +++ b/macros/latex/exptl/graphicp/epstopdf @@ -0,0 +1,476 @@ +#! /bin/sh +eval '(exit $?0)' && eval 'PERL_BADLANG=x;export PERL_BADLANG;: \ +;exec perl -x -S -- "$0" ${1+"$@"};#'if 0; +eval 'setenv PERL_BADLANG x;exec perl -x -S -- "$0" $argv:q;#'.q +#!perl -w ++($0=~/(.*)/s);do$1;die$@if$@;__END__+if 0; +# Don't touch/remove lines 1--7: http://www.inf.bme.hu/~pts/Magic.Perl.Header + +use strict; + +# Change by Thomas Esser, Sept. 1998: The above lines allows us to find +# perl along $PATH rather than guessing a fixed location. The above +# construction should work with most shells. +# Modified by pts@fazekas.hu at and before Sun Feb 2 12:57:10 CET 2003 + +# A script to transform an EPS file so that: +# a) it is guarenteed to start at the 0,0 coordinate +# b) it sets a page size exactly corresponding to the BoundingBox +# This means that when Ghostscript renders it, the result needs no +# cropping, and the PDF MediaBox is correct. +# c) the result is piped to Ghostscript and a PDF version written +# +# -- It needs a Level 2 PS interpreter. +# -- If the bounding box is not right, of course, you have problems... +# -- BoundingBox: (atend) is perfectly supported. +# -- recommended options: --below --hires +# +# Sebastian Rahtz, for Elsevier Science +# +# now with extra tricks from Hans Hagen's texutil. +# +# History +# 1999/05/06 v2.5 (Heiko Oberdiek) +# * New options: --hires, --exact, --filter, --help. +# * Many cosmetics: title, usage, ... +# * New code for debug, warning, error +# * Detecting of cygwin perl +# * Scanning for %%{Hires,Exact,}BoundingBox. +# * Scanning only the header in order not to get a wrong +# BoundingBox of an included file. +# * (atend) supported. +# * uses strict; (earlier error detecting). +# * changed first comment from '%!PS' to '%!'; +# * corrected (atend) pattern: '\s*\(atend\)' +# * using of $bbxpat in all BoundingBox cases, +# correct the first white space to '...Box:\s*$bb...' +# * corrected first line (one line instead of two before 'if 0;'; +# 2000/11/05 v2.6 (Heiko Oberdiek) +# * %%HiresBoundingBox corrected to %%HiResBoundingBox +# 2001/03/05 v2.7 (Heiko Oberdiek) +# * Newline before grestore for the case that there is no +# whitespace at the end of the eps file. +# 2003/02/02 (Szabó Péter) +# * option --below +# * removes DOS EPSF binary junk correctly +# * adds all 3 BoundingBox DSC comments +# * reads all 3 BoundingBox DSC comments, and picks the best +# * forces BoundingBox to be an integer +# * adds %%EndComments and proper %!PS-Adobe-?-? EPSF-?.? header +# * adds %%Pages: +# +# Dat: calling ``showpage'' is not required, gs 6.50 works without it +# Imp: detect error messages from GS, abort... +# Imp: make it work for PDF input +# Imp: make it work for PS non-EPS files + +### program identification +my $program = "epstopdf"; +my $filedate="2003/02/02"; # my $filedate="2001/03/05"; +my $fileversion="2.7p"; +my $copyright = "Copyright 1998-2001 by Sebastian Rahtz et al.\nContains modifications by pts\@fazekas.hu"; +my $title = "\U$program\E $fileversion, $filedate - $copyright\n"; + +### ghostscript command name +my($quote,$GS)=("'","gs"); +($quote,$GS) = ("\"","gswin32c") if $^O eq 'MSWin32' or $^O =~ /cygwin/i; + +### options +$::opt_help=0; +$::opt_debug=0; +$::opt_compress=1; +$::opt_gs=1; +$::opt_hires=0; +$::opt_exact=0; +$::opt_filter=0; +$::opt_outfile=""; +$::opt_below=0; + +### usage +my @bool = ("false", "true"); +my $usage = <<"END_OF_USAGE"; +${title}Syntax: $program [options] <eps file> +Options: + --help: print usage + --outfile=<file>: write result to <file> + --(no)filter: read standard input (default: $bool[$::opt_filter]) + --(no)gs: run Ghostscript to create PDF (default: $bool[$::opt_gs]) + --(no)compress: use compression (default: $bool[$::opt_compress]) + --(no)hires: scan HiResBoundingBox (default: $bool[$::opt_hires]) + --(no)exact: scan ExactBoundingBox (default: $bool[$::opt_exact]) + --(no)debug: debug informations (default: $bool[$::opt_debug]) + --(no)below: allow below baseline (default: $bool[$::opt_below]) +Examples for producing 'test.pdf': + * $program test.eps + * produce postscript | $program --filter >test.pdf + * produce postscript | $program -f -d -o=test.pdf +Example: look for HiResBoundingBox and produce corrected PostScript: + * $program -d --nogs -hires test.ps>testcorr.ps +END_OF_USAGE + +### process options +use Getopt::Long; +GetOptions ( + "help!", + "debug!", + "filter!", + "compress!", + "gs!", + "hires!", + "below!", + "exact!", + "outfile=s", +) or die $usage; + +### help functions +sub debug { + print STDERR "* @_\n" if $::opt_debug; +} +sub warning { + print STDERR "==> Warning: @_!\n"; +} +sub error { + die "$title!!! Error: @_!\n"; +} +sub errorUsage { + die "$usage\n!!! Error: @_!\n"; +} + +### option help +die $usage if $::opt_help; + +### get input filename +my $InputFilename = ""; +if ($::opt_filter) { + @ARGV == 0 or + errorUsage "Input file cannot be used with filter option"; + $InputFilename = "-"; + debug "Input file: standard input"; +} else { + @ARGV > 0 or errorUsage "Input filename missing"; + @ARGV < 2 or errorUsage "Unknown option or too many input files"; + $InputFilename = $ARGV[0]; + if ($ARGV[0] eq '-') { + $::opt_filter=1; + debug "Input file: standard input"; + } else { + -f $InputFilename or error "'$InputFilename' does not exist"; + debug "Input filename:", $InputFilename; + } +} + +### option compress +my $GSOPTS; +$GSOPTS = "-dUseFlateCompression=".($::opt_compress?"true":"false")." "; +# $GSOPTS.=" -r72 -g99999x99999 "; +$GSOPTS.=" -r72 -sPAPERSIZE=a4 "; # default +$GSOPTS.=" -dCompatibilityLevel=1.2"; + +### option BoundingBox types +#**** pts **** +# scan all of them and find the best +{ my $BBprint = "%%BoundingBox:"; + $BBprint = "%%HiResBoundingBox:" if $::opt_hires; + $BBprint = "%%ExactBoundingBox:" if $::opt_exact; + debug "strongest BoundingBox comment:", $BBprint; +} +my $BBregex='%%(Hi[Rr]es|Exact|)BoundingBox:'; + +### option outfile +my $OutputFilename = $::opt_outfile; +if ($OutputFilename eq "") { + if ($::opt_gs) { + $OutputFilename = $InputFilename; + if (!$::opt_filter) { + $OutputFilename =~ s/\.[^\.]*$//; + $OutputFilename .= ".pdf"; + } + } + else { + $OutputFilename = "-"; # standard output + } +} +if ($::opt_filter) { + debug "Output file: standard output"; +} +else { + debug "Output filename:", $OutputFilename; +} + +### option gs +if ($::opt_gs) { + debug "Ghostscript command:", $GS; + debug "Compression:", ($::opt_compress) ? "on" : "off"; +} + +### open input file +if ($::opt_filter) { + open(IN, "<&STDIN") or error "Cannot open standard input"; +} else { + open(IN,"< $InputFilename") or error "Cannot open '$InputFilename'"; +} +binmode IN; + + +#**** pts **** +sub read_error() { error "read $InputFilename: $!" } +my $bytes_left=-1; +#** @param $_[0] number of bytes to read, or undef to read a line +#** @return the string read +sub readIN(;$) { + my $S; + return "" if $bytes_left==0; + ## print STDERR "READ\n"; + if (defined $_[0]) { read_error if 0>read IN, $S, $_[0] } + else { + $S=<IN>; + read_error if !defined($S) and $!; + $S="" if !defined $S; + } + if ($bytes_left<0) { # unlimited + } elsif (length($S)>=$bytes_left) { + $S=substr($S, 0, $bytes_left); + $bytes_left=0; + } else { $bytes_left-=length($S) } + $S +} + +### scan first line, check for DOS eps (and remove DOS headers) +#**** pts **** +my $header=""; +$_=""; +{ my $S; + read_error if 0>read IN, $S, 1; + error "$InputFilename: empty file" if 0==length($S); + if ($S eq "\305") { # DOS EPSF header + read_error if 29>read IN, $S, 29, 1; + my ($eheader,$ps_ofs,$ps_len,$wmf_ofs,$wmf_len,$tif_ofs,$tif_len,$checksum)= + unpack"A4VVVVVVv", $S; + error "$InputFilename: bad DOS EPS" if $eheader ne "\305\320\323\306" or $ps_ofs<30; + my($ps_end, $wmf_end, $tif_end)=($ps_ofs+$ps_len, $wmf_ofs+$wmf_len, $tif_ofs+$tif_len); + $ps_ofs-=30; + if (!seek IN, $ps_ofs, 1) { + while ($ps_ofs>4096) { $ps_ofs-=4096; readIN 4096 } + read_in $ps_ofs if $ps_ofs>0; + } + $bytes_left=($ps_end>$wmf_end and $ps_end>$tif_end) ? -1 : $ps_len; + $S=readIN(1); + } + if ($S eq '%') { + $S.=readIN; + error "$InputFilename: won't read a PDF file" if substr($S,0,4)eq'%PDF'; + error "$InputFilename: EPS DSC must be %!PS-Adobe" if substr($S,0,4)ne'%!PS'; + # ^^^ Dat: mpost outputs "%!PS\n" + } else { + warning "$InputFilename: no PS ADSC header, BoundingBox not found\n" + } + $header=$S; +} + +### open output file +if ($::opt_gs) { + my $fn=$OutputFilename; + $fn=~s@'@\\'@g if $quote eq "'"; + my $pipe = "$GS -q -dBATCH -sDEVICE=pdfwrite $GSOPTS " . + "-sOutputFile=$quote$OutputFilename$quote -"; + debug "Ghostscript pipe:", $pipe; + open(OUT,"|$pipe") or error "Cannot open Ghostscript for piped input"; +} else { + open(OUT,"> $OutputFilename") or error "Cannot write '$OutputFilename"; +} +die unless binmode OUT; + +### variables and pattern for BoundingBox search +my $bbxpatt = '[0-9eE\.\-]'; + # protect backslashes: "\\" gets '\' +my $BBValues = "\\s*($bbxpatt+)\\s+($bbxpatt+)\\s+($bbxpatt+)\\s+($bbxpatt+)"; + +#** @return arg rounded down to int +sub floor($) { + # Dat: Perl int() rounds towards zero + $_[0] < 0 ? -int(-$_[0]) : int($_[0]) +} + +#** @return arg rounded up to int +sub ceil($) { + $_[0] > 0 ? -int(-$_[0]) : int($_[0]) +} + +my ($xoffset, $yoffset) = (0, 0); +my $do_translate=0; +#** @return PostScript code to be printed after the header +sub CorrectBoundingBox($$$$) { + my ($llx, $lly, $urx, $ury) = @_; + debug "Old BoundingBox:", $llx, $lly, $urx, $ury; + my ($width, $height) = ($urx - $llx, $ury - $lly); + ($xoffset, $yoffset) = (-$llx, -$lly); + # Dat: it is inherently impossible to tell GS that it shouldn't + # recompress the images already compressed in the EPS file, but keep + # them in their original, compressed form. So we rather instruct GS to + # recompress + my $pagedevice2set=" +/AutoRotatePages /None +/CompatibilityLevel 1.2 +/UseFlateCompression true +/AutoPositionEPSFiles false +/AutoFilterGrayImages false +/ConvertImagesToIndexed false +/DownsampleMonoImages false +/DownsampleGrayImages false +/DownsampleColorImages false +/AutoFilterColorImages false +/EncodeMonoImages true +/EncodeGrayImages true +/EncodeColorImages true +/AntiAliasMonoImages false +/AntiAliasGrayImages false +/AntiAliasColorImages false\n"; + + $::opt_below=0 if $lly>=0; + ($llx,$lly,$urx,$ury)=(0,0,$urx-$llx,$ury-$lly) if !$::opt_below; + my $bbx="%%BoundingBox: ".floor($llx)." ".floor($lly)." ". + ceil ($urx)." ".ceil ($ury)."\n". + "%%HiResBoundingBox: $llx $lly $urx $ury\n". + "%%ExactBoundingBox: $llx $lly $urx $ury\n%%EndComments\n"; + if ($::opt_below) { #**** pts **** + # vvv we output a second /MediaBox here, and we'll remove the first one + # (written by GS) later + return "$bbx<< /PageSize [$width $height] $pagedevice2set >> setpagedevice +mark /MediaBox [$llx $lly $urx $ury] /PAGE pdfmark +mark /CropBox [$llx $lly $urx $ury] /PAGE pdfmark\n"; + } + debug "New BoundingBox: 0 0", $width, $height; + debug "Offset:", $xoffset, $yoffset; + if ($xoffset==0 and $yoffset==0) { + return "$bbx<< /PageSize [$width $height] $pagedevice2set >> setpagedevice +mark /CropBox [0 0 $width $height] /PAGE pdfmark\n" + } + $xoffset=0 if $xoffset==0; # get rid of `-0' + $yoffset=0 if $yoffset==0; # get rid of `-0' + $do_translate=1; + "$bbx<< /PageSize [$width $height] $pagedevice2set >> setpagedevice +mark /CropBox [0 0 $width $height] /PAGE pdfmark +gsave $xoffset $yoffset translate\n" +} + +### scan header +if (1<length($header)) { + my($llx,$lly,$urx,$ury); + my($bbtype)='-'; # None + debug "Scanning header for BoundingBox"; + $header=~s@\r\n?\Z(?!\n)@@; + { my $headEPSF="EPSF-3.0"; + my $headPS="PS-Adobe-3.0"; + $headEPSF=$1 if $header=~s/\s+(EPSF-[.\d]+)$//; + $headPS=$1 if $header=~s/(PS-Adobe-[.\d+])$//; + print OUT "%!$headPS $headEPSF\n"; + } + my $BBCorrected=""; + my $do_atend=0; + my $had_pages=0; + my $doing_atend=0; + my $saved_pos; + my $saved_bytes_left; + read_again: while (length($_=readIN)) { + ## print STDERR "(($_))\n"; + ### end of header + if (!$doing_atend) { + if (/^%%EndComments/i) { last } + if (substr($_,0,2)ne'%%' or substr($_,0,5)eq'%%End') { $BBCorrected=$_; last } + } + + ### BoundingBox with values + if (/^$BBregex$BBValues/oi) { + if ($bbtype eq '-' + or $::opt_hires and $1 eq 'H' + or $::opt_exact and $1 eq 'E' + or $::opt_hires and $1 eq 'E' and $bbtype ne 'H' + or $::opt_exact and $1 eq 'H' and $bbtype ne 'E' + ) { + ($bbtype,$llx,$lly,$urx,$ury)=($1,$2+0,$3+0,$4+0,$5+0); + } + } elsif (/^$BBregex\s*\(atend\)/oi) { + ### BoundingBox with (atend) + debug "BoundingBox $1 (atend)"; + if ($::opt_filter) { + warning "Cannot look for BoundingBox in the trailer", + "with option --filter"; + } else { $do_atend=1 } + } elsif ($doing_atend) { + } elsif (/^%%Pages:/) { + print OUT; $had_pages=1; + } else { print OUT } + } + if ($doing_atend) { # already read (atend); restore file position + seek(IN, $saved_pos, 0) or error "Cannot go back to line `: (atend)'"; + $bytes_left=$saved_bytes_left; + } elsif ($do_atend) { # seek to near EOF and try again + error "Cannot leave line `: (atend)'" if ($saved_pos=tell IN)<0; + $saved_bytes_left=$bytes_left; + # vvv get the very last *BoundingBox entry from the last 4096 bytes + if ($bytes_left>4096) { + die unless seek(IN, $bytes_left-4096, 1); + $bytes_left=4096; + } elsif ($bytes_left<0) { + die unless seek(IN, -4096, 2); + } + $doing_atend=1; goto read_again; + } + print OUT "%%Pages: 1\n" if !$had_pages; + if ($bbtype ne'-') { print OUT CorrectBoundingBox $llx, $lly, $urx, $ury } + else { warning "BoundingBox not found"; print OUT "%%EndComments\n" } + print OUT $BBCorrected; +} + +### print rest of file +print OUT while length($_=readIN 4096); + +### close files +error "running gs" unless close(IN); +# ^^^ SUXX: gs always exit(0), if exists +print OUT "\ngrestore\n" if $do_translate; +close(OUT); + +if ($::opt_below and $::opt_gs) { + ### ****pts**** remove incorrect /MediaBox produced by gs + die unless open F, "> $OutputFilename.tgs"; # Imp: in temp dir + die unless print F ' + % this is temporary gs command file created by epstopdf + GS_PDF_ProcSet begin + pdfdict begin + FN (r) file pdfopen begin + % vvv keep file offsets, because `pdffindpageref` overrides it with contents + /OFT Objects 0 get dup length array copy def + % vvv Dat: the generation number is assumed to be 0 + % vvv Dat: modifies Objects[0] + 1 pdffindpageref 0 get + Objects 0 OFT put + readxrefentry === + currentdict pdfclose end end end + '; + die unless close F; + + my $offset=`$GS -dNODISPLAY -dSAFER -dBATCH -sFN=$quote$OutputFilename$quote -q $quote$OutputFilename.tgs$quote`; + chomp $offset; + unlink "$OutputFilename.tgs"; + die unless $offset=~/\A\d+\Z(?!\n)/; + # Dat: now $offsets is a file position in $OutputFilename containing our /Page object + + die unless open F, "+< $OutputFilename"; + die unless binmode F; + die unless seek F, $offset+=0, 0; + my $pageobj; + die unless 32<read F, $pageobj, 4096; + if ($pageobj=~m@\A(.*?/Type\s*/Page\b.*?)(/MediaBox\s*\[[^\]]*\]).*?/MediaBox@s) { + substr($pageobj, length($1), length($2))=" "x length($2); + # ^^^ overwrite first buggy /MediaBox definition with spaces + die unless seek F, $offset, 0; + die unless print F $pageobj; + debug "Below correction ($xoffset $yoffset) applied."; + } else { + debug "warning: double /MediaBox not found."; + } + die unless close F; +} + +debug "Ready."; diff --git a/macros/latex/exptl/graphicp/f2cletter.eps b/macros/latex/exptl/graphicp/f2cletter.eps new file mode 100644 index 0000000000..dad46ba7df --- /dev/null +++ b/macros/latex/exptl/graphicp/f2cletter.eps @@ -0,0 +1,35 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Pages: 1 +%%BoundingBox: 3 -10 23 20 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%EndComments +%%Page: 1 1 +save 26 dict begin +3 -10 translate +/x{load def}def/E/def x/A/currentfile x/c/exch x/i/ifelse x/S 32 E/D 0 E/C 0 E +/;/getinterval x/p/putinterval x/b/bitshift x/+/add x/O/pop x/*/mul x/u/dup x +/-/sub x/"/string x/?/length x/y/copy x{ +{mark A/ASCII85Decode filter/T exch def}stopped +/B exch def cleartomark B{{ +/d{{27 S ge{exit}if A read not{511}if u 122 eq{/S 27 E/D 0 E/C 0 E}{u 117 gt{ +A read{O}if/S 54 S - E}{u 33 ge{S 32 eq{u/C c E/D -1670420001 E}{u 117 -{1 85 +7225 614125}S 28 - get * D +/D c E}i/S S 1 - E}if}i}i O}loop S 22 eq{511}{C +1868977 * D + S 24 and neg b 23 S lt{C 3 * +}if 255 and/S S 3 eq{32}{S 7 mod 3 +eq{22}{S 8 -}i}i E}i}E +/B 90 " E/L 128 " E/Ex()E +20 30 1[1 0 0 -1 0 30]{B Ex{2 y ? c ? ge{2 y c ? 0 c ; 2 index y ? 2 y c +? c - ;/Ex c E O exit}{2 y c y O ? 2 y c ? c - ;}i d u 128 le{L c 0 c 1 + ; u ? +1 - 0 c 1 c{d 3 y put O O}for}{L c d c 257 c - 3 y 1 - -1 0{3 y c put O}for O O +c O 0 c ;}i}loop B}image +d O d O}bind exec}{ +/F T/RunLengthDecode filter def +20 30 1[1 0 0 -1 0 30]F image F closefile T closefile}i} +%%BeginData: +exec +2?<4HJbTeor%Q%d0Z3fBkPfG`IW4I6E9E7#kN6aA!-$irE9HA&kDjNE5&f\6E5VT-JbTcVqu?p#cg^ +^Bn-SS3nFAC)noO<l%J0)bkOA6OnGEgds$-"'~> +%%EndData +end restore showpage +%%Trailer +%%EOF diff --git a/macros/latex/exptl/graphicp/f2cletter.pdf b/macros/latex/exptl/graphicp/f2cletter.pdf Binary files differnew file mode 100644 index 0000000000..267f853dfa --- /dev/null +++ b/macros/latex/exptl/graphicp/f2cletter.pdf diff --git a/macros/latex/exptl/graphicp/f2mletter.eps b/macros/latex/exptl/graphicp/f2mletter.eps new file mode 100644 index 0000000000..3310d86cf4 --- /dev/null +++ b/macros/latex/exptl/graphicp/f2mletter.eps @@ -0,0 +1,23 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Pages: 1 +%%BoundingBox: -8 5 12 35 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%EndComments +%%Page: 1 1 +save 9 dict begin +-8 5 translate +{/T currentfile/ASCII85Decode filter def/DeviceGray setcolorspace +/F T/LZWDecode filter def +<</ImageType 1/Width 20/Height 30/BitsPerComponent +1/ImageMatrix[1 0 0 -1 0 30]/Decode +[0 1]/DataSource F>> image + F closefile T closefile} +%%BeginData: +exec +J,gVj":O-1_gW";&?&6mr,?_LU''V23[!QE2ujPXgR^+^M`KdZ'8.tF&-,=6:\K.On7Qu."RcSWc=h +9D4Pju]bFVrDGWu5t#Pe8V!<~> +%%EndData +end restore showpage +%%Trailer +%%EOF diff --git a/macros/latex/exptl/graphicp/f2mletter.pdf b/macros/latex/exptl/graphicp/f2mletter.pdf Binary files differnew file mode 100644 index 0000000000..4a78a6c166 --- /dev/null +++ b/macros/latex/exptl/graphicp/f2mletter.pdf diff --git a/macros/latex/exptl/graphicp/ficletter.jpg b/macros/latex/exptl/graphicp/ficletter.jpg Binary files differnew file mode 100644 index 0000000000..958f35809d --- /dev/null +++ b/macros/latex/exptl/graphicp/ficletter.jpg diff --git a/macros/latex/exptl/graphicp/ficletter.pbm b/macros/latex/exptl/graphicp/ficletter.pbm Binary files differnew file mode 100644 index 0000000000..13db3eddff --- /dev/null +++ b/macros/latex/exptl/graphicp/ficletter.pbm diff --git a/macros/latex/exptl/graphicp/ficletter.png b/macros/latex/exptl/graphicp/ficletter.png Binary files differnew file mode 100644 index 0000000000..6a803b1c91 --- /dev/null +++ b/macros/latex/exptl/graphicp/ficletter.png diff --git a/macros/latex/exptl/graphicp/files b/macros/latex/exptl/graphicp/files new file mode 100644 index 0000000000..1423b1331b --- /dev/null +++ b/macros/latex/exptl/graphicp/files @@ -0,0 +1,22 @@ +files +div16b.sty +graphicp.sty +keyvalx.sty +laemu.sty +pts_img.sty +pts_bbox.sty +descend.mp +descend.1 +laltest.tex +ficletter.pbm +f2cletter.eps +f2cletter.pdf +f2mletter.eps +f2mletter.pdf +ficletter.png +ficletter.jpg +laxtest.bbx +epstopdf +img_bbox.pl +pdfboxes.pl +graphicpdoc.tex diff --git a/macros/latex/exptl/graphicp/graphicp.sty b/macros/latex/exptl/graphicp/graphicp.sty new file mode 100644 index 0000000000..001aaad978 --- /dev/null +++ b/macros/latex/exptl/graphicp/graphicp.sty @@ -0,0 +1,407 @@ +% +% graphicp.tex -- a graphics.sty replacement for LaTeX and laemu.sty +% by pts@fazekas.hu at Fri Jan 24 13:26:22 CET 2003 +% +% GraphicP is a system that provides an easy, fast and reliable method for +% including external images into LaTeX and plain TeX documents. The +% \includegraphics macro of GraphicP is a drop-in replacement of the same +% command of LaTeX graphics.sty and graphicx.sty, but with many enhancements. +% Input images are ususally in EPS or PDF format. Drivers for xdvi, dvips, +% pdftex and dvipdfm are included. Perl scripts are provided for +% faster bounding box manipulations. +% +% This is version 0.12. +% +% Features over LaTeX `\usepackage{graphicx}': +% +% -- both plain TeX and LaTeX support +% -- specified width=... and height=... are strictly enforced, without rounding +% -- image scaling calculations are much more accurate +% -- works with `dvips -E' bounding-box calculations, even with buggy dvips +% 5.86e +% -- doesn't have to open the .eps file for reading the bbox +% -- xdvi doesn't forcibly crop (clip) the image to the bbox +% -- Below feature: allows the image descend below the baseline +% (supports depth, not only width and height) +% -- drop dependency on Perl, parse Adobe DSC comments in EPS files +% -- non-standard, quick, DSC-like parsing for special PDF files +% -- an enhanced `epstopdf' utility +% -- the `img_bbox.pl' utility +% -- the `pdfboxes.pl' utility +% -- voluntary clipping (cropping) +% -- all 8 mirror and rotate transformation (must be a multipe of 90 degrees) +% -- does not rely on the filename to determine the FileFormat +% -- embeds each image file only once with pdfTeX and dvipdfm +% -- imtrix: unified PSTricks/PSFrag support for EPS and PDF +% +% Q1. Can I use the Below feaure with dvipdfm+EPS? +% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +% Use the epstopdf untility shipped with graphicP instead of the default one +% shipped with teTeX. +% To do it, please update /etc/texmf/dvipdfm/config first with the line: +% +% D "zcat -f %i | ./epstopdf --below --hires --outfile=%o -" +% +% Substitute the `./epstopdf' with the real, absolute path to our epstopdf. +% +% Don't forget to specify \includegraphics[...,below]{...} +% +% Which characters can I have in the filename? +% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +% For dvips, xdvi and dvipdfm: +% -- You must avoid the double quote ("), because it is the filename terminator +% of the PSFile \special. +% For pdftex: +% -- You must also avoid the dollar sign +% ($), because kpsewhich interprets it as a variable substitution, and +% pdftex calls KPSE to look up image file names. +% For old pdftex 0.12 shipped with Debian Slink (pdftex >=0.14 is OK): +% -- You must avoid space, because stupid \pdfimage cannot parse it. +% For xdvi and dvipdfm: +% -- You must also avoid the +% backslash (\), because xdvi removes it from the filename (dvips doesn't). +% +% All other characters can be used, but you have to quote some of them to +% avoid wrong category codes and/or expansion: +% +% All characters [\000-\037\177-\377] should be input as hex: \expandafter\@secondoftwo\string\^^HL +% All characters [\040-\176] can be written as-is, except for: +% $ is OK +% & is OK +% _ is OK +% a space should be input as '\iftrue\space\fi '; # won't collapse two spaces into one +% \ { } % # ^ ~ ` " should be input as \expandafter\@secondoftwo\string\\ etc. +% +% Note that `\noexpand"' is not good enough for `"', because `\noexpand"e' +% would expand to an accented letter if expanded twice under +% \usepackage[german]{babel}. +% +% I've verified these characters on the file name +% +% ugly_"$&_ \}%#^^aáéb{%#^~` +% +% which was input as +% +% ugly_"$&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\\\expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\` +% +% Can I embed MetaPost output? +% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +% Yes, \includegraphics{ajobname.1} works fine with all drivers. (ajobname.1 +% is the output file of MetaPost when ajobname.mp contains `beginfig(1)'.) +% +% How do I specify an output filename for MetaPost? +% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +% Basicly you invoke MetaPost as `mpost ajobname.mp', where ajobname.mp is +% the MetaPost source file. MetaPost writes the log file ajobname.log. If +% you say `beginfig(42)' in ajobname.mp, the output EPS file `ajobname.42' +% will be created. If you say `beginfig(-1)' (or any negative number), +% `ajobname.ps' will be created. You cannot force any other filename -- +% these are hard-wired to the MetaPost executable. +% +% How do I make MetaPost emit a HiResBoundingBox? +% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +% Just add +% +% extra_endfig := extra_endfig +% & "special (" +% & ditto & "%%HiResBoundingBox: " & ditto +% & "&decimal xpart llcorner currentpicture &" & ditto & " " & ditto +% & "&decimal ypart llcorner currentpicture &" & ditto & " " & ditto +% & "&decimal xpart urcorner currentpicture &" & ditto & " " & ditto +% & "&decimal ypart urcorner currentpicture );"; +% +% to the beginning of ajobname.mp. context/mp-tool.mp does this already. +% You cannot force it before %%EndProlog or %%Page:. This is an inherent +% limitation of the MetaPost executable. +% +% --- +% +% Dat: dvipdfm crops EPS images below y==0; it doesn't crop PDF images. See +% FAQ answer Q1 to overcome it. +% Dat: works with `dvips', `dvipdfm', `xdvi' and `pdftex' +% Dat: works with pdftex 3.14159-0.12r (Slink), 0.14 (Potato), 1.00a (Woody) +% OK : use bbox cache by img_bbox.pl +% OK : verify slink -- potato -- woody +% OK : sam2p Below feature +% OK : verify and document various filename chars +% OK : bbox read directly from image +% OK : respect best of BoundingBox, HiResBoundingBox and ExactBoundingBox +% OK : pdfboxes.pl: Perl script to inject PDF bbox near beginning +% OK : guess extension if unspecified, automatic filename.ext +% OK : pts_bbox.sty handles PDF, EPS, MPS +% OK : pts_bbox.sty handles TIFF, JPEG and PNG -- only with pdfTeX +% OK : pts_img.sty handles JPEG and PNG for pdfTeX and dvipdfm, TIFF for pdfTeX +% OK : MetaPost EPS is recognised properly by the pdftex driver (dvipdfm already did it right) +% OK : warning if FileFormat not supported by driver +% OK : \usepackage[nopdftexmpost]{graphicp} disables loading of ConTeXt supp-pdf.tex +% OK : \usepackage[forceunknown]{graphicp}. If an unknown FileFormat is not +% forced, an \errmessage is displayed, and the reference point is moved +% without drawing the image. +% OK : \includegraphics[raise=20]{...} or lower=-20 specifies raising in image +% dimensions (pixels) +% OK : \includegraphics[lower=0] disables autobelow +% OK : needed sam2p "Q endstream", because we say \pdfliteral{ Q}, so +% the embedding bug pdfTeX Version 3.14159-0.12r won't manifest. +% In sam2p-0.42 /Length+=1 on the content stream fixed the problem. +% OK : dvipdfm usexobj +% OK : sam2p 0.43 pre-/MediaBox feature (object reordering) +% OK : move reference point for \convertMPtoPDF in Debian Slink +% OK : below option is not default since Sun Feb 9 22:27:23 CET 2003 +% OK : proven not to work: PDF XObject on old pdftexs (Potato, Slink) +% OK : frame, namedframe, invisible and blackbox drivers, only show the bboxes and the filename +% Imp: documentation .tex +% Imp: use pdfTeX to read the bounding box (non-negative below feature) +% Imp: better \usepackage{graphicx} compatibility: clip=, bb=, totalheight=, +% keepaspectratio=, type=, ext=, read=, viewport=, clip=, `gunzip +% Imp: allow user select from BoundingBox, HiResBoundingBox and ExactBoundingBox +% Imp: add clipping support +% Imp: add rotation + mirroring support +% Imp: advanced \textascii for driver=namedframe +% Imp: imtrix ? + +\expandafter\ifx\csname ifLaTeX\endcsname\relax\input laemu.sty\relax\fi% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{graphicp}[2003/01/24 v0.0 graphics.sty replacement] +\RequirePackage{keyvalx} +\RequirePackage{pts_bbox} + +%\errmessage{O(\csname opt@graphicp.sty\endcsname)}% +%\errmessage{D(\@declaredoptions)}% +%\errmessage{C(\@curroptions)}% +%\errmessage{C(\@unprocessedoptions)}% +%\expandafter\def\csname opt@graphicp.sty\endcsname{}% +%\def\@declaredoptions{}% +%\expandafter\let\csname ds@alma\endcsname\relax% +%\show\@unprocessedoptions +%\let\@unprocessedoptions\relax +%\AtEndOfPackage{\def\@unprocessedoptions{}}% + +%** \def's #1 to 1 if #2 contains a true boolean value; 0 otherwise. A true +%** value is a value beginning with `t', `y' or `1'. +\def\@@gp@boolpon#1#2{% + \expandafter\@@gp@boolpon@low#2f\\#1% + %\message{ponated(#1)}% +}% +\def\@@gp@boolpon@low#1#2\\#3{% + \edef#3{% + \if\noexpand#1t1% true + \else\if\noexpand#1y1% yes + \else\if\noexpand#111% 1 + \else0\fi\fi\fi% + }% +}% +%** Similar to \@@gp@boolpon, but inverts the condition +\def\@@gp@boolneg#1#2{% + \@@gp@boolpon{#1}{#2}% + \edef#1{\if#101\else0\fi}% +}% + +%\LaemuProcessOptions\errmessage +\define@key{graphicp}{driver}{\edef\@@gp@driver{#1}}% +\define@key{graphicp}{pdftex}{\edef\@@gp@driver{pdftex}}% +\define@key{graphicp}{dvi}{\edef\@@gp@driver{dvi}}% +\define@key{graphicp}{dvips}{\edef\@@gp@driver{dvips}}% +\define@key{graphicp}{dvipdfm}{\edef\@@gp@driver{dvipdfm}}% +\define@key{graphicp}{pdftexmpost}[true]{\@@gp@boolpon\@@gp@pdftexmpost{#1}}% +\define@key{graphicp}{nopdftexmpost}[true]{\@@gp@boolneg\@@gp@pdftexmpost{#1}}% +%\define@key{graphicp}{forceunknown}[true]{\@@gp@boolpon\@@gp@forceunknown{#1}}% +\define@key{graphicp}{forceunknown}[2]{\def\@@gp@forceunknown{#1}}% +\define@key{graphicp}{forceunknown}[true]{\@@gp@boolneg\@@gp@forceunknown{#1}}% +\def\@@gp@pdftexmpost{1}% +\def\@@gp@driver{}% +\def\@@gp@forceunknown{0}% +\LaemuProcessOptions{\setkeys{graphicp}}% + +\if0\@@gp@pdftexmpost \def\graphicPnopdftexmpost{}\fi% +\if1\@@gp@forceunknown \def\@@img@forceunknown{1}\fi% +\let\@@gp@pdftexmpost\relax% +\RequirePackage{pts_img}% uses \graphicPnopdftexmpost +\@@img@setdriver{\@@gp@driver}% +\let\@@gp@driver\relax% +%\let\@@gp@forceunknown\relax% + +% --- Mon Feb 3 18:12:46 CET 2003 + +%** Expands to the filename extension of #1, e.g 'ePs' for `a.b/cd.ePs' +\def\@@gp@getext#1{% + \@@gp@getexta#1/\@empty% +}% + +\def\@@gp@getexta#1/#2{% + \ifx#2\@empty% \@empty itself or a macro with empty expansion + \@@gp@getextb#1.\@empty% + %\expandafter\@gobble% needed unless \@empty is the delimiter + \else% + \expandafter\@@gp@getexta + \fi% + #2% +}% +\def\@@gp@getextb#1.#2{% + \ifx#2\@empty% + % Extension not found, expand to nothing + %\expandafter\@gobble% needed unless \@empty is the delimiter + \else% + %:#2%\@@gp@getextc#2\\% + \expandafter\@@gp@getextc% + \fi% + #2% +}% +\def\@@gp@getextc#1.#2{% + \ifx#2\@empty% + #1% found extension + %\expandafter\@gobble% needed unless \@empty is the delimiter + \else% + \expandafter\@@gp@getextc + \fi% + #2% +}% + +%** Adds extension #1 to filename #2, unless #2 already has an extension. +%** Example: `\@@gp@addext{eps}{my.document/myfigure}' expands to +%** `my.document/myfigure.eps' +\def\@@gp@addext#1#2{% + #2\if.\@@gp@getext{#2}..#1\fi% + % ^^^ we use the fact that the first unexpandable token of the expansion of + % \@@gp@getext is either nonexistent, or it is a char other than `.' +} + +% --- + +%** Doesn't work if the 1st token of #1 is expandable or it is a control +%** sequence. +%\def\@@gp@isempty#1{% +% \if\noexpand\noexpand\noexpand#1\noexpand% +% empty% +% \else% +% not% +% \fi% +%}% + +%** Expands #1 iff #2 is empty. +%** @param #2 may not contain an extra (unbalanced) \else +\def\@@gp@isempty#1#2{% + \@@gp@isemptyi{#1}#2\else\fi% +}% +%** Same as \@@gp@isempty{#2}{#1} +\def\@@gp@isemptyr#1#2{% + \message{(\noexpand#1:#2)}% + \@@gp@isemptyi{#2}#1\else\fi% +}% +\def\@@gp@isemptyi#1#2{\iffalse#2#1}% + +% Regression test: +%\message{g(\@@gp@getext{hello})} +%%\tracingmacros=1 +%\message{g(\@@gp@getext{hel.lo/barna})} +%\message{g(\@@gp@getext{hel.lo/you/barna.ePs})} +%\message{g(\@@gp@getext{hel.lo/you/barna.ePs.gz})} +%\message{e(\@@gp@isempty{empty}{})}% +%\message{e(\@@gp@isempty{empty}{foo})}% +%\message{e(\@@gp@isempty{empty}{,alma})}% +%\message{e(\@@gp@isempty{empty}{\relax,korte})}% +%\message{e(\@@gp@isempty{empty}{\iftrue\else\fi})}% +%\message{a(\@@gp@addext{alma}{kor.te})} +%\message{a(\@@gp@addext{alma}{korte})} +%\message{a(\@@gp@addext{eps}{my.document/myfigure})} +%\@@gp@addext{alma}{korte} + +% --- GraphicP implementation begins + +\def\@@gp@setbbox#1#2#3#4{% + %\message{bb:(#1)(#2)(#3)(#4).}% + \def\@@gp@llx{#1}% + \def\@@gp@lly{#2}% + \def\@@gp@urx{#3}% + \def\@@gp@ury{#4}% +}% +\def\@@gp@question{?}% +\def\@@gp@PDF{PDF}% +\def\@@gp@setfbbox#1#2#3#4#5{% + %\message{(ff=#1)(#2)(#3)(#4)(#5).}% + \def\@@gp@format{#2}% assign temporarily + \ifx\@@gp@format\@@gp@question\else + % ^^^ assign only other than `?', so \@@GetBBox can override @@gp@format + \def\@@gp@llx{#2}% + \def\@@gp@lly{#3}% + \def\@@gp@urx{#4}% + \def\@@gp@ury{#5}% + \fi% + \edef\@@gp@format{#1}% FileFormat +}% + +%** Must be bbox={{0bp}{0bp}{72bp}{72bp}} +\define@key{incgP}{bbox}{\@@gp@setbbox#1}% +%** Must be fbbox={{TIFF}{0bp}{0bp}{72bp}{72bp}} +\define@key{incgP}{fbbox}{\@@gp@setfbbox#1}% +\define@key{incgP}{format}{\def\@@gp@format{#1}}% +\define@key{incgP}{width}{\def\@@gp@width{#1}}% +\define@key{incgP}{height}{\def\@@gp@height{#1}}% +\define@key{incgP}{raise}{\def\@@gp@raise{#1}}% +\define@key{incgP}{lower}{\def\@@gp@raise{-#1}}% +\define@key{incgP}{below}[]{\def\@@gp@raise{-#1}}% +\define@key{incgP}{clip}[true]{\csname if#1\endcsname\let\@@dp@clip1\else\let\@@dp@clip0\fi}% +\define@key{incgP}{noclip}[true]{\csname if#1\endcsname\let\@@dp@clip0\else\let\@@dp@clip1\fi}% +\define@key{incgP}{forceunknown}[2]{\def\@@gp@forceunknown{#1}}% + +\def\@@gp@checkbbox{% + \edef\@@gp@havebbox{% + \ifx\@@gp@llx\@@gp@question\else% + \ifx\@@gp@lly\@@gp@question\else% + \ifx\@@gp@urx\@@gp@question\else% + \ifx\@@gp@ury\@@gp@question\else% + 1\fi\fi\fi\fi% + }% +}% + +\def\@@gp@runpdfboxes{\MessageBreak Run pdfboxes.pl to fix the file.}% + +\def\includegraphicP{\@ifnextchar[\@@gp@includegraphics{\@@gp@includegraphics[]}}% +\let\includegraphics\includegraphicP +\def\@@gp@includegraphics[#1]#2{% + % Imp: change space tokens to `\space' in the filename + \begingroup + %\def\@@gp@bbox{{invalid}{}{}{}}% + %\def\@@gp@raise{}% dimension to raise above the baseline -- or empty + \def\@@gp@raise{0bp}% \usepackage{graphicx} compatibility + \def\@@gp@llx{?}% source image bbox and size + \def\@@gp@lly{?}% + \def\@@gp@urx{?}% + \def\@@gp@ury{?}% + \def\@@gp@format{?}% + \def\@@gp@width{0pt}% + \def\@@gp@height{0pt}% desired target width+height + \def\@@gp@clip{0}% + %\def\space{\noexpand\space}%expandafter\string\csname space \endcsname}% + \chardef\space0 % \space will expand to `\space ' + \edef\@@gp@filename{\@@gp@addext{\@@img@defext}{#2}}% add default extension + %\message{fn(\@@gp@filename)}% + \def\space{ }% change it back + \setkeys{incgP}{#1}% + \@@gp@checkbbox% + \ifx\@@gp@havebbox\@empty% bbox not specified as arg + \@@GetBBox\@@gp@setfbbox{\@@gp@filename}% load bbox from file + %\errmessage{z}% + \else% + \ifx\@@gp@format\@@gp@question% + \@@GetBBox\@@gp@setfbbox{\@@gp@filename}% determine FileFormat from file, possibly override with real bbox + \fi% + \fi% + \@@gp@checkbbox% + %\message{fn=(#2) havebbox=(\@@gp@havebbox) bbox=(\@@gp@llx)}% + \ifx\@@gp@havebbox\@empty% failed to determine bbox + \ifx\@@gp@format\@@gp@PDF \let\@@gp@err\@@gp@runpdfboxes + \else \let\@@gp@err\@empty\fi + \PackageError{graphicP}{Cannot get BoundingBox of image file `#2'\@@gp@err}\@ehc% + \@@gp@setbbox{0}{0}{72bp}{72bp}% fallback if the user continues + \fi% + %\expandafter\@@PutImage\@@gp@bbox% + \chardef\space0 % \space will expand to `\space ' + \edef\@tempa{\noexpand\@@PutImage% + {\@@gp@raise}{\@@gp@forceunknown}.% + {{\@@gp@llx}{\@@gp@lly}{\@@gp@urx}{\@@gp@ury}}% + {\@@gp@width}{\@@gp@height}{\@@gp@clip}{\@@gp@filename}{\@@gp@format}}% + \def\space{ }% change it back + \expandafter\endgroup\@tempa % so \@@PutImage can change global variables +}% + +%\zzzzzzzz diff --git a/macros/latex/exptl/graphicp/graphicpdoc.pdf b/macros/latex/exptl/graphicp/graphicpdoc.pdf Binary files differnew file mode 100644 index 0000000000..944635ed93 --- /dev/null +++ b/macros/latex/exptl/graphicp/graphicpdoc.pdf diff --git a/macros/latex/exptl/graphicp/graphicpdoc.tex b/macros/latex/exptl/graphicp/graphicpdoc.tex new file mode 100644 index 0000000000..86cc3b9135 --- /dev/null +++ b/macros/latex/exptl/graphicp/graphicpdoc.tex @@ -0,0 +1,146 @@ +% +% graphicpdoc.tex: documentation of GraphicP, a LaTeX source file +% by pts@fazekas.hu at Mon Feb 10 00:07:07 CET 2003 +% + +\documentclass[a4paper]{article} + \usepackage[latin2]{inputenc} + %\usepackage[magyar]{babel}% for testing the active ` + \usepackage[english]{babel} + %\usepackage{ascii} + %\usepackage{pts_cs} + %\usepackage{t1enc} + + \paperheight=297mm \paperwidth=210mm + \expandafter\ifx\csname pdfoutput\endcsname\relax% + \special{papersize=595bp,842bp}% + \else% + \pdfoutput=1% + \pdfcompresslevel=9% + \pdfpagewidth=595bp \pdfpageheight=842bp% + \pdfpageattr={/CropBox [0 0 595 842]}% + \fi% + + \hoffset=2cm \voffset=2cm + \textheight=\paperheight \advance\textheight by -2\voffset + \textwidth =\paperwidth \advance\textwidth by -2\hoffset + \advance\hoffset by -1in + \advance\voffset by -1in + \topmargin=0cm% + \headheight=0cm% + \headsep=0cm% + \marginparsep=0cm% + \marginparwidth=0cm% + \oddsidemargin=0cm% + \evensidemargin=0cm% csak páratlan oldalak E twoside nélkül + \footskip=15pt% a sorszám basline-ja a szöveg alsó bl-jától + \relax% + +\def\product/{\textsf{GraphicP}} +\def\tokenfbox#1{{\fboxrule=0.2pt \fboxsep=1pt \fbox{\textex{#1}}}} +\def\aproduct#1{\textsf{#1}} +\makeatletter +%** Example: \bchar\\ +\def\bchar#1{\expandafter\@gobble\string#1}% + +\title{Documentation of \product/} +\author{Szab\'o P\'eter\\\texttt{<pts@fazekas.hu>}} + +\begin{document} + +\makeatletter + \def\@listi{% \begin{document} után kell! + \leftmargin=\leftmargini% + \topsep=5pt plus3pt minus1pt% + %\partopsep=0pt% + \parsep=0.5pt plus0.5pt minus0.5pt% + \itemsep=3pt plus3pt minus1pt% + %\parsep=0pt \itemsep=0pt % works fine + }% + +\maketitle +\begin{abstract} + This is the documentation of \product/, a system that provides an easy, fast and reliable method for + including external images into {\LaTeX} and plain {\TeX} documents. The + \texttt{\bchar\\includegraphics} macro of \product/ is a drop-in + replacement of the same + command of {\LaTeX} \texttt{graphics.sty} and \texttt{graphicx.sty}, but with + many enhancements. + Input images are ususally in EPS or PDF format. Drivers for \aproduct{xdvi}, + \aproduct{dvips}, \aproduct{pdftex} and \aproduct{dvipdfm} are included. + Perl scripts are provided for + faster bounding box manipulations. +\end{abstract} + +\section{Availability and usage} + +You can download \product/ from +\texttt{http://www.inf.bme.hu/\textasciitilde pts/graphicp-latest.tar.gz}. + +Load \product/ with \texttt{\bchar\\usepackage\bchar\{graphicp\bchar\}} +instead of +\texttt{\bchar\\usepackage\bchar\{graphicx\bchar\}}. Use the +\texttt{\bchar\\includegra\allowbreak phics} macro as usual, but beware of the +differences. + +\section{Quick feature list} + +Features over {\LaTeX} \texttt{\bchar\\usepackage\bchar\{graphicx\bchar\}}: + +\begin{itemize} + +\item both plain TeX and LaTeX support +\item specified width=... and height=... are strictly enforced, without rounding +\item image scaling calculations are much more accurate +\item works with \textit{dvips -E} bounding-box calculations, even with buggy dvips + 5.86e +\item doesn't have to open the .eps file for reading the bbox +\item xdvi doesn't forcibly crop (clip) the image to the bbox +\item Below feature: allows the image descend below the baseline + (supports depth, not only width and height) +\item drop dependency on Perl, parse Adobe DSC comments in EPS files +\item non-standard, quick, DSC-like parsing for special PDF files +\item an enhanced \aproduct{epstopdf} utility +\item the \aproduct{img\textunderscore bbox.pl} utility +\item the \aproduct{pdfboxes.pl} utility +\item voluntary clipping (cropping) +\item all 8 mirror and rotate transformation (must be a multipe of 90 degrees) +\item does not rely on the filename to determine the FileFormat +\item embeds each image file only once with pdfTeX and dvipdfm +\item {}[long term plan] imtrix: unified PSTricks/PSFrag support for EPS and PDF + +\end{itemize} + +\section{Further reading} + +The full documentation hasn't been written yet. See the file +\texttt{graphicp.sty} for more information. + +To see samples, try the following compilation procedures: + +\begin{verbatim} + tex laltest # or: latex laltest + xdvi laltest + dvips -o laltest.ps laltest + dvipdfm -v laltest + xpdf laltest.pdf +\end{verbatim} + +\begin{verbatim} + pdftex laltest # or: pdflatex laltest + xpdf laltest.pdf +\end{verbatim} + +\begin{verbatim} + latex '\def\graphicPdriver{dvips}\input laltest' + xdvi laltest + dvips -o laltest.ps laltest +\end{verbatim} + +\begin{verbatim} + tex '\def\graphicPdriver{dvipdfm}\input laltest' + dvipdfm -v laltest + xpdf laltest.pdf +\end{verbatim} + +\end{document} diff --git a/macros/latex/exptl/graphicp/img_bbox.pl b/macros/latex/exptl/graphicp/img_bbox.pl new file mode 100755 index 0000000000..12c1b951c7 --- /dev/null +++ b/macros/latex/exptl/graphicp/img_bbox.pl @@ -0,0 +1,2079 @@ +#! /bin/sh +eval '(exit $?0)' && eval 'PERL_BADLANG=x;export PERL_BADLANG;: \ +;exec perl -x -S -- "$0" ${1+"$@"};#'if 0; +eval 'setenv PERL_BADLANG x;exec perl -x -S -- "$0" $argv:q;#'.q+ +#!perl -w +package Htex::img_bbox; $0=~/(.*)/s;unshift@INC,'.';do($1);die$@if$@;__END__+if !1; +# This Perl script was generated by JustLib2 at Sun Feb 9 23:57:24 2003. +# Don't touch/remove any lines above; http://www.inf.bme.hu/~pts/justlib +package just; BEGIN{$INC{'just.pm'}='just.pm'} +BEGIN{ $just::VERSION=2 } +sub end(){1} +sub main(){} + +BEGIN{$ INC{'integer.pm'}='integer.pm'} { +package integer; +use just; +# by pts@fazekas.hu at Wed Jan 10 12:42:08 CET 2001 +sub import { $^H |= 1 } +sub unimport { $^H &= ~1 } +just::end} + +BEGIN{$ INC{'strict.pm'}='strict.pm'} { +package strict; +use just; +# by pts@fazekas.hu at Wed Jan 10 12:42:08 CET 2001 +require 5.002; +sub bits { + (grep{'refs'eq$_}@_ && 2)| + (grep{'subs'eq$_}@_ && 0x200)| + (grep{'vars'eq$_}@_ && 0x400)| + ($@ || 0x602) +} +sub import { shift; $^H |= bits @_ } +sub unimport { shift; $^H &= ~ bits @_ } +just::end} + +BEGIN{$ INC{'Pts/string.pm'}='Pts/string.pm'} { +package Pts::string; +# by pts@fazekas.hu at Sat Dec 21 21:32:18 CET 2002 +use just; +use integer; +use strict; + +#** @param $_[0] a string +#** @param $_[1] index of first bit to return. Bit 128 of byte 0 is index 0. +#** @param $_[2] number of bits to return (<=32) +#** @return an integer (negative on overflow), bit at $_[1] is its MSB +sub get_bits_msb($$$) { + # assume: use integer; + my $loop=$_[1]; + my $count=$_[2]; + my $ret=0; + ($ret+=$ret+(1&(vec($_[0],$loop>>3,8)>>(7-($loop&7)))), $loop++) while $count--!=0; + $ret +} + +#** @param $_[0] a string +#** @return value if $_[0] represents a floating point numeric constant +#** in the C language (without the LU etc. modifiers) -- or undef. Returns +#** undef for integer constants +sub c_floatval($) { + my $S=$_[0]; + no integer; # very important; has local scope + return 0.0+$S if $S=~/\A[+-]?(?:[0-9]*\.[0-9]+|[0-9]+\.])(?:[eE][+-]?[0-9]+)?\Z(?!\n)/; + undef +} + +#** @param $_[0] a string +#** @return value if $_[0] represents a floating point or integer numeric +#** constant in the C language (without the LU etc. modifiers) -- or undef +sub c_numval($) { + my $S=$_[0]; + no integer; # very important; has local scope + return 0+$S if $S=~/\A[+-]?(?:[0-9]*\.[0-9]+(?:[eE][+-]?[0-9]+)?|[0-9]+\.?)\Z(?!\n)/; + undef +} + +#** @param $_[0] a string +#** @return the integer value of $_[0] in C -- or undef +sub c_intval($) { + my $S=$_[0]; + my $neg=1; + $neg=-1 if $S=~s@\A([+-])@@ and '-'eq$1; + return $neg*hex $1 if $S=~/\A0[xX]([0-9a-fA-F]+)\Z(?!\n)/; + return $neg*oct $1 if $S=~/\A0([0-7]+)\Z(?!\n)/; + return $neg*$1 if $S=~/\A([0-9]+)\Z(?!\n)/; + undef +} + +sub import { + no strict 'refs'; + my $package = (caller())[0]; + shift; # my package + for my $p (@_ ? @_ : qw{get_bits_msb c_floatval c_numval c_intval}) { *{$package."::$p"}=\&{$p} } +} + +just::end} + +BEGIN{$ INC{'Htex/dimen.pm'}='Htex/dimen.pm'} { +package Htex::dimen; +# by pts@fazekas.hu at Sat Dec 21 21:26:15 CET 2002 +use just; +use integer; +use strict; +use Pts::string qw(c_numval); + +my %bp_mul; +{ no integer; %bp_mul=( + 'bp'=>1, # 1 bp = 1 bp (big point) + 'in'=>72, # 1 in = 72 bp (inch) + 'pt'=>72/72.27, # 1 pt = 72/72.27 bp (point) + 'pc'=>12*72/72.27, # 1 pc = 12*72/72.27 bp (pica) + 'dd'=>1238/1157*72/72.27, # 1 dd = 1238/1157*72/72.27 bp (didot point) [about 1.06601110141206 bp] + 'cc'=>12*1238/1157*72/72.27, # 1 cc = 12*1238/1157*72/72.27 bp (cicero) + 'sp'=>72/72.27/65536, # 1 sp = 72/72.27/65536 bp (scaled point) + 'cm'=>72/2.54, # 1 cm = 72/2.54 bp (centimeter) + 'mm'=>7.2/2.54, # 1 mm = 7.2/2.54 bp (millimeter) +) } + +#** @param $_[0] a (real or integer) number, optionally postfixed by a +#** TeX dimension specifier (default=bp) +#** @return the number in bp, or undef +sub dimen2bp($) { + no integer; + my $S=$_[0]; + my $mul; + $mul=$bp_mul{$1} if $S=~s/\s*([a-z][a-z0-9]+)\Z(?!\n)// and exists $bp_mul{$1}; + my $val=c_numval($S); + $val*=$mul if defined $val and defined $mul; + $val +} + +just::end} + +BEGIN{$ INC{'Htex/ImgBBox.pm'}='Htex/ImgBBox.pm'} { +package Htex::ImgBBox; +# +# ImgBBox -- extract file format and size from image files +# by pts@fazekas.hu at Sat Dec 7 21:31:01 CET 2002 +# JustLib2 at Sat Dec 21 21:29:21 CET 2002 +# +# Dat: we know most of xloadimage-1.16, most of of file(1)-debian-potato, +# all of sam2p-0.40, all of xv-3.10 +# Dat: only in xloadimage: g3Ident, g3Load, "G3 FAX Image", (hard to identify file format) +# Dat: only in xloadimage: macIdent, macLoad, "MacPaint Image", (stupid, black-white) +# Imp: multiple paper sizes +# +use just; +use integer; +use strict; +use Htex::dimen; +use Pts::string; +# use Data::Dumper; + +# Dat: BBoxInfo is a hashref: +# Dat: Info.* keys has FileFormat-dependent meaning (thus Info.depth may have +# different meanings for different FileFormats) +# { 'FileFormat' => 'TIFF' # ... +# 'SubFormat' => 'PPM' +# 'Error' => 0 +# 'LLX' => ... # lower left x (usually 0) +# 'LLY' => ... # lower left y (usually 0) +# 'URX' => ... # upper right x (usually width) +# 'URY' => ... # upper right y (usually height) +# } + +# Dat: \usepackage[hiresbb]{graphicx} +# Dat: pdfTeX graphicx.sty doesn't respect PDF CropBox. For +# /MediaBox[a b c d], \ht=d, \wd=c, and no overwrite below (a,b) + +# --- + +#** import will set them +my $have_pdf; +my $have_paper; + +#** May moves the file offset, but only relatively (SEEK_CUR). +#** @param $_[0] \*FILE +#** @return BBoxInfo +sub calc($) { + my $F=$_[0]; + my $dummy; + my @L; + my $head; + #** BBoxInfo to return + my $bbi={ + # 'FileFormat' => '.IO.error', + 'FileFormat' => 'unknown', + 'LLX' => 0, 'LLY' => 0, # may be float; in `bp' + # 'URX' => 0, 'URY' => 0 # default: missing; may be float; in `bp' + }; + binmode $F; + if (0>read $F, $head, 256) { IOerr: $bbi->{Error}="IO: $!"; goto done } + if (length($head)==0) { $bbi->{FileFormat}='Empty'; return $bbi } + if ($head=~m@\A\s*/[*]\s+XPM\s+[*]/@) { # XPM + $bbi->{FileFormat}='XPM'; + goto IOerr if !seek $F, -length($head), 1; + select($F); $/='"'; select(STDOUT); <$F>; + $head=<$F>; + if ($head!~/\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*"\Z(?!\n)/s) { SYerr: $bbi->{Error}='syntax'; goto done } + # width, height, length(palette), length(pixelchar) + $bbi->{URX}=0+$1; + $bbi->{URY}=0+$2; + } elsif ($head=~m@\A\s*\/\*\s*Format_version=\S*\s+@i) { + $bbi->{FileFormat}='XBM1'; # ?? + goto IOerr if 0>read $F, $head, 256-length($head), length($head); + $head=~s@\*\/.*@@s; # keep only header + goto SYerr if $head!~m@\s+Width=(\d+)@i; + $bbi->{URX}=0+$1; + goto SYerr if $head!~m@\s+Height=(\d+)@i; + $bbi->{URY}=0+$1; + } elsif ($head=~m@\A(?:/[*].*?[*]/)?\s*#define\s+.*?_width\s+(\d+)\s*#define\s+.*?_height\s+(\d+)\s*@) { # XBM (1) + # Dat: this `if' must be after checking XPM + # Imp: recognise a longer comment (that does not fit into $head) + $bbi->{FileFormat}='XBM'; + $bbi->{URX}=0+$1; + $bbi->{URY}=0+$2; + } elsif ($head=~m@\A(?:/[*].*?[*]/)?\s*#define\s+.*?_height\s+(\d+)\s*#define\s+.*?_width\s+(\d+)\s*@) { # XBM (2) + $bbi->{FileFormat}='XBM'; + $bbi->{URX}=0+$2; + $bbi->{URY}=0+$1; + } elsif ($head=~m@\AP([1-6])[\s#]@) { # PNM + $bbi->{FileFormat}='PNM'; + my @subformats=qw{- PBM.text PGM.text PPM.text PBM.raw PGM.raw PPM.raw}; + $bbi->{SubFormat}=$subformats[0+$1]; + goto IOerr if 0>read $F, $head, 1024-length($head), length($head); + $head=~s@#.*@@g; # remove comments + goto SYerr if ($head!~/\AP[1-6]\s+(\d+)\s+(\d+)\s/); + $bbi->{URX}=0+$1; $bbi->{URY}=0+$2; + } elsif (substr($head, 0, 4) eq "MM\000\052" or substr($head, 0, 4) eq "II\052\000") { + $bbi->{FileFormat}='TIFF'; + my $LONG="N"; + my $SHORT="n"; + if (substr($head, 0, 1) eq "I") { + $bbi->{SubFormat}='LSBfirst'; + $LONG="V"; $SHORT="v"; + } else { + $bbi->{SubFormat}='MSBfirst'; + } + my($dummy,$ifd_ofs)=unpack $LONG.$LONG, $head; + goto IOerr if !seek $F, $ifd_ofs-length($head), 1; + my $ifd_len; + goto IOerr if 2!=read $F, $ifd_len, 2; + $ifd_len=unpack($SHORT,$ifd_len); + while ($ifd_len--!=0) { + my($entry,$tag,$type,$count,$value); + goto IOerr if 12!=read $F, $entry, 12; + ($tag,$type,$count)=unpack($SHORT.$SHORT.$LONG, $entry); + # vvv Dat: we discard tags with $value longer than 4 bytes + # Unfortunately BitsPerSample may be such a tag for RGB + if ($type==3) { $value=unpack($SHORT,substr($entry,8,2)) } + elsif ($type==4) { $value=unpack($LONG, substr($entry,8,4)) } + else { $value=vec($entry,8,8); } + if ($tag==256 and $count==1) { $bbi->{URX}=$value } # ImageWidth + elsif ($tag==257 and $count==1) { $bbi->{URY}=$value } # ImageLength + elsif ($tag==258 and $count<=2) { $bbi->{BitsPerSample}=$value } + elsif ($tag==259) { $bbi->{"Info.Compression"}=$value } + elsif ($tag==254) { $bbi->{"Info.NewSubfileType"}=$value } + elsif ($tag==255) { $bbi->{"Info.SubfileType"}=$value } + elsif ($tag==262) { $bbi->{"Info.PhotometricInterpretation"}=$value } + elsif ($tag==263) { $bbi->{"Info.Thresholding"}=$value } + elsif ($tag==264) { $bbi->{"Info.CellWidth"}=$value } + elsif ($tag==265) { $bbi->{"Info.CellLength"}=$value } + elsif ($tag==266) { $bbi->{"Info.FillOrder"}=$value } + elsif ($tag==274) { $bbi->{"Info.Orientation"}=$value } + elsif ($tag==277) { $bbi->{SamplesPerPixel}=$value } + elsif ($tag==278) { $bbi->{"Info.RowsPerStrip"}=$value } + elsif ($tag==280) { $bbi->{"Info.MinSampleValue"}=$value } + elsif ($tag==281) { $bbi->{"Info.MaxSampleValue"}=$value } + elsif ($tag==284) { $bbi->{"Info.PlanarConfiguration"}=$value } + elsif ($tag==290) { $bbi->{"Info.GrayResponseUnit"}=$value } + elsif ($tag==296) { $bbi->{"Info.ResolutionUnit"}=$value } + elsif ($tag==338 and $count<=2) { $bbi->{"Info.ExtraSamples"}=$value } + } + } elsif ($head=~/\A\12[\0-\005]\001[\001-\10]/) { + $bbi->{FileFormat}='PCX'; # PC Paintbrush image + ($dummy,$bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=unpack("A4vvvv",$head); + $bbi->{URX}++; $bbi->{URY}++; + # pinfo->w = 1+ (hdr[PCX_XMAXL] + ((int) hdr[PCX_XMAXH]<<8)) - (hdr[PCX_XMINL] + ((int) hdr[PCX_XMINH]<<8)); + # pinfo->h = 1+ (hdr[PCX_YMAXL] + ((int) hdr[PCX_YMAXH]<<8)) - (hdr[PCX_YMINL] + ((int) hdr[PCX_YMINH]<<8)); + } elsif ($head=~/\AGIF(8[79]a)/) { + $bbi->{FileFormat}='GIF'; + $bbi->{SubFormat}=$1; + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("A6vv",$head); + } elsif ($head=~/\A(\377+\330)\377/g) { + $bbi->{FileFormat}='JPEG'; + die if !seek $F, length($1)-length($head), 1; + my $id_rgb=0; + my $had_jfif=0; + my $cpp; + my $colortransform=-1; # as defined by the Adobe APP14 marker + my $tag; + my $w; + while (1) { + goto IOerr if !defined($tag=getc($F)) or ord($tag)!=255; + 1 while defined($tag=getc($F)) and 255==($tag=ord($tag)); + goto IOerr if !defined($tag); + if ($tag==0xC0) { # SOF0 marker: Baseline JPEG file + $bbi->{SubFormat}='Baseline'; + goto IOerr if 2!=read $F, $w, 2; + $dummy=unpack('n',$w)-2; # length includes itself + goto IOerr if $dummy<9 or $dummy!=read($F, $w, $dummy); + $bbi->{BitsPerSample}=vec($w,0,8); + $bbi->{URY}=(vec($w,1,8)<<8)|vec($w,2,8); + $bbi->{URX}=(vec($w,3,8)<<8)|vec($w,4,8); + $cpp=vec($w,5,8); + goto SYerr if ($dummy-=6)!=3*$cpp or $cpp>6 or $cpp<1; + $bbi->{'Info.hvs'}=vec($w,7,8); # HVSamples ? + $id_rgb=1 if $cpp==3 and $w=~/\A......R..G..B/s; + } elsif (0xC1<=$tag and $tag<=0xCF and $tag!=0xC4 and $tag!=0xC8) { # SOFn + $bbi->{Subformat}="SOF".($tag-0xC0); + last + } elsif ($tag==0xD9 or $tag==0xDA) { # EOI or SOS marker; we're almost done + if (!defined $cpp) { + } elsif ($cpp==1) { + $bbi->{'ColorSpace'}='Gray'; + } elsif ($cpp==3) { + $bbi->{'ColorSpace'}='YCbCr'; + if ($had_jfif!=0 or $colortransform==1) {} + elsif ($colortransform==0 or $id_rgb) { $bbi->{'ColorSpace'}='RGB' } + } elsif ($cpp==4) { + $bbi->{'ColorSpace'}='CMYK'; + if ($colortransform==2) { $bbi->{'ColorSpace'}='YCCK' } + } + last + } else { + # skip over a variable-length block; assumes proper length marker + # ($tag==0xE0) # APP0: JFIF application-specific marker + # ($tag==0xEE) # APP14: Adobe application-specific marker + goto IOerr if 2!=read $F, $w, 2; + $dummy=unpack('n',$w)-2; # length includes itself + goto IOerr if $dummy!=read $F, $w, $dummy; + $colortransform=ord($1) if + $tag==0xEE and $dummy==12 and $w=~/\AAdobe[\001-\377].....(.)/s; + $had_jfif=1 if + $tag==0xE0 and $dummy==14 and $w=~/\AJFIF\0/; + } ## IF + } ## WHILE + $bbi->{'Info.id_rgb'}=$id_rgb; + $bbi->{'Info.had_jfif'}=$had_jfif; + $bbi->{'Info.ColorTransform'}=$colortransform; + $bbi->{SamplesPerPixel}=$cpp; + } elsif (substr($head,0,8) eq "\211PNG\r\n\032\n") { + $bbi->{FileFormat}='PNG'; + goto SYerr if $head!~/\A........\0\0\0[\15-\77]IHDR/s; + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("A16NN",$head); + } elsif (substr($head,0,5) eq "%PDF-") { + $bbi->{FileFormat}='PDF'; # Adobe Portable Document Format + # Dat: this routine cannot read encrypted PDF files + # Dat: example $bbi return: { + # 'URY' => 792, 'LLX' => '0', 'LLY' => '0', 'URX' => 612 + # 'FileFormat' => 'PDF', 'SubFormat' => '1.2', 'Info.linearized' => 1, 'Info.binary' => 'Binary', + # 'Info.MediaBox' => [ 0, 0, 612, 792 ], + # 'Info.CropBox' => [ 41, 63, 572, 729 ], + # }; + # Dat: $bbi->{'Info.num_pages'} is not reported for Linearized PDF. + # Imp: report much more specific error messages + # Imp: better distinguish between IOerr and SYerr + $bbi->{SubFormat}=$1 if $head=~/\A%PDF-([\d.]+)/; + $bbi->{'Info.binary'}=($head=~/\A[^\r\n]+[\r\n]+[ -~]*[^\n\r -~]/) ? 'Binary' : 'Clean7Bit'; + # die $have_pdf; + goto done if !$have_pdf; + # if ($head=~m@\A(?:%[^\r\n]*[\r\n])*.{0,40}/Linearized@s and $head=~m@\A(?:%[^\r\n]*[\r\n])*.{0,200}/O\s+(\d+)@s) { + my $had_pdfboxes=($head=~m@/Type\s*/pdfboxes%@); # `%' is important + $head=pdf_rewrite($head,1); + my $page1obj; + $bbi->{'Info.linearized'}=0; + $bbi->{'Info.pdfboxes'}=0; + if (defined $head) { + $head=~s@\bendobj.*@@s; + if ($had_pdfboxes) { + # a hint of very strict format, by + $head=""; + goto IOerr if !seek($F, 0, 0) or 20>read($F, $head, 2048); + goto SYerr unless $head=~/\d\s+\d+\s+obj\s*(.*?)\bendobj/s; + $head=$1; goto SYerr unless $head=~m@/Type\s*/pdfboxes%@; + while ($head=~m@^\s*/(\w+Box)\s*\[\s*(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s*\]@gm) { + ## print "($1) ($2) ($3) ($4) ($5)\n"; + ($bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=($2,$3,$4,$5) if $1 eq 'MediaBox'; + $bbi->{"Info.$1"}=[$2,$3,$4,$5]; + } + $bbi->{'Info.pdfboxes'}=1; + goto done; + } elsif ($head=~m@/Linearized\s+@ and $head=~m@/O\s+(\d+)@) { + $bbi->{'Info.linearized'}=1; + $page1obj=$bbi->{'Info.page1obj'}=$1+0; + } + } + goto IOerr if !seek $F, -1024, 2 and !seek $F, 0, 0; + goto IOerr if 1>read $F, $head, 1024; + goto SYerr if $head!~/startxref\s+(\d+)\s*%%EOF\s*\Z(?!\n)/ + and $head!~/startxref\s+(\d+)\s*%%EOF/; + # ^^^ Dat: some PDF files contain binary junk at the end + my $xref_ofs=$1+0; + goto IOerr if !seek $F, $xref_ofs, 0; + # die pdf_read_obj($F); + my $xref=[]; + my $trailer=pdf_read_xref($F,$xref); + goto SYerr if !defined $trailer; + + my $pages; + my $type; + if (!defined $page1obj) { do_pdf_slow: + ## die $trailer; + ## die pdf_ref($F,$xref,37550,0); + ## die pdf_get($F,$xref,$trailer,'/ID'); + ## die pdf_get($F,$xref,$trailer,'/Root'); + ## die pdf_get($F,$xref,$trailer,'/Size'); + ## die pdf_get($F,$xref,$trailer,'/Sizez'); + + my $root=pdf_get($F,$xref,$trailer,'/Root'); + goto IOerr if !defined $root; goto SYerr if !length $root; + $type=pdf_get($F,$xref,$root,'/Type'); + goto IOerr if !defined $type; goto SYerr if $type ne ' /Catalog'; + # die $root; + # vvv Dat: reading xref for /Pages in a linearized PDF is quite slow + $pages=pdf_get($F,$xref,$root,'/Pages'); + goto IOerr if !defined $pages; goto SYerr if !length $pages; + ## die $pages; + my $kids; + + while (1) { + $type=pdf_get($F,$xref,$pages,'/Type'); + goto IOerr if !defined $type; + last if $type ne ' /Pages'; + pdf_get_boxes($F, $xref, $pages, $bbi); + $kids=pdf_get($F,$xref,$pages,'/Kids'); + goto IOerr if !defined $kids; goto SYerr if !length $kids; + ## die $kids; + $pages=pdf_get($F,$xref,$kids,0); + ## die $pages; + goto IOerr if !defined $pages; goto SYerr if !length $pages; + } + goto SYerr if $type ne ' /Page'; + # Dat: cannot set $page1obj properly here, because it might be a direct object + $bbi->{'Info.page1obj'}=$Htex::PDFread::pdf_last_ref0; + } else { + # die $page1obj; + $pages=pdf_ref($F, $xref, $page1obj, 0); + goto IOerr if !defined $pages; + $type=pdf_get($F,$xref,$pages,'/Type'); + goto IOerr if !defined $type; + goto SYerr if $type ne ' /Page'; + my $mediabox=pdf_get($F,$xref,$pages,'/MediaBox'); + goto IOerr if !defined $mediabox; + goto do_pdf_slow if !length $mediabox; + } + pdf_get_boxes($F, $xref, $pages, $bbi); + } elsif (substr($head,0,4) eq "%!PS") { + # Dat: the user should not trust Val.languagelevel blindly. There are far + # too many PS files hanging around that do not conform to any standard. + $bbi->{FileFormat}=$bbi->{SubFormat}= + ($head=~/\A[^\n\r]*?\bEPSF-/) ? "EPS" : "PS"; + goto SYerr if $head!~s@[^\n\r]*[\n\r]+@@; + # vvv Dat `+' is `or' with full boolean eval + until ($head=~s@[\n\r]%%EndComments.*@@s + $head=~s@[\n\r](?:[^%]|%[^%]).*@@s) { + goto IOerr if 0>read $F, $head, 1024, length($head); + } + my $headlen=length($head); + $head=~s@(?:\r\n|\n\r|[\n\r])@\n@g; # uniformize newlines + $head=~s@\s*\n%%[+]\s*@ @g; # unify line continuations + my %H; + my $had_hires=0; # HiresBoundingBox overrides normal + my $val; + while ($head=~/^%%([A-Za-z]+):?\s*((?:.*\S)?)/gm) { + next if $2 ne '(atend)'; + # read additional ADSC comments from the last 1024 bytes of the file + goto IOerr if !seek $F, -1024, 2 and !seek $F, 0, 0; # Dat: seek to EOF + $dummy=tell $F; + goto IOerr if $dummy<$headlen and $headlen-$dummy!=read $F, $val, $headlen-$dummy; + goto IOerr if 0>read $F, $val, 1024; + $val=~s@(?:\r\n|\n\r|[\n\r])@\n@g; # uniformize newlines + $val=~s@\s*\n%%[+]\s*@ @g; # unify line continuations + $val=~s@^(?:[^%]|%[^%]).*\n?@@mg; # remove non-DSC lines + # vvv Dat: appending is schemantically correct here + $head.="\n$val"; last + } + while ($head=~/^%%([A-Za-z]+):?[ \t]*((?:.*\S)?)/gm) { # iterate over Adobe DSC comments + $dummy=lc($1); $val=$2; + next if $dummy eq 'enddata' or $dummy eq 'trailer' or $dummy eq 'eof'; + $bbi->{"Val.$dummy"}=$2; + if ($dummy eq 'documentdata') { + $dummy=lc($2); + $bbi->{'Info.binary'}='Clean7Bit' if $dummy eq 'clean7bit'; + $bbi->{'Info.binary'}='Clean8Bit' if $dummy eq 'clean8bit'; + $bbi->{'Info.binary'}='Binary' if $dummy eq 'binary'; + } elsif ($dummy eq 'creator' and $val=~/\bMetaPost\b/) { + $bbi->{FileFormat}='EPS'; + $bbi->{SubFormat}='MPS'; # useful for graphicP.sty + } elsif ($dummy eq 'boundingbox' and $val=~/\A([+-]?\d+)\s+([+-]?\d+)\s+([+-]?\d+)\s+([+-]?\d+)\Z(?!\n)/) { + ($bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=($1+0,$2+0,$3+0,$4+0) if !$had_hires; + } elsif (($dummy eq 'hiresboundingbox' or $dummy eq 'exactboundingbox') + and $val=~/\A([+-]?[0-9eE.-]+)\s+([+-]?[0-9eE.-]+)\s+([+-]?[0-9eE.-]+)\s+([+-]?[0-9eE.-]+)\Z(?!\n)/ + and defined c_numval($1) and defined c_numval($2) and defined c_numval($3) and defined c_numval($4) + ) { + # Dat: capitalized names are: HiResBoundingBox, ExactBoundingBox + no integer; + ($bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=($1+0,$2+0,$3+0,$4+0); + $had_hires=1; + } + } + } elsif ($head=~/\AFORM....ILBMBMHD/s) { + $bbi->{FileFormat}='LBM'; + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("A20nn",$head); + } elsif ($head=~/\AFORM....(RGB[8N])/s) { # /etc/magic + $bbi->{FileFormat}="IFF.$1"; + # dimension info not available + } elsif ($head=~/\ABM....\0\0\0\0....[\014-\177]\0\0\0/s) { # PC bitmaps (OS/2, Windoze BMP files) (Greg Roelofs, newt@uchicago.edu) + $bbi->{FileFormat}='BMP'; + if (vec($head,14,8)==12) { + $bbi->{SubFormat}='OS/2 1.x'; + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("A18vv",$head); + } elsif (vec($head,14,8)==64) { + $bbi->{SubFormat}='OS/2 2.x'; + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("A18vv",$head); + } elsif (vec($head,14,8)==40) { + $bbi->{SubFormat}='Windows'; + ($dummy,$bbi->{URX},$bbi->{URY},$dummy,$bbi->{"Info.depth"})=unpack("A18VVvv",$head); + } else { goto SYerrr } + #0 string BM PC bitmap data + #>14 leshort 12 \b, OS/2 1.x format + #>>18 leshort x \b, %d x + #>>20 leshort x %d + #>14 leshort 64 \b, OS/2 2.x format + #>>18 leshort x \b, %d x + #>>20 leshort x %d + #>14 leshort 40 \b, Windows 3.x format + #>>18 lelong x \b, %d x + #>>22 lelong x %d x + #>>28 leshort x %d + } elsif (substr($head,0,10) eq "\367\002\001\203\222\300\34;\0\0") { FF__DVI: + $bbi->{FileFormat}='DVI'; + # read 1st page of the DVI file, look for TeX \special{papersize=21cm,29.7cm}, + # as understood by dvips and xdvi + ($dummy,$bbi->{'Info.version_id'},$bbi->{'Info.numerator'}, + $bbi->{'Info.denominator'},$bbi->{'Info.magnification'})=unpack('CCNNN',$head); + goto IOerr if !seek $F, 15-length($head), 1; + $dummy=vec($head,14,8); + goto IOerr if $dummy!=read $F, $bbi->{'Info.jobname'}, $dummy; + my($tag,$action); + my @actions=(0)x256; # skip that char + $actions[139]=15; # Bop + @actions[248,249,140,223]=(16,16,16,16); # stop parsing file + @actions[128,133,143,148,153,157,162,167,235]=(1,1,1,1,1,1,1,1,1); # read 1 extra bytes + @actions[129,134,144,149,154,158,163,168,236]=(2,2,2,2,2,2,2,2,2); # read 2 extra bytes + @actions[130,135,145,150,155,159,164,169,237]=(3,3,3,3,3,3,3,3,3); # read 2 extra bytes + @actions[131,136,146,151,156,160,165,170,238]=(4,4,4,4,4,4,4,4,4); # read 2 extra bytes + @actions[132,137]=(8,8); # read 8 extra bytes + @actions[243,244,245,246]=(17,18,19,20); # Fnt_def + @actions[239,240,241,242]=(33,34,35,26); # Special (XXX) + while (1) { + goto IOerr if !defined($tag=getc($F)); # Dat: EOF is error + $tag=$actions[ord($tag)]; + if ($tag==0) { + } elsif ($tag==16) { + last + } elsif ($tag==15) { # Bop + last if exists $bbi->{'Info.page1_nr'}; + goto IOerr if 44!=read $F, $dummy, 44; + $bbi->{'Info.page1_nr'}=unpack "N", $dummy; + } else { + # read number of ($tag&15) bytes in MSBfirst byte order + $dummy="\0\0\0\0"; + goto IOerr if ($tag&15)!=read $F, $dummy, ($tag&15), 4; + $dummy=unpack("N",substr($dummy,-4)); + if ($tag>=33) { # Special + goto IOerr if $dummy!=read $F, $tag, $dummy; + @L=split /\s*=\s*/, $tag, 2; + if ($#L) { + $bbi->{"Val.$L[0]"}=$L[1]; + if ($L[0] eq 'papersize') { + @L=split /,/, $L[1], 2; + $bbi->{URX}=Htex::dimen::dimen2bp($L[0]); + $bbi->{URY}=Htex::dimen::dimen2bp($L[1]); + if (!defined $bbi->{URX} or !defined $bbi->{URY}) { + delete $bbi->{URX}; delete $bbi->{URY}; + } + } + } else { $bbi->{'Info.special'}=$tag; } + } elsif ($tag>=17) { # Fnt_def + goto IOerr if 14!=read $F, $tag, 14; + $dummy=vec($tag,12,8)+vec($tag,13,8); + goto IOerr if $dummy!=read $F, $tag, $dummy; + } + } # IF + } # WHILE + } elsif ($head=~/\Aid=ImageMagick\r?\n/) { + $bbi->{FileFormat}='MIFF'; + # goto IOerr if 0>read $F, $head, 128-length($head), length($head); + goto SYerr if $head!~/\bcolumns=(\d+)\s+rows=(\d+)/; + $bbi->{URX}=0+$1; $bbi->{URY}=0+$2; + } elsif (substr($head,0,3) eq 'FWS') { + $bbi->{FileFormat}='SWF'; # Macromedia ShockWave Flash + my $nbits=get_bits_msb($head, 64, 5); + no integer; + $bbi->{URX}=get_bits_msb($head, 69+ $nbits, $nbits)/20.0; + $bbi->{LLX}=get_bits_msb($head, 69, $nbits)/20.0; + $bbi->{URY}=get_bits_msb($head, 69+3*$nbits, $nbits)/20.0; + $bbi->{LLY}=get_bits_msb($head, 69+2*$nbits, $nbits)/20.0; + } elsif (substr($head,0,14) eq "gimp xcf file\0") { # GIMP XCF image data + $bbi->{SubFormat}='version.000'; + do_XCF: + $bbi->{FileFormat}='XCF'; + ($dummy,$bbi->{URX},$bbi->{URY},$dummy)=unpack("A14NNN", $head); + if ($dummy==0) { $bbi->{ColorSpace}='RGB' } + elsif ($dummy==1) { $bbi->{ColorSpace}='Gray' } + elsif ($dummy==2) { $bbi->{ColorSpace}='Indexed' } + } elsif ($head=~/\Agimp xcf v(\d\d\d)\0/) { + $bbi->{SubFormat}="version.$1"; + goto do_XCF; + } elsif ($head=~/\A\0\0\001\0[\001-\50]\0/) { # Windows ICO icon + $bbi->{FileFormat}='ICO'; + # An .ico file may contain multiple icons (hence [\001-50]); we report the + # properties of the very first one. Code based on ImageMagick. + # Imp: WinXP True color icons + ($dummy,$bbi->{URX},$bbi->{URY},$bbi->{'Info.colors'},$bbi->{'Info.reserved'}, + $bbi->{'Info.planes'},$bbi->{BitsPerSample})=unpack("A6CCCCvv", $head); + # more precisely: BitsPerSample is bits per pixel; + # Dat: Info.reserved, BitsPerSample and Info.planes are often 0 + } elsif (substr($head,0,4)eq"8BPS") { # PSD image data (Adobe Photoshop bitmap) + # based on PHP 4.2 image.c; untested + $bbi->{FileFormat}='PSD'; + ($dummy,$bbi->{URY},$bbi->{URX})=unpack("A14NN",$head); + } elsif (substr($head,0,8) eq "\%bitmap\0") { # Fuzzy Bitmap (FBM) image; untested + $bbi->{FileFormat}='FBM'; + @L=unpack("A8A8A8A8A8A8A12A12A12A12A80A80",$head); # <=256 chars OK + for (@L) { s@\0.*@@s } # make strings null-terminated + $bbi->{"Info.credits"}=pop(@L); # string + $bbi->{"Info.title"}=pop(@L); # string + goto SYerr if !defined ($bbi->{aspect}=c_numval(pop(@L))); + shift(@L); # magic + for my $item (@L) { goto SYerr if !defined($item=c_intval($item)) } + ( $bbi->{URX},$bbi->{URY},$bbi->{"Info.planes"},$bbi->{"Info.bits"}, + $bbi->{"Info.physbits"},$bbi->{"Info.rowlen"},$bbi->{"Info.plnlen"}, + $bbi->{"Info.clrlen"})=@L; + # char cols[8]; /* Width in pixels */ + # char rows[8]; /* Height in pixels */ + # char planes[8]; /* Depth (1 for B+W, 3 for RGB) */ + # char bits[8]; /* Bits per pixel */ + # char physbits[8]; /* Bits to store each pixel */ + # char rowlen[12]; /* Length of a row in bytes */ + # char plnlen[12]; /* Length of a plane in bytes */ + # char clrlen[12]; /* Length of colormap in bytes */ + # char aspect[12]; /* ratio of Y to X of one pixel */ + } elsif (substr($head,0,4)eq"\x59\xa6\x6a\x95") { # Sun raster images; untested + $bbi->{FileFormat}='SunRaster'; + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("NNN",$head); + #0 belong 0x59a66a95 Sun raster image data + #>4 belong >0 \b, %d x + #>8 belong >0 %d, + #>12 belong >0 %d-bit, + ##>16 belong >0 %d bytes long, + #>20 belong 0 old format, + ##>20 belong 1 standard, + #>20 belong 2 compressed, + #>20 belong 3 RGB, + #>20 belong 4 TIFF, + #>20 belong 5 IFF, + #>20 belong 0xffff reserved for testing, + #>24 belong 0 no colormap + #>24 belong 1 RGB colormap + #>24 belong 2 raw colormap + #>28 belong >0 colormap is %d bytes long + } elsif (substr($head,0,4)eq"\xf1\x00\40\xbb") { + $bbi->{FileFormat}='CMUWM'; # from xloadimage; untested + ($dummy,$bbi->{URX},$bbi->{URY},$bbi->{"Info.depth"})=unpack("NNNn",$head); + } elsif (substr($head,0,4) eq "\361\0\100\273") { # CMU window manager raster image data + # from xvl untested + $bbi->{FileFormat}='CMUWM'; + ($dummy,$bbi->{URX},$bbi->{URY},$bbi->{'Info.num_bits'})=unpack("VVVV",$head); + } elsif (substr($head,0,2)eq"\x52\xCC") { # Utah Raster Toolkit RLE images; untested + $bbi->{FileFormat}='RLE'; # from xloadimage + ($dummy,$bbi->{URX},$bbi->{URY},$bbi->{LLX},$bbi->{LLY})=unpack("A6vvvv",$head); + $bbi->{BitsPerSample}=vec($head,12,8)/vec($head,11,8); + $bbi->{SamplesPerPixel}=vec($head,11,8); + #0 leshort 0xcc52 RLE image data, + #>6 leshort x %d x + #>8 leshort x %d + #>2 leshort >0 \b, lower left corner: %d + #>4 leshort >0 \b, lower right corner: %d + #>10 byte&0x1 =0x1 \b, clear first + #>10 byte&0x2 =0x2 \b, no background + #>10 byte&0x4 =0x4 \b, alpha channel + #>10 byte&0x8 =0x8 \b, comment + #>11 byte >0 \b, %d color channels + #>12 byte >0 \b, %d bits per pixel + #>13 byte >0 \b, %d color map channels + } elsif (substr($head,0,32)eq"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377") { # Kodak Photograph on CD Image + # derived from xloadimage; untested + $dummy=3587-length($head); + goto IOerr if $dummy=read $F, $head, $dummy, length($head); + goto SYerr if substr($head,2048,7) ne "PCD_IPI"; + $bbi->{FileFormat}='PCD'; + # vvv funny: an image format with fixed (hard-wired) image size + if ((vec($head,3586,8)&1)!=0) { ($bbi->{URY},$bbi->{URX})=(768,512) } + else { ($bbi->{UXY},$bbi->{URY})=(768,512) } + } elsif ($head=~/\A\0\0..\0\0\0[\001-\50]\0\0\0[\0-\002]\0\0\0([\001-\77])/s) { + $bbi->{FileFormat}='XWD'; + $bbi->{SubFormat}='MSBfirst'; + $bbi->{'Info.depth'}=ord($1); + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("A16NN",$head); + } elsif ($head=~/\A..\0\0[\001-\50]\0\0\0[\0-\002]\0\0\0([\001-\77])\0\0\0/s) { + $bbi->{FileFormat}='XWD'; + $bbi->{SubFormat}='LSBfirst'; + $bbi->{'Info.depth'}=ord($1); + ($dummy,$bbi->{URX},$bbi->{URY})=unpack("A16VV",$head); + } elsif ($head=~/\A\0\001\0[\010-\377](?:\0.|\001\0)\0.....(?:[\001-\37].|\0[^\0]|\40\0){2}/s) { # GEM Bit image + # from xloadimage; untested + $bbi->{FileFormat}='GEM'; + ($dummy,$bbi->{'Info.hlen'},$bbi->{'Info.colors'},$bbi->{'Info.patlen'}, + $bbi->{URX},$bbi->{URY},$bbi->{'Info.llen'},$bbi->{'Info.lines'})=unpack("nnnnnnnn",$head); + } elsif ($head=~/\A....\0\0\0\004....\0\0[\0-\001].\0\0[\0-\003]./s) { # McIDAS areafile + # from xloadimage; untested + $bbi->{FileFormat}='McIDAS'; + $bbi->{SubFormat}='MSBfirst'; + ($dummy,$bbi->{URY},$bbi->{URX})=unpack("A32NN",$head); + } elsif ($head=~/\A....\004\0\0\0.....[\0-\001]\0\0.[\0-\003]\0\0/s) { # McIDAS areafile + # from xloadimage; untested + $bbi->{FileFormat}='McIDAS'; + $bbi->{SubFormat}='LSBfirst'; + ($dummy,$bbi->{URY},$bbi->{URX})=unpack("A32VV",$head); + } elsif ($head=~/\AVIEW/) { + # from xv; untested + $dummy="NNNNNN"; $bbi->{SubFormat}='MSBfirst'; + do_PM: + $bbi->{FileFormat}='PM'; + ($dummy,$bbi->{'Info.num_planes'},$bbi->{URX},$bbi->{URY}, + $bbi->{'Info.num_bands'}, $bbi->{'Info.pixel_format'})=unpack($dummy,$head); + } elsif ($head=~/\AWEIV/) { + $dummy="VVVVVV"; $bbi->{SubFormat}='LSBfirst'; + goto do_PM; + } elsif ($head=~/\A\001\332/) { # SGI 'rgb' image data + $bbi->{SubFormat}='MSBfirst'; $dummy="nCCnnnn"; + do_SGI: + $bbi->{FileFormat}='SGI'; # from xv IRIS; untested + ($dummy,$bbi->{'Info.compression'},$bbi->{'Info.precision'},$bbi->{'Info.dimension'}, + $bbi->{URX},$bbi->{URY},$bbi->{SamplesPerPixel})=unpack($dummy,$head); + if ($bbi->{'Info.compression'}==0) { $bbi->{'Info.compression'}='None' } + elsif ($bbi->{'Info.compression'}==1) { $bbi->{'Info.compression'}='RLE' } + $dummy=substr($head,80); + $bbi->{'Info.comment'}=$1 if $dummy=~m@\A([^\0])\0@s; + # Dat: Info.dimension is 2 or 3 + ## See http://reality.sgi.com/grafica/sgiimage.html + } elsif ($head=~/\A\332\001/) { # SGI 'rgb' image data + $bbi->{SubFormat}='MSBfirst'; $dummy="vCCvvvvv"; + goto do_SGI; + } elsif (substr($head,0,9) eq "SIMPLE =") { + $bbi->{FileFormat}='FITS'; + while ($head!~/\bEND/) { + goto IOerr if 1>read $F, $head, 1024, length($head); + } + $bbi->{'Info.bits_per_pixel'}=$1 if $head=~/\bBITPIX\s*=\s*(\d+)/; + $bbi->{'Info.num_axis'}=$1 if $head=~/\bNAXIS\s*=\s*(\d+)/; + $bbi->{URX}=$1 if $head=~/\bNAXIS1\s*=\s*(\d+)/; + $bbi->{URY}=$1 if $head=~/\bNAXIS2\s*=\s*(\d+)/; + $bbi->{'Info.depth'}=$1 if $head=~/\bNAXIS3\s*=\s*(\d+)/; + $bbi->{'Info.data_max'}=$1 if $head=~/\bDATAMAX\s*=\s*(\d+)/; + $bbi->{'Info.data_min'}=$1 if $head=~/\bDATAMIN\s*=\s*(\d+)/; + # Dat: it would be quite hard to extract the dimensions... + ## FITS is the Flexible Image Transport System, the de facto standard for + ## data and image transfer, storage, etc., for the astronomical community. + ## (FITS floating point formats are big-endian.) + #0 string SIMPLE\ \ = FITS image data + #>109 string 8 \b, 8-bit, character or unsigned binary integer + #>108 string 16 \b, 16-bit, two's complement binary integer + #>107 string \ 32 \b, 32-bit, two's complement binary integer + #>107 string -32 \b, 32-bit, floating point, single precision + #>107 string -64 \b, 64-bit, floating point, double precision + } elsif ($head=~/\A(?:NJPL1I|CCSD3Z|LBLSIZE=)/) { + # from xv, imagemagick; untested + $bbi->{FileFormat}='VICAR'; + while ($head!~/\bEND/) { + goto IOerr if 1>read $F, $head, 1024, length($head); + } + $bbi->{URX}=$1 if $head=~/\b(?:IMAGE_LINES|LINES|NL)\s*=\s*(\d+)/; + $bbi->{URY}=$1 if $head=~/\b(?:LINE_SAMPLES|NS)\s*=\s*(\d+)/; + ##------------------------------------------------------------------------------ + ## vicar: file(1) magic for VICAR files. + ## + ## From: Ossama Othman <othman@astrosun.tn.cornell.edu + ## VICAR is JPL's in-house spacecraft image processing program + ## VICAR image + #0 string LBLSIZE= VICAR image data + #>32 string BYTE \b, 8 bits = VAX byte + #>32 string HALF \b, 16 bits = VAX word = Fortran INTEGER*2 + #>32 string FULL \b, 32 bits = VAX longword = Fortran INTEGER*4 + #>32 string REAL \b, 32 bits = VAX longword = Fortran REAL*4 + #>32 string DOUB \b, 64 bits = VAX quadword = Fortran REAL*8 + #>32 string COMPLEX \b, 64 bits = VAX quadword = Fortran COMPLEX*8 + ## VICAR label file + #43 string SFDU_LABEL VICAR label file + } elsif (substr($head,0,4) eq "IT01" or substr($head,0,4) eq "IT02") { # untested + $bbi->{FileFormat}='FIT'; # do not cunfuse FIT and FITS + ($dummy,$bbi->{URX},$bbi->{URY},$bbi->{'Info.num_bits'})=unpack("NNNN",$head); + } elsif (substr($head,0,4) eq "#FIG") { + $bbi->{FileFormat}='FIG'; + $bbi->{SubFormat}=$1 if $head=~/\A....[ \t]+(\S+)/s; + ## FIG (Facility for Interactive Generation of figures), an object-based format + ## (as handled by xfig). There is no size information, fig2dev saves bounding + ## box as EPS + #0 string #FIG FIG image text + #>5 string x \b, version %.3s + +## These file formats below are known to the Debian potato file(1) command, +## but the magic(5) file doesn't tell us how to extract size information +## +## NITF is defined by United States MIL-STD-2500A +#0 string NITF National Imagery Transmission Format +#>25 string >\0 dated %.14s +# +## NIFF (Navy Interchange File Format, a modification of TIFF) images +#0 string IIN1 NIFF image data +## ITC (CMU WM) raster files. It is essentially a byte-reversed Sun raster, +## 1 plane, no encoding. +## Artisan +#0 long 1123028772 Artisan image data +#>4 long 1 \b, rectangular 24-bit +#>4 long 2 \b, rectangular 8-bit with colormap +#>4 long 3 \b, rectangular 32-bit (24-bit with matte) +# +# +## PHIGS +#0 string ARF_BEGARF PHIGS clear text archive +#0 string @(#)SunPHIGS SunPHIGS +## version number follows, in the form m.n +##>40 string SunBin binary +##>32 string archive archive +## +## GKS (Graphics Kernel System) +#0 string GKSM GKS Metafile +#>24 string SunGKS \b, SunGKS +# +## CGM image files +#0 string BEGMF clear text Computer Graphics Metafile +## XXX - questionable magic +#0 beshort&0xffe0 0x0020 binary Computer Graphics Metafile +#0 beshort 0x3020 character Computer Graphics Metafile +# +## MGR bitmaps (Michael Haardt, u31b3hs@pool.informatik.rwth-aachen.de) +#0 string yz MGR bitmap, modern format, 8-bit aligned +#0 string zz MGR bitmap, old format, 1-bit deep, 16-bit aligned +#0 string xz MGR bitmap, old format, 1-bit deep, 32-bit aligned +#0 string yx MGR bitmap, modern format, squeezed +# +## image file format (Robert Potter, potter@cs.rochester.edu) +#0 string Imagefile\ version- iff image data +## this adds the whole header (inc. version number), informative but longish +#>10 string >\0 %s +# +## other images +#0 string This\ is\ a\ BitMap\ file Lisp Machine bit-array-file +#0 string \!\! Bennet Yee's "face" format +# +## From SunOS 5.5.1 "/etc/magic" - appeared right before Sun raster image +## stuff. +## +#0 beshort 0x1010 PEX Binary Archive +# +## Visio drawings +#03000 string Visio\ (TM)\ Drawing %s +# +#0 string IC PC icon data +#0 string PI PC pointer image data +#0 string CI PC color icon data +#0 string CP PC color pointer image data + + } elsif (substr($head,0,2) eq "\37\x9d") { + # .Z compress(1)ed file; may be an image (i.e pbm.Z) + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='compress'; + } elsif (substr($head,0,2) eq "\37\x8b") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='gzip'; + } elsif (substr($head,0,2) eq "\37\x36") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='pack'; + } elsif ($head=~/\A(?:\377\037|\037\377)/) { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='compact'; + } elsif (substr($head,0,3) eq "BZh") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='bzip2'; + } elsif (substr($head,0,2) eq "BZ") { # check must be after bzip + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='bzip1'; + } elsif (substr($head,0,2) eq "\x76\xff") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='squeeze'; + } elsif (substr($head,0,2) eq "\x76\xfe") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='crunch'; + } elsif (substr($head,0,2) eq "\x76\xfd") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='LZH'; + } elsif (substr($head,0,2) eq "\037\237") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='freeze2'; + } elsif (substr($head,0,2) eq "\037\236") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='freeze1'; + } elsif (substr($head,0,2) eq "\037\240") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='SCO.LZH'; + } elsif (substr($head,0,9) eq "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a") { + $bbi->{FileFormat}='compress'; $bbi->{SubFormat}='lzop'; + + } elsif (substr($head,0,2) eq "\x60\xEA") { + $bbi->{FileFormat}='archive'; $bbi->{SubFormat}='ARJ'; + } elsif ($head=~/\A..-l[hz]/s) { + $bbi->{FileFormat}='archive'; $bbi->{SubFormat}='LHA'; + } elsif (substr($head,0,4) eq "Rar!") { + $bbi->{FileFormat}='archive'; $bbi->{SubFormat}='RAR'; + } elsif (substr($head,0,4) eq "UC2\x1A") { + $bbi->{FileFormat}='archive'; $bbi->{SubFormat}='UC2'; + } elsif (substr($head,0,4) eq "PK\003\004") { + $bbi->{FileFormat}='archive'; $bbi->{SubFormat}='ZIP'; + } elsif (substr($head,0,4) eq "\xDC\xA7\xC4\xFD") { + $bbi->{FileFormat}='archive'; $bbi->{SubFormat}='ZOO'; + + } elsif ($head=~/\A.PC Research, Inc/s) { + $bbi->{FileFormat}='G3'; + $bbi->{SubFormat}='Digifax'; + # Dat: determining $bbi->{URX} and $bbi->{URY} would require a complex + # and full parsing of the G3 facsimile data + } elsif ($head=~/\A\367[\002-\005]/) { + # Dat: \005 is rather arbitrary here + goto FF__DVI; + } elsif ($head=~/\A[\36-\77](?:\001[\001\11]|\0[\002\12\003\13])\0\0/ and + vec($head, 1, 8)<=11 and (vec($head, 16, 8)<=8 or vec($head, 16, 8)==24)) { # potato magic + my @types=(0,'Map','RGB','Gray',0,0,0,0,0,'Map.RLE','RGB.RLE','Gray.RLE'); + $bbi->{FileFormat}='TGA'; + $bbi->{SubFormat}=$types[vec($head,2,8)]; + ($dummy,$bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=unpack("A8vvvv",$head); + # Imp: verify LLX!=0 URX-LLX + } elsif (30<=vec($head, 0, 8) and vec($head, 0, 8)<=63 and + vec($head, 1, 8)<=11 and (vec($head, 16, 8)<=8 or vec($head, 16, 8)==24)) { + # ^^^ Dat: TGA doesn't have a fixed-format header, so this detection is quite + # weak. That's why it is the last one we perform. + $bbi->{FileFormat}='TGA'; + $bbi->{SubFormat}='fallback'; + ($dummy,$bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=unpack("A8vvvv",$head); + # Imp: verify LLX!=0 URX-LLX + } elsif ($head=~/^PicData:\s*(\d+)\s*(\d+)\s*(\d+)/m) { # grayscale Faces Project imagegrayscale Faces Project image; untested + # ^^^ Dat: regexp match is quite weak; perform check last + $bbi->{FileFormat}='Faces'; # from xloadimage + $bbi->{URX}=$1+0; $bbi->{URY}=$2+0; $bbi->{"Info.bitdepth"}=$3+0; + } elsif ($head=~/\A\001\0/s) { # really weak + $bbi->{FileFormat}='G3'; + $bbi->{SubFormat}='MSBfirst.bytepad'; + } elsif ($head=~/\A\0\001/s) { # really weak + $bbi->{FileFormat}='G3'; + $bbi->{SubFormat}='LSBfirst.bytepad'; + } elsif ($head=~/\A\24\0/s) { # really weak + $bbi->{FileFormat}='G3'; + $bbi->{SubFormat}='MSBfirst.raw'; + } elsif ($head=~/\A\0\24/s) { # really weak + $bbi->{FileFormat}='G3'; + $bbi->{SubFormat}='LSBfirst.raw'; + # Dat: determining $bbi->{URX} and $bbi->{URY} would require a complex + # and full parsing of the G3 facsimile data + } else { + $bbi->{Error}='unrecognised FileFormat' + } + done: + if ($have_paper and exists $bbi->{URX} and exists $bbi->{URY}) { + ($bbi->{Paper},$bbi->{PaperWidth},$bbi->{PaperHeight})=@L[0,1,2] if + @L=Htex::papers::valid_bp($bbi->{URX},$bbi->{URY},$bbi->{LLX},$bbi->{LLY}); + } else { + delete $bbi->{LLX} if !exists $bbi->{URX}; + delete $bbi->{LLY} if !exists $bbi->{URY}; + } + $bbi +} + +sub import { + no strict 'refs'; + my $package=(caller())[0]; + shift; + ($have_paper,$have_pdf)=(1,1); + for my $p (@_) { + if ($p eq '-PDF') { $have_pdf=0 } + elsif ($p eq '-paper') { $have_paper=0 } + else { *{$package."::$p"}=\&{$p} } + } + if ($have_pdf) { require Htex::PDFread; import Htex::PDFread } + if ($have_paper) { require Htex::papers; import Htex::papers } +} + +just::end} + +BEGIN{$ INC{'vars.pm'}='vars.pm'} { +package vars; +use just; +# by pts@fazekas.hu at Wed Jan 10 12:42:08 CET 2001 +require 5.002; +sub import { + my $callpack = caller; + my ($sym, $ch, $sym9); + shift; + for $sym0 (@_) { + die("Can't declare another package's variables") if $sym0 =~ /::/; + ($ch, $sym) = unpack('a1a*', $sym0); + *{"${callpack}::$sym"} = + ( $ch eq "\$" ? \$ {"${callpack}::$sym"} + : $ch eq "\@" ? \@ {"${callpack}::$sym"} + : $ch eq "\%" ? \% {"${callpack}::$sym"} + : $ch eq "\*" ? \* {"${callpack}::$sym"} + : $ch eq "\&" ? \& {"${callpack}::$sym"} + : die("'$ch$sym' is not a valid variable name\n") + ); + } +} +just::end} + +BEGIN{$ INC{'Htex/PDFread.pm'}='Htex/PDFread.pm'} { +package Htex::PDFread; +# by pts@fazekas.hu at Sat Dec 21 21:28:09 CET 2002 +use just; +use integer; +use strict; +use Pts::string; +use vars qw($pdf_last_ref0); + +my @pdf_classify; +#** @param $_[0] a string in PDF source format +#** @return a rewritten string, or "" if $_[0] is truncated, or undef if +#** there is a parse error +sub pdf_rewrite($;$) { + my $explicit_term_p=$_[1]; + my $L=length($_[0]); + return "" if $L==0; + my $S="$_[0]\n>> "; # add sentinel + my $I=0; + my $O; + my $RET=""; + if (!@pdf_classify) { + # Dat: PDF whitespace(0) is [\000\011\012\014\015\040] + # Dat: PDF separators(10) are < > { } [ ] ( ) / % + # Dat: PDF regular(40) character is any of [\000-\377] which is not whitespace or separator + @pdf_classify=(40)x256; + @pdf_classify[ord('<'),ord('>'),ord('{'),ord('}'),ord('['),ord(']'), + ord('('),ord(')'),ord('/'),ord('%')]=(10,11,12,13,14,15,16,17,18,19); + @pdf_classify[000,011,012,014,015,040]=(0,0,0,0,0,0); + } + while ($I<$L) { + $O=$pdf_classify[vec($S,$I,8)]; + if ($O==0) { # whitespace + } elsif (12<=$O and $O<=15) { # one-char token + $RET.=" ".substr($S,$I,1); + } elsif ($O==18 or $O==40) { # name or /name + my $P=0; + if ($O==18) { $I++; $RET.=" /" } else { $RET.=" "; $P=1 } + my $T=""; + $T.=chr($O) while $pdf_classify[$O=vec($S,$I++,8)]==40; + $I--; + ## die $I; + $T=~s@([^A-Za-z0-9_.-])@sprintf"#%02x",ord$1@ge; # make name safe + $RET.=$T; + return $RET if $P and ($T eq "stream" or $T eq "endobj" or $T eq "startxref"); + next + } elsif ($O==11) { # `>' + return "" if ++$I==$L; # only `>' has arrived + return undef if vec($S,$I,8)!=62; # err(">> expected"); + $RET.=" >>"; + } elsif ($O==16) { # string + my $T=""; + my $depth=1; $I++; + while ($I<$L) { + $O=vec($S,$I++,8); bcont: + ## print chr($O),":$depth\n"; + if ($O==40) { $depth++ } + elsif ($O==41) { last unless --$depth } + elsif ($O==92) { # a backslash + $O=vec($S,$I++,8); + if (48<=$O && $O<=55) { + my $P=$O-48; $O=vec($S,$I++,8); + if (48<=$O && $O<=55) { + my $Q=$O-48; $O=vec($S,$I++,8); + if (48<=$O && $O<=55) { $T.=chr(255&($P<<6|$Q<<3|($O-48))) } + else { $T.=chr($P<<3|$Q); goto bcont } + } else { $T.=chr($P); goto bcont } + } elsif ($O==110) { $O=10 } + elsif ($O==114) { $O=13 } + elsif ($O==116) { $O=9 } + elsif ($O== 98) { $O=8 } + elsif ($O==102) { $O=12 } + } + $T.=chr($O) + } # WHILE + return "" if $depth; # err("unterminated string") + $T=~s@([^A-Za-z0-9_.-])@sprintf"\\%03o",ord$1@ge; # make string safe + $RET.=" ($T)"; next + } elsif ($O==10) { # hex string + $O=vec($S,++$I,8); + if ($O==60) { $RET.=" <<"; $I++; next } + # parse hexadecimal string + my $half=0x100; + my $T=""; + while (1) { + 1 until $pdf_classify[$O=vec($S,$I++,8)]; # skip whitespace + if ($O==62) { $T.=chr($half&0xFF) if $half&0x1000; last } # '>' + return undef if $pdf_classify[$O]!=40; # err("unexpected token in hex") + if (65<=$O and $O<=70) { $half+=$O-55 } + elsif (97<=$O and $O<=102) { $half+=$O-87 } + elsif (48<=$O and $O<=57) { $half+=$O-48 } + else { return undef } # err("illegal hex digit") + if ($half&0x1000) { $T.=chr($half&0xFF); $half=0x100 } + else { $half<<=4 } + } + $T=~s@([^A-Za-z0-9_.-])@sprintf"\\%03o",ord$1@ge; # make string safe + $RET.=" ($T)"; next + } elsif ($O==19) { # single-line comment + $I++ while ($O=vec($S,$I,8))!=13 && $O!=10; + ## print STDERR "I=$I L=$L\n"; + next + } else { return undef } # err("token expected") # $O==11, $O==17 + $I++ + } ## WHILE + ## print STDERR "XI=$I L=$L\n"; + # die $explicit_term_p; + return "" if $explicit_term_p; + ($I>$L) ? "" : $RET +} + +# Unit test: +#die unless pdf_rewrite("hello \n\t world\n\t") eq " hello world"; +#die unless pdf_rewrite('(hel\)lo\n\bw(or)ld)') eq ' (hel\051lo\012\010w\050or\051ld)'; +#die unless pdf_rewrite('(hel\)lo\n\bw(orld)') eq ''; +#die unless pdf_rewrite('[ (hel\)lo\n\bw(or)ld)>>') eq ' [ (hel\051lo\012\010w\050or\051ld) >>'; +#die unless pdf_rewrite('>') eq ""; +#die unless pdf_rewrite('<') eq ""; +#die unless pdf_rewrite('< ') eq ""; +#die unless !defined pdf_rewrite('< <'); +#die unless !defined pdf_rewrite('> >'); +#die unless pdf_rewrite('[ (hel\)lo\n\bw(or)ld) <') eq ""; +#die unless pdf_rewrite("<\n3\t1\r4f5C5 >]") eq ' (1O\134P) ]'; +#die unless pdf_rewrite("<\n3\t1\r4f5C5") eq ""; +#die unless !defined pdf_rewrite("<\n3\t1\r4f5C5]>"); +#die unless pdf_rewrite("% he te\n<\n3\t1\r4f5C5 >]endobj<<") eq ' (1O\134P) ] endobj'; +#die unless pdf_rewrite("") eq ""; +#die unless pdf_rewrite("<<") eq " <<"; +#die unless pdf_rewrite('%hello') eq ''; +#die unless pdf_rewrite("alma\n%korte\n42") eq ' alma 42'; +#die unless pdf_rewrite('/Size 42') eq ' /Size 42'; +#die "OK"; + +#** Reads a single PDF indirect object (without its stream) from a PDF file. +#** Does some trivial transformations on it to make later regexp matching +#** easier. Stops at `stream', `endobj' and `startxref'. +#** @param $_[0] a filehandle (e.g \*STDIN), correctly positioned in the PDF +#** file to the beginning of the object data (i.e just before `5 0 obj') +#** @return string containing PDF source code, or undef on error +sub pdf_read_obj($) { + my $F=$_[0]; my $L=1024; my $M; my $S=""; my $RET; + while (1) { # read as much data as necessary + return undef if 0>($M=read $F, $S, $L, length($S)); + $RET=pdf_rewrite($S,1); + ## print "($S)\n"; + return undef if !defined $RET; # parse error + return $RET if length $RET; # OK, found object + return undef if $M==0; # cannot read more, reached EOF + $L<<=1; + } + #$S=~m@[\000\011\012\014\015\040]*( + # %[^\r\n]*[\r\n]| + # /?[^\000\011\012\014\015\040<>{}\[\]()/%]*(?=[\000\011\012\014\015\040<>{}\[\]()/%])| # unterminated + # <<|>>|\{|}|\[|]| + # <[a-fA-F0-9\000\011\012\014\015\040]*>| # hex string + # \((?:[^\\()]+|\\[\000-\377])*\)| # literal string, the easy way + # \( # an unfinished string, needs special care + #)@gx +} + +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file, positioned +#** just before an `xref' table +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4; will be extended +#** @return the `trailer' section after the `xref'; or undef +sub pdf_read_xref($$) { + # made much faster at Wed Dec 18 09:50:23 CET 2002 + my $T; + my $E; + my $F=$_[0]; + my $XREF=$_[1]; + return undef if 8>read $F, $T, 1024; + return undef unless $T=~s@\A\s*xref\s+(\d+)\s+(\d+)\s+(?=\S)@@; + my ($first,$len,$flen); + while (1) { + ($first,$len)=($1+0,$2+0); + ## print " $first + $len\n"; + $flen=($len*=20)-length($T)+20; + return undef unless $flen<1 or $flen==read $F, $T, $flen, length($T); + for (my $I=0;$I<$len;$I+=20, $first++) { + $E=substr($T, $I, 20); + return undef unless $E=~/\A(\d{10})\s(\d{5})\s([nf])\s\s/; + ## print "($1 $2 $3)\n"; + $XREF->[$2+0][$first]=$1+0 if $3 eq 'n'; + } + $E=substr($T, $len); + last if $E!~s@\A\s*(\d+)\s*(\d+)\s+(?=\S)@@; # next section + $T=$E; + } + + # die(-length($T)+$len); + ## die tell($F); + return undef if length($T)!=$len and !seek $F, -length($T)+$len, 1; + ## die tell($F); + return undef unless defined($T=pdf_read_obj($F)); + $XREF->[0][0]=undef if defined $XREF->[0]; + $XREF->[0][0]=$1+0 if $T=~m@ /Prev (\d+)@; # remember /Prev xref table + return undef unless $T=~m@\A trailer( .*) startxref\Z(?!\n)@s; + $1 +} + +$pdf_last_ref0=0; +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4 +#** @param $_[2] an object number +#** @param $_[3] a generation number +#** @return PDF source code of the reference, or undef +sub pdf_ref($$$$) { + my $F=$_[0]; my $XREF=$_[1]; my $ON=$_[2]+0; my $GN=$_[3]+0; + my $T; + $pdf_last_ref0=$ON if $GN==0; + ## print "REF $ON $GN;\n"; + until (ref $XREF->[$GN] and defined ($T=$XREF->[$GN][$ON])) { + return undef if !ref $XREF->[0] or !defined $XREF->[0][0]; # no /Prev entry, `$ON $GN R' not found + return undef unless seek $F, $XREF->[0][0], 0; + return undef if !defined pdf_read_xref($F,$XREF); + } + ## print "REF at $T;\n"; + return undef unless seek $F, $T, 0; + return undef unless defined($T=pdf_read_obj($F)); + ## print "REF=($T);\n"; + return undef unless $T=~s@\A (\d+) (\d+) obj\b(.*) (endobj|stream)\Z(?!\n)@$3@s; + $T +} + +#** Gets a key from a direct dict, and resolves it if it is an indirect object +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4 +#** @param $_[2] a PDF source dict (`<< ... >>') or array +#** @param $_[3] a key (`/...') +sub pdf_get($$$$) { + my $F=$_[0]; my $XREF=$_[1]; my $S=$_[2]; my $KEY=$_[3]; my $POS=0; + my $DEPTH=0; my $IS_DICT; my $C=0; my $N=0; + ## print "\n"; + while ($S=~/\G (\S+)/g) { + $C=vec($1,0,8); $POS=pos($S); + ## print "($1) $DEPTH $N\n"; + if ($1 eq '>>' or $1 eq ']') { + return undef if 0==$DEPTH--; + last if !$DEPTH; + $N++ if 1==$DEPTH; + } + elsif ($DEPTH==1 and !$IS_DICT and $KEY==$N) { $POS=pos($S)-=length($1)+1; goto do_ret } + elsif ($1 eq '<<') { $IS_DICT=1 if 0==$DEPTH++ } + elsif ($1 eq '[') { + if (0==$DEPTH++) { + $IS_DICT=0; + return undef if $KEY!~/\A(\d+)\Z(?!\n)/; # err("non-numeric key in array") + } + } + elsif (0==$DEPTH) { return undef } # not in a composite object + elsif (1!=$DEPTH) { next } + elsif (!$IS_DICT) { $N++ } + elsif ($C==40) { $N++ } # `(': string or bare name + elsif ($C>=47 and $C<=57) { # '/': /name 0..9: number + ## print "TRY ($1) KEY=$KEY.\n"; + next if ($N++&1)==1 or $1 ne $KEY; + do_ret: + ## print substr($S,pos($S)),";;\n"; + return pdf_ref $F, $XREF, $1, $2 if $S=~/\G (\d+) (\d+) R\b/gc; + ## print substr($S,pos($S)),"::\n"; + $DEPTH=0; + while ($S=~/\G( \S+)/g) { + if ($1 eq ' <<' or $1 eq ' [') { $DEPTH++ } + elsif ($1 eq ' >>' or $1 eq ' ]') { + ## die "($1)\n"; + return undef if 0==$DEPTH--; # err("nesting") + return substr($S,$POS,pos($S)-$POS) if 0==$DEPTH; + } elsif ($DEPTH==0) { return $1 } + } + } else { $N++ } # bare name + } + return undef if $POS!=length($S); # err("invalid source dict"); + "" # not found +} + +# Unit test: +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 0) eq ' al'; +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 1) eq ' makorte'; +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 2) eq ' 42'; +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 3) eq ''; +#die unless pdf_get(\*STDIN, 0, ' [ << >> ]', 0) eq ' << >>'; +#die unless pdf_get(\*STDIN, 0, ' [ << >> ]', 1) eq ''; +#die unless pdf_get(\*STDIN, 0, ' [ << >> [ al makorte 42 ] ]', 1) eq ' [ al makorte 42 ]'; +#die unless pdf_get(\*STDIN, 0, ' << /Alma [ 1 2 ] /Korte [ 3 4 ] >>', '/Korte') eq ' [ 3 4 ]'; +#die unless !defined pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', '/Name'); +#die unless !defined pdf_get(\*STDIN, 0, ' << al makorte 42 >>', 42); +#die unless pdf_get(\*STDIN, 0, ' << al makorte 42 137 >>', 42) eq ' 137'; +#die unless pdf_get(\*STDIN, 0, ' << al makorte >>', 'al') eq ""; +#die "OK"; + +#** Reported boxes: /MediaBox /CropBox /BleedBox /TrimBox /ArtBox +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4 +#** @param $_[2] a PDF source dict (`<< ... >>') of /Type/Catalog +#** /Type/Pages or /Type/Page +#** @param $_[3] hashref to update. $_[3]{BleedBox}[2] will be the URX corner +#** of the BleedBox +sub pdf_get_boxes($$$$) { + my $F=$_[0]; my $XREF=$_[1]; my $S=$_[2]; my $bbi=$_[3]; + return if !defined $S; + for my $name (qw{MediaBox CropBox BleedBox TrimBox ArtBox}) { + my $box=pdf_get($F, $XREF, $S, "/$name"); + next if !defined $box or !length $box + or $box!~m@ \[ ([0-9eE.-]+) ([0-9eE.-]+) ([0-9eE.-]+) ([0-9eE.-]+) \]\Z(?!\n)@ + or !defined c_numval($1) or !defined c_numval($2) or !defined c_numval($3) or !defined c_numval($4); + ($bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=($1+0,$2+0,$3+0,$4+0) if $name eq 'MediaBox'; + my $name2="Info.$name"; + ($bbi->{$name2}[0],$bbi->{$name2}[1],$bbi->{$name2}[2],$bbi->{$name2}[3])=($1+0,$2+0,$3+0,$4+0); + } +} + +sub import { + no strict 'refs'; + my $package=(caller())[0]; + shift; + for my $p (@_ ? @_ : qw{pdf_get_boxes pdf_get pdf_read_xref pdf_read_obj + pdf_rewrite pdf_ref}) { *{$package."::$p"}=\&{$p} } +} + +just::end} + +BEGIN{$ INC{'Htex/papers.pm'}='Htex/papers.pm'} { +package Htex::papers; +# contains paper size information +# by pts@fazekas.hu at Sun Dec 22 00:30:58 CET 2002 +use just; +use integer; +use strict; +use Htex::dimen; + +my @papers=( +# +# paper.txt +# by pts@fazekas.hu at Tue Jan 16 18:21:59 CET 2001 +# by pts@fazekas.hu at Tue Jan 16 19:13:16 CET 2001 +# +# Examined: dvips, gs, libpaperg +# +# all units are measured in Big Points (bp) +# 72 bp == 1 in +# 2.54 cm == 1 in +# +# papername width height +qw{Comm10 297 684}, +qw{Monarch 279 540}, +qw{halfexecutive 378 522}, + +qw{Legal 612 1008}, +qw{Statement 396 612}, +qw{Tabloid 792 1224}, +qw{Ledger 1224 792}, +qw{Folio 612 936}, +qw{Quarto 610 780}, +qw{7x9 504 648}, +qw{9x11 648 792}, +qw{9x12 648 864}, +qw{10x13 720 936}, +qw{10x14 720 1008}, +qw{Executive 540 720}, +qw{ISOB0 2835 4008}, +qw{ISOB1 2004 2835}, +qw{ISOB2 1417 2004}, +qw{ISOB3 1001 1417}, +qw{ISOB4 709 1001}, +qw{ISOB5 499 709}, +qw{ISOB6 354 499}, +qw{ISOB7 249 354}, +qw{ISOB8 176 249}, +qw{ISOB9 125 176}, +qw{ISOB10 88 125}, +qw{C7 230 323}, +qw{DL 312 624}, + +qw{a3 842 1190}, # defined by Adobe +qw{a4 595 842}, # defined by Adobe; must precede a4small + +# a4small should be a4 with an ImagingBBox of [25 25 570 817].}, +qw{a4small 595 842}, +qw{letter 612 792}, # must precede lettersmall +# lettersmall should be letter with an ImagingBBox of [25 25 587 767]. +qw{lettersmall 612 792}, +# note should be letter (or some other size) with the ImagingBBox +# shrunk by 25 units on all 4 sides. +qw{note 612 792}, +qw{letterLand 792 612}, +# End of Adobe-defined page sizes + +qw{a0 2380 3368}, +qw{a1 1684 2380}, +qw{a2 1190 1684}, +qw{a5 421 595}, +qw{a6 297 421}, +qw{a7 210 297}, +qw{a8 148 210}, +qw{a9 105 148}, +qw{a10 74 105}, +qw{b0 2836 4008}, +qw{b1 2004 2836}, +qw{b2 1418 2004}, +qw{b3 1002 1418}, +qw{b4 709 1002}, +qw{b5 501 709}, # defined by Adobe + +qw{a0Land 3368 2380}, +qw{a1Land 2380 1684}, +qw{a2Land 1684 1190}, +qw{a3Land 1190 842}, +qw{a4Land 842 595}, +qw{a5Land 595 421}, +qw{a6Land 421 297}, +qw{a7Land 297 210}, +qw{a8Land 210 148}, +qw{a9Land 148 105}, +qw{a10Land 105 74}, +qw{b0Land 4008 2836}, +qw{b1Land 2836 2004}, +qw{b2Land 2004 1418}, +qw{b3Land 1418 1002}, +qw{b4Land 1002 709}, +qw{b5Land 709 501}, + +qw{c0 2600 3677}, +qw{c1 1837 2600}, +qw{c2 1298 1837}, +qw{c3 918 1298}, +qw{c4 649 918}, +qw{c5 459 649}, +qw{c6 323 459}, + +# vvv U.S. CAD standard paper sizes +qw{archE 2592 3456}, +qw{archD 1728 2592}, +qw{archC 1296 1728}, +qw{archB 864 1296}, +qw{archA 648 864}, + +qw{flsa 612 936}, # U.S. foolscap +qw{flse 612 936}, # European foolscap +qw{halfletter 396 612}, +qw{csheet 1224 1584}, # ANSI C 17x22 +qw{dsheet 1584 2448}, # ANSI D 22x34 +qw{esheet 2448 3168}, # ANSI E 34x44 +qw{17x22 1224 1584}, # ANSI C 17x22 +qw{22x34 1584 2448}, # ANSI D 22x34 +qw{34x44 2448 3168}, # ANSI E 34x44 +); + +#** @param $_[0] width, in bp +#** @param $_[1] height, in bp +#** @return () or ("papername", width.bp, height.bp) +sub valid_bp($$;$$) { + no integer; + my ($W1,$H1)=(defined$_[2]?$_[2]:0,defined$_[3]?$_[3]:0); + my ($WW,$HH)=(Htex::dimen::dimen2bp($_[0]-$W1), Htex::dimen::dimen2bp($_[1]-$H1)); + # Dat: 1mm == 720/254bp; 3mm =~ 8.5bp + no integer; + for (my $I=0; $I<@papers; $I+=3) { + return @papers[$I,$I+1,$I+2] if abs($papers[$I+1]-$WW)<=8.5 and abs($papers[$I+2]-$HH)<=8.5; + } + () +} + +#** @param $_[0] "width width_unit, height, height_unit" +#** @return () or ("papername", width.bp, height.bp) +sub valid($) { # valid_papersize + my $S=lc shift; + $S=~/^\s*(\d+(\.\d+)?)\s*([a-z][a-z0-9]+)\s*,\s*(\d+(\.\d+)?)\s*([a-z][a-z0-9]+)\s*\Z(?!\n)/ ? + valid_bp("$1$3","$4$6") : (); +} + +just::end} + +BEGIN{$ INC{'Htex/img_bbox.pm'}='Htex/img_bbox.pm'} + +package Htex::img_bbox; +# img_bbox.pa -- extract file format and size from image files +# This file contains embedded perldoc(1) POD documentation. +# by pts@fazekas.hu at Sat Dec 7 21:31:01 CET 2002 +# JustLib2 at Sat Dec 21 21:29:21 CET 2002 +# +# img_bbox.pl is a standalone Perl script that can extract file format, +# width, height, bounding box and +# other meta-information from image files. Supported vector formats are: +# PDF, Flash SWF, EPS, PS, DVI and FIG. Supported raster image formats are: +# GIF, JPEG, PNG, TIFF, XPM, XBM1, XBM, PNM, PBM, PGM, PPM, PCX, LBM, other +# IFF, Windows and OS/2 BMP, MIFF, Gimp XCF, Windows ICO, Adobe PSD, FBM, +# SunRaster, CMUWM, Utah RLE, Photo CD PCD, XWD, GEM, McIDAS, PM, SGI IRIS, +# FITS, VICAR, PDS, FIT, Fax G3, Targa TGA and Faces. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Extracting the image size is not supported for: other IFF, FIG. +# +# +use just 1; +use integer; # important +use strict; # not so important +# use Htex::ImgBBox qw(calc -PDF -paper); +use Htex::ImgBBox qw(calc); + +sub delete0($$) { + delete $_[0]{$_[1]}; + "" +} + +#** @param $_[0] $bbi hashref +#** @return a multiline dump of all key--value pairs, sorted by key +sub all($) { + my $bbi=$_[0]; + my $RET=""; + for my $key (sort keys %$bbi) { if (1<length $key) { + my $val=$bbi->{$key}; + $RET.=" $key = ".(ref($val)eq'ARRAY' ? "[ @$val ]\n" : "$val\n"); + } } + $RET +} + +my %texq; +#** @param $_[0] arbitrary binary string +#** @return the string quoted, so it can be safely placed inside TeX +#** \message{...} or \special{...} +sub texq($) { + if (!keys %texq) { + $texq{' '}='\iftrue\space\fi '; # won't collapse two spaces into one + $texq{'\\'}='\expandafter\@secondoftwo\string\\\\'; + $texq{'{'}='\expandafter\@secondoftwo\string\{'; + $texq{'}'}='\expandafter\@secondoftwo\string\}'; + $texq{'%'}='\expandafter\@secondoftwo\string\%'; + $texq{'#'}='\expandafter\@secondoftwo\string\#'; + $texq{'^'}='\expandafter\@secondoftwo\string\^'; # no danger of ^^ + $texq{'~'}='\expandafter\@secondoftwo\string\~'; + $texq{'`'}='\expandafter\@secondoftwo\string\`'; + $texq{'"'}='\expandafter\@secondoftwo\string\"'; + # vvv will work only if the token is expanded only once + #$texq{'~'}='\noexpand~'; + #$texq{'`'}='\noexpand`'; + #$texq{'"'}='\noexpand"'; + } + my $S=$_[0]; + $S=~s@(\W)@exists$texq{$1}?$texq{$1}:$1@ge; + $S=~s~([\000-\037\177-\377])~sprintf"\\expandafter\\\@secondoftwo\\string\\^^%02x",ord$1~ge; + $S +} + +sub aq($$) { + $_[0] eq ":t" ? texq($_[1]) : $_[1] +} + +my $t_short="%{FileName} %{FileFormat:-??} %{LLX:-??} %{LLY:-??} %{URX:-??} %{URY:-??}%{Paper?+ %{Paper}}%{Error?+ error:%{Error}}\n"; +my $t_long="%{FileName}%{FileName?0}\n%{all}"; +# my $t_tex='\graphicPmeta{%{FileName:t}%{c}{%{FileFormat:-?}%{c}{%{LLX:-?}%{c}{%{LLY:-?}%{c}{%{URX:-?}%{c}{%{URY:-?}%{c}%{n}'; +my $t_tex='\graphicPmeta{%{FileName:t}%{c}{%{FileFormat:-?}%{SubFormat?+.%{SubFormat}}%{c}{%{LLX:-?}%{c}{%{LLY:-?}%{c}{%{URX:-?}%{c}{%{URY:-?}%{c}%{n}'; + +sub compile_template($) { + my $template=$_[0]; + # convert $template to Perl code + $template=~s@([\\'])@\\$1@g; + $template=~s@([}])|[%][{]([\w.-]+)(:t)?(:-|[?][+0-]|)@ + defined($1) ? "').'" : + $4 eq "" && $2 eq "all" ? "'.(all(\$bbi).'" : + $4 eq "" ? "'.(!defined\$bbi->{'$2'}?'':aq('".($3||"")."',\$bbi->{'$2'}).'" : + $4 eq "?+" ? "'.(!defined\$bbi->{'$2'}?'':'" : + $4 eq "?-" ? "'.(defined\$bbi->{'$2'}?'':'" : + $4 eq ":-" ? "'.(defined\$bbi->{'$2'}?aq('".($3||"")."',\$bbi->{'$2'}):'" : + $4 eq "?0" ? "'.(delete0(\$bbi,'$2').'" : + "[$1]($2)($4)" # should never happen + @ge; + my $sub=eval "sub { my \$bbi=\$_[0]; '$template' }"; + die "$0: template syntax error: $@" if $@ or ref($sub) ne 'CODE'; + $sub +} + +sub work($$) { + my($sub,$filename)=@_; + my $bbi; + # die "$0: $filename: $!\n" unless open F, "< $filename"; + if (open F, "< $filename") { + ## print STDERR "$filename\n"; + $bbi=calc(\*F); + } else { + $bbi->{Error}="open: $!" + } + $bbi->{FileName}=$filename; + $bbi->{n}="\n"; + $bbi->{p}="%"; + $bbi->{c}="}"; + print $sub->($bbi); +} + +sub usage() { + die "This is img_bbox.pl by pts\@fazekas.hu, version 0.08 +This program is free software, licensed under the GNU GPL. +This software comes with absolutely NO WARRANTY. Use at your own risk! + +Usage: $0 [<template>] <filename.image> [...] +Template is one of: -- --short --long --tex --template <t> + +I can extract file format, width, height, bounding box and other +meta-information from image files. Run this to get more docs: + perldoc '$0'\n" +} + +just::main; + +usage if !@ARGV; + +my $template=$t_short; +if ($ARGV[0] eq '--' or $ARGV[0] eq '--short') { } +elsif ($ARGV[0] eq '--long') { $template=$t_long; shift @ARGV } +elsif ($ARGV[0] eq '--tex') { $template=$t_tex; shift @ARGV } +elsif ($ARGV[0] eq '--template') { usage if @ARGV<2; $template=$ARGV[1]; splice @ARGV, 0, 2 } +elsif ($ARGV[0]=~/\A--/) { goto usage } + +my $sub=compile_template($template); +for my $filename (@ARGV) { work $sub, $filename } + +__END__ + +=begin man + +.ds pts-dev \*[.T] +.do if '\*[.T]'ascii' .ds pts-dev tty +.do if '\*[.T]'ascii8' .ds pts-dev tty +.do if '\*[.T]'latin1' .ds pts-dev tty +.do if '\*[.T]'nippon' .ds pts-dev tty +.do if '\*[.T]'utf8' .ds pts-dev tty +.do if '\*[.T]'cp1047' .ds pts-dev tty +.do if '\*[pts-dev]'tty' \{\ +.ll 79 +.pl 33333v +.nr IN 2n +.\} +.ad n + +=end + +=head1 NAME + +img_bbox.pl - Extract file format and size from image files + +=head1 SYNOPSIS + +C<B<img_bbox.pl>> + S<[ C<--> | C<--short>> + S<| C<--long>> + S<| C<--tex>> + S<| C<--template> I<template> ]> + S<I<filename.image>> S<[ ... ]> + +=head1 DESCRIPTION + +img_bbox.pl is a standalone Perl script that can extract file format, +width, height, bounding box and +other meta-information from image files. Supported vector formats are: +PDF, Flash SWF, EPS, PS, DVI and FIG. Supported raster image formats are: +GIF, JPEG, PNG, TIFF, XPM, XBM1, XBM, PNM, PBM, PGM, PPM, PCX, LBM, other +IFF, Windows and OS/2 BMP, MIFF, Gimp XCF, Windows ICO, Adobe PSD, FBM, +SunRaster, CMUWM, Utah RLE, Photo CD PCD, XWD, GEM, McIDAS, PM, SGI IRIS, +FITS, VICAR, PDS, FIT, Fax G3, Targa TGA and Faces. + +img_bbox.pl writes the extracted information to STDOUT, in a format +determined by the template specified on the command line. The default +template is C<--short>. Templates are: + +=over 10 + +=item C<--short> + +writes the file name, file format and the four +bounding box coordinates (lower left x, lower left y, upper right x, upper +right y), separated by spaces. + +=item C<--long> + +writes a multi-line entry for each file containing all key--value pairs +that img_bbox.pl was able to extract. + +=item C<--tex> + +writes output suitable for C<\input> in TeX. The file name, file format and +bounding box is dumped + +=item C<--pat> + +lets the user specify an individual pattern, see later. + +=back + +=head1 PATTERNS + +Individual patterns can be specified after C<--pat>. Built-in patterns are: + + --short: %{FileName} %{FileFormat:-??} %{LLX:-??} %{LLY:-??} %{URX:-??} %{URY:-??}%{Paper?+ %{Paper}}%{Error?+ error:%{Error}}%{n} + --long : %{FileName}%{FileName?0}%{n}%{all} + --tex : \graphicPmeta{%{FileName:t}%{c}{%{FileFormat:-?}%{c}{%{LLX:-?}%{c}{%{LLY:-?}%{c}{%{URX:-?}%{c}{%{URY:-?}%{c}%{n} + +Expressions of the form + C<%{> I<key> [ I<quoting> ] I<method> I<body> C<}> + are substituted. + +I<key>s of interest will be enumerated later in this subsection. + +I<quoting> is one of + +=over 7 + +=item (none) + +The string is inserted as-is. + +=item C<:t> + +Quotes all TeX and LaTeX control characters. + +=back + +The interpretation of I<body> depends on I<method>. The default action is to +append the contents of I<body> verbatim after the substitution. I<body> is +an empty string most of the time. + +I<method> is one of + +=over 7 + +=item (none) + +Expands to the value of I<key>, or an empty string. I<body> must be empty. + +=item C<:-> + +Expands to the value of I<key>, or I<body>. + +=item C<?0> + +Deletes I<key>, and expands to I<body>. + +=item C<?+> + +Expands to I<body> if I<key> exists, or an empty string. + +=item C<?-> + +Expands to I<body> if I<key> is missing, or an empty string. + +=back + +I<key>s of interest are: + +=over 20 + +=item n + +a newline + +=item p + +a percent sign + +=item c + +a close brace + +=item all + +A detailed, multi-line key--value listing of all information extracted, as +output by the C<--long> template. + +=item FileName + +=item FileFormat + +=item SubFormat + +=item LLX + +Zero for most file formats. + +=item LLY + +Zero for most file formats. + +=item URX + +The width for most file formats. + +=item URY + +The height for most file formats. + +=item SamplesPerPixel + +=item BitsPerSample + +=item ColorSpace + +Gray, RGB, YCbCr, CMYK, YCCK, Indexed etc. + +=item Error + +the first I/O or other error + +=item Info. + +various file format specific keys begin with C<Info.> + +=item Val. + +various key--value pairs read from the file, beginning with C<Val.> + +=item Info.MediaBox + +PDF only + +=item Info.CropBox + +PDF only + +=item Info.BleedBox + +PDF only + +=item Info.TrimBox + +PDF only + +=item Info.ArtBox + +PDF only + +=item Info.Compression + +TIFF only + +=item Info.NewSubfileType + +TIFF only + +=item Info.PhotometricInterpretation + +TIFF only + +=item Info.Thresholding + +TIFF only + +=item Info.CellWidth + +TIFF only + +=item Info.CellLength + +TIFF only + +=item Info.FillOrder + +TIFF only + +=item Info.Orientation + +TIFF only + +=item Info.RowsPerStrip + +TIFF only + +=item Info.MinSampleValue + +TIFF only + +=item Info.MaxSampleValue + +TIFF only + +=item Info.PlanarConfiguration + +TIFF only + +=item Info.GrayResponseUnit + +TIFF only + +=item Info.ResolutionUnit + +TIFF only + +=item Info.ExtraSamples + +TIFF only + +=item Info.hvs + +JPEG only + +=item Info.id_rgb + +JPEG only + +=item Info.had_jfif + +JPEG only + +=item Info.ColorTransform + +JPEG only + +=item Info.binary + +Clean7Bit, Clean8Bit or Binary. PDF and PS only + +=item Info.linearized + +PDF only + +=item Info.denominator + +DVI only + +=item Info.nominator + +DVI only + +=item Info.version_id + +DVI only + + +=item Info.maginification + +DVI only + + +=item Info.jobname + +DVI only + +=item Info.page1_nr + +DVI only + +=item Info.special + +DVI only + +=item Info.colors + +ICO only + +=item Info.reserved + +ICO only + + +=item Info.planes + +ICO only + + +=item Info.credits + +FBM only + +=item Info.title + +FBM only + +=item Info.planes + +FBM only + +=item Info.bits + +FBM only + +=item Info.rowlen + +FBM only + +=item Info.plnlen + +FBM only + +=item Info.clrlen + +FBM only + +=item Info.hlen + +GEM only + +=item Info.colors + +GEM only + +=item Info.patlen + +GEM only + +=item Info.llen + +GEM only + +=item Info.lines + +GEM only + +=item Info.num_planes + +PM only + +=item Info.num_bands + +PM only + +=item Info.pixel_format + +PM only + +=item Info.compression + +SGI only + +=item Info.comment + +SGI only + +=item Info.bits_per_pixel + +FITS only + +=item Info.num_axis + +FITS only + +=item Info.depth + +FITS only + +=item Info.data_max + +FITS only + +=item Info.data_min + +FITS only + +=back + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +=head1 AUTHOR + +Szabó Péter <F<pts@fazekas.hu>> + +=head1 SEE ALSO + +file(1) diff --git a/macros/latex/exptl/graphicp/keyvalx.sty b/macros/latex/exptl/graphicp/keyvalx.sty new file mode 100644 index 0000000000..a678a63b5a --- /dev/null +++ b/macros/latex/exptl/graphicp/keyvalx.sty @@ -0,0 +1,76 @@ +% +% keyvalx.sty +% by pts@fazekas.hu at Fri Jan 24 12:27:05 CET 2003 +% +% Works with laemu.sty. Based on standard LaTeX keyval.sty. +% +\expandafter\ifx\csname ifLaTeX\endcsname\relax\input laemu.sty\relax\fi% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{keyvalx} + [1999/03/16 v1.13 key=value parser (DPC)] +\def\setkeys#1#2{% + \def\KV@prefix{KV@#1@}% + \let\@tempc\relax + \KV@do#2,\relax,} +\def\KV@do#1,{% + \ifx\relax#1\empty\else + \KV@split#1==\relax + \expandafter\KV@do\fi} +\def\KV@split#1=#2=#3\relax{% + \KV@@sp@def\@tempa{#1}% + \ifx\@tempa\@empty\else + \expandafter\let\expandafter\@tempc + \csname\KV@prefix\@tempa\endcsname + \ifx\@tempc\relax + \KV@errx + {key \@tempa\space in \KV@prefix\space undefined}% + \else + \ifx\@empty#3\@empty + \KV@default + \else + \KV@@sp@def\@tempb{#2}% + \expandafter\@tempc\expandafter{\@tempb}\relax + \fi + \fi + \fi} +\def\KV@default{% + \expandafter\let\expandafter\@tempb + \csname\KV@prefix\@tempa @default\endcsname + \ifx\@tempb\relax + \KV@err{No value specified for \@tempa}% + \else + \@tempb\relax + \fi} + +%**** pts **** +%\DeclareOption{unknownkeysallowed}{% +% \def\KV@errx#1{\PackageInfo{keyval}{#1}}} +%\DeclareOption{unknownkeyserror}{% +% \def\KV@errx#1{\PackageError{keyval}{#1}\@ehc}} +%\ExecuteOptions{unknownkeyserror} +%\let\KV@err\KV@errx +%\ProcessOptions +\def\KV@errx#1{\PackageError{keyval}{#1}\@ehc}% +\let\KV@err\KV@errx + +\def\@tempa#1{% +\def\KV@@sp@def##1##2{% + \futurelet\KV@tempa\KV@@sp@d##2\@nil\@nil#1\@nil\relax##1}% +\def\KV@@sp@d{% + \ifx\KV@tempa\@sptoken + \expandafter\KV@@sp@b + \else + \expandafter\KV@@sp@b\expandafter#1% + \fi}% +\def\KV@@sp@b#1##1 \@nil{\KV@@sp@c##1}% + } +\@tempa{ } +\def\KV@@sp@c#1\@nil#2\relax#3{\KV@toks@{#1}\edef#3{\the\KV@toks@}} +\newtoks\KV@toks@ +\def\define@key#1#2{% + \@ifnextchar[{\KV@def{#1}{#2}}{\@namedef{KV@#1@#2}####1}} +\def\KV@def#1#2[#3]{% + \@namedef{KV@#1@#2@default\expandafter}\expandafter + {\csname KV@#1@#2\endcsname{#3}}% + \@namedef{KV@#1@#2}##1} +\endinput diff --git a/macros/latex/exptl/graphicp/laemu.sty b/macros/latex/exptl/graphicp/laemu.sty new file mode 100644 index 0000000000..2dd8868d56 --- /dev/null +++ b/macros/latex/exptl/graphicp/laemu.sty @@ -0,0 +1,206 @@ +% +% laemu.sty -- helper TeX macros and LaTeX emulation for plain TeX + LaTeX +% by pts@fazekas.hu at Fri Jan 24 11:14:34 CET 2003 +% +% To use this package from LaTeX, type +% +% \usepackage{laemu} +% +% To use this package from either LaTeX, plain TeX or AMSTeX, type +% +% \input laemu.sty +% +% As an alternative, the following solution will open laemu.sty only once: +% +% \expandafter\ifx\csname usepackage\endcsname\relax% +% \def\usepackage#1{\input#1.sty\relax}\fi% +% \usepackage{laemu} +% % this ensures that laemu.sty won't be loaded twice +% +% Tho use further packages from any TeX formats, type +% +% \usepackage{...PACKAGENAME...} +% + +% vvv Don't load laemu.sty more than once +\expandafter\ifx\csname ifLaTeX\endcsname\relax\else\expandafter\endinput\fi + +\newif\ifWasLetter% false +\ifnum\the\catcode`\@=\the\catcode`\a\relax\WasLettertrue\fi% +\catcode`\@=11% early \makeatletter + +%** Are we running a real LaTeX? +\newif\ifLaTeX% default to false +%** Sets \ifLaTeX to (#1 == 'L' && #2 == 'a') +\def\@@setlatex#1#2#3\end{% + \if#1L\if#2a\LaTeXtrue\else\LaTeXfalse\fi\fi% +}% +% Dat: \fmtname is "plain", "LaTeX2e" or "AmS-TeX" +\expandafter\@@setlatex\fmtname\end% + +\ifLaTeX% + %\PackageError{laemu}{alma}\@ehc + %** Calls #1{...}, where ... is the comma-separated option list for the + %** current package. + %** Arranges that these options won't be found at \endinput + %** Example: \LaemuProcessOptions\errmessage + %** @param #1 a \cs + \def\LaemuProcessOptions#1{% + \edef\reserved@a{\noexpand#1{\@ptionlist{\@currname.\@currext}}}% + \reserved@a + \AtEndOfPackage{\def\@unprocessedoptions{}}% + }% +\else% + \expandafter\let\csname opt@laemu.sty\endcsname\@empty% loaded ourselves + \long\def\@gobble#1{}% + \def\@ehc{No help here.}% + \newlinechar=`\^^J% + \def\on@line{ in line \the\inputlineno}% so it can be \@gobble-d + \def\NeedsTeXFormat#1{}% ignore + \def\ProvidesPackage#1#2[#3]{\makeatletter}% so `\input MYPKG.sty' works + % Dat: use \MessageBreak to separate error/warning/info lines + \def\PackageWarning#1#2{% Imp: robust + \def\MessageBreak{^^Jw: (#1) }% + % vvv Dat: line number refers to place of the \PackageWarning invocation + \immediate\write16{^^JPackage #1 Warning: #2\on@line.^^J}% + }% + \def\PackageInfo#1#2{% Imp: robust + \def\MessageBreak{^^Ji: (#1) }% + % vvv Dat: line number refers to place of the \PackageWarning invocation + \immediate\write-1{Package #1 Info: #2\on@line.}% + }% + \def\PackageError#1#2#3{\begingroup% Imp: robust + % Dat: real LaTeX \GenericError doesn't print stupid macro expansions + % after the error message. We cannot emulate it here, possibly because it + % this \PackageError should have been put into the format file (??) + \immediate\write16{}% an empty line + \def\MessageBreak{^^J!: (#1) }% + % vvv Dat: line number refers to place of the \PackageWarning invocation + \edef\@err@{{Package #1 Error: #2\MessageBreak#3}}% + \errhelp\@err@% + %\let\@err@\empty% + \errmessage{Package #1 Error: #2^^J!, See the package #1 docs for explanation}% + %~% + \endgroup}% + % + %** `\RequirePackage{package}' loads package.sty unless already loaded + %** `\RequirePackage[option]{package}' + %** `\RequirePackage[option1,option2,option3]{package}' + \def\RequirePackage{% + % Imp: allow optional arguments + % Imp: show a warning of loading with different arguments + \@ifnextchar[%] + {\@@RequirePackage@lowa}% + {\@@RequirePackage@lowa[]}% + }% + \def\@@RequirePackage@lowa[#1]#2{% + % Imp: add/strip ".sty" from end of #1 + \@@RequirePackage@lowb{#2.sty}{#1}% + }% + %** {current.sty}{lower.sty}....% + \def\@@laemu@packagestack{.}% Imp: save \catcode64 + %** \def#1{...}, where ... is the current package filename + \def\@@laemu@packagetop#1{% + %\message{T(\@@laemu@packagestack)}% + \expandafter\@@laemu@packagetop@low\@@laemu@packagestack#1% + }% + \def\@@laemu@packagetop@low#1#2.#3{% + % Dat: #2 is invalid now (braces may be stripped), don't use it + \def#3{#1}% + }% + \def\@@laemu@packagepop{% Imp: error on underflow + %\message{P(\@@laemu@packagestack)}% + \global\edef\@@laemu@packagestack{\expandafter\@gobble\@@laemu@packagestack}% + %\expandafter\@@laemu@packagepop@low\@@laemu@packagestack% doesn't work well + }% + %\def\@@laemu@packagepop@low#1#2.{% SUXX: removes brace from {y} in {x}{y}. + % \message{Q(#1,#2)}% + % \global\edef\@@laemu@packagestack{#2.}% + % \message{R(\@@laemu@packagestack)}% + %}% + \def\@@laemu@packagepush#1{% + \global\edef\@@laemu@packagestack{{#1}\@@laemu@packagestack}% + %\message{E(\@@laemu@packagestack)}% + }% + %** @param #1 filename with `.sty' + %** @param #2 options + \def\@@RequirePackage@lowb#1#2{% + \expandafter\ifx\csname opt@#1\endcsname\relax% + \expandafter\def\csname opt@#1\endcsname{#2}% + %\ifcat \noexpand @\noexpand a% + \@@laemu@packagepush{#1}% + \ifnum\the\catcode`\@=\the\catcode`\a\relax% Dat: \ifcat is wrong, because we need the _current_ value (at the time of execution) + \input#1\relax% + \else% + \makeatletter% + \input#1\relax% + \makeatother% + \fi% + \@@laemu@packagepop% + \else% package already loaded -- verify options + \def\reserved@a{#2}% + % Imp: allow \usepackage[a,b]{c} and \usepackage[b,a]{c} + % Dat: LaTeX \def's comma-separated-values to \csname opt@graphic.p.sty\endcsname + \expandafter\ifx\csname opt@#1\endcsname\reserved@a\else% + \PackageError{laemu}{Option clash for package file `#1'}{% + Old options: \csname opt@#1\endcsname\MessageBreak% + New options: \reserved@a + }% + \fi% + \let\reserved@a\@empty + \fi% + }% + \let\usepackage\RequirePackage% + % vvv see full comment above + \def\LaemuProcessOptions#1{% + \@@laemu@packagetop\reserved@a% + \edef\reserved@a{\noexpand#1{\csname opt@\reserved@a\endcsname}}% + \reserved@a + }% + % + \def\makeatletter{\catcode`\@11\relax}% + \def\makeatother{\catcode`\@12\relax}% + \def\@empty{}% not needed for LaTeX, needed for plain TeX + \long\def\@secondoftwo#1#2{#2}% + \def\@namedef#1{\expandafter\def\csname #1\endcsname}% + \def\@nameuse#1{\csname #1\endcsname}% + \expandafter\ifx\csname @ne\endcsname\relax \chardef\@ne=1\fi% + % + \long\def\@ifnextchar#1#2#3{% + \let\reserved@d=#1% + \def\reserved@a{#2}% + \def\reserved@b{#3}% + \futurelet\@let@token\@ifnch} + \def\@ifnch{% + \ifx\@let@token\@sptoken + \let\reserved@c\@xifnch + \else + \ifx\@let@token\reserved@d + \let\reserved@c\reserved@a + \else + \let\reserved@c\reserved@b + \fi + \fi + \reserved@c} + \def\:{\let\@sptoken= } \: % this makes \@sptoken a space token + \def\:{\@xifnch} \expandafter\def\: {\futurelet\@let@token\@ifnch}% + \expandafter\ifx\csname @inputcheck\endcsname\relax% + \newread\@inputcheck% + \fi% +\fi% + +%** \input's a file if it exists +%** @param #1 filename +\def\LaemuInputQuiet#1{% + \openin\@inputcheck#1 % + \ifeof\@inputcheck\else% + \closein\@inputcheck% + \input#1 % + \fi +}% + +%\PackageWarning{laemu}{alma\MessageBreak korte} +%\PackageInfo{laemu}{ialma\MessageBreak korte} +%\PackageError{laemu}{ialma\MessageBreak korte}\@ehc + +\ifWasLetter\else\makeatother\fi% diff --git a/macros/latex/exptl/graphicp/laltest.tex b/macros/latex/exptl/graphicp/laltest.tex new file mode 100644 index 0000000000..01013f602a --- /dev/null +++ b/macros/latex/exptl/graphicp/laltest.tex @@ -0,0 +1,166 @@ +% +% latest.tex -- both plain TeX and LaTeX +% by pts@fazekas.hu at Fri Jan 24 11:24:28 CET 2003 +% at Mon Feb 3 16:21:04 CET 2003 +% + +\input laemu.sty + +\ifLaTeX + \documentclass{article} + \usepackage[magyar]{babel} + %\usepackage[german]{babel} + \usepackage[latin2]{inputenc} +\fi + +%\expandafter\ifx\csname usepackage\endcsname\relax% +% \def\usepackage#1{\input#1.sty\relax}\fi% +%\usepackage{laemu} +%\usepackage{pts_img} + +%\usepackage[nopdftexmpost]{graphicp} +\usepackage{graphicp} +%\usepackage[alma,korte]{graphicp} + +\ifLaTeX + \begin{document} +\fi + +\makeatletter + +\ifLaTeX + Hello, LaTeX! +\else + Hello, other. +\fi + +%\@@muldivletposdim{\dimen3}{-2.99998pt}{2.83466pt}{1pt}% Imp: precision!! should be 8.50392 +% \immediate\write16{t9(-8.50394):\the\dimen3}% Division is not that exact... + +% \message{\@@divhundred{345.6}}% +% \@@letdimcount{\count0}{0.5pt} \showthe\count0% + +%\@@gobbleend almakorte\end szilva + +%\expandafter\ifx\csname graphicPdriver +%\@@setdriver{dvips} +%\@@setdriver{pdftex} +%\@@setdriver{dvipdfm} +%\@@setdriver{} +%\@@setdriver{} +% +% +\setbox0=\vbox{\hsize=9cm +\hrule width 5cm +\noindent +Hello,% +\@@PutImage{}{}.{{3bp}{-10bp}{23bp}{20bp}}{0pt}{0pt}{0}{f2cletter.\@@img@defext}{}% +%\unskip% +World! + +\par\noindent +2Hello,% +\@@PutImage{}{}.{{3bp}{-10bp}{23bp}{20bp}}{3cm}{0pt}{0}{f2cletter.\@@img@defext}{}% +World! +\hrule width 4cm + +\par\noindent +Hello,% +\@@PutImage{}{}.{{3bp}{-10bp}{23bp}{20bp}}{0pt}{3cm}{0}{f2cletter.\@@img@defext}{}% +World! + +\par\noindent +Hello,% +\@@PutImage{}{}.{{3bp}{-10bp}{23bp}{20bp}}{2cm}{3cm}{0}{f2cletter.\@@img@defext}{}% +World! + +\par\noindent +Hello,% +%\includegraphics[width=2cm,height=3cm,noclip]{f2cletter.\@@img@defext}% +\includegraphics[width=2cm,height=3cm,noclip]{f2mletter}% +ZWorld! +\par +\hrule + +\noindent +Hello,% +%\includegraphics[bbox={{0}{0}{20bp}{30bp}},width=20bp,height=30bp,noclip]{ficletter.png}% only in pdfTeX and dvipdfm +%\includegraphics[bbox={{0}{0}{20bp}{30bp}},width=2cm,height=3cm,noclip]{ficletter.eps}% only in pdfTeX and dvipdfm +%\includegraphics[bbox={{0}{0}{20bp}{30bp}},width=2cm,height=3cm,noclip]{ficletter.pdf}% only in pdfTeX and dvipdfm +%\includegraphics[width=2cm,height=3cm,noclip]{fromp.eps}% +\includegraphics[width=2cm,height=3cm,noclip,below]{descend.1}% +%\includegraphics[format=TIFF,bbox={{0}{0}{72bp}{72bp}},width=2cm,height=3cm,noclip]{ficletter.tiff}% +%\includegraphics[width=2cm,height=3cm,noclip]{ficletter.tiff}% +%\includegraphics[width=2cm,height=3cm,noclip]{ficletter.png}% only in pdfTeX +%\ifnum\pdftexversion>0 +\iftrue% +\includegraphics[forceunknown=1,bbox={{0}{0}{20bp}{30bp}},width=2cm,height=3cm,noclip,below]{ficletter.png}% only in pdfTeX and dvipdfm +\includegraphics[forceunknown=1,bbox={{0}{0}{20bp}{30bp}},lower=10,width=2cm,height=3cm,noclip]{ficletter.png}% only in pdfTeX and dvipdfm +\fi +MetaPost! + +%\def\secondofthree#1#2#3{#2}% +%\def\thirdofthree#1#2#3{#2}% + +\message{% + %\noexpand{\iffalse}\fi% + E% + %\iffalse{\fi% + %\iffalse}\fi% + %\expandafter\expandafter\expandafter\secondofthree% + %\expandafter\string\csname{}\endcsname% + \expandafter\@secondoftwo\string\\% + F% +}% + +%\message{AAA% +% \expandafter\expandafter\expandafter\@firstoftwo +% \expandafter\string\csname v\endcsname BBB} + +%\def\xgobble{\let\next}% + +\input laxtest.bbx + +\par\noindent +Hello,% +%\iftrue % stress test on special characters in filename +\iffalse\iffalse +%\ifnum\pdftexversion>0\ifnum\pdftexversion>12 % +%\includegraphics[bbox={{3bp}{-10bp}{23bp}{20bp}},width=1cm,height=1cm,noclip]{% +\includegraphics[width=1cm,height=1cm,noclip,below]{% + %\noexpand{%\expandafter\@gobble\n + %\expandafter\expandafter\expandafter\xgobble% + %\expandafter\noexpand}% + %\iffalse}\fi% + %\expandafter\@secondoftwo\string\^% + %\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^40% + %\noexpand`tty% + %\noexpand"a% + %ő% + %\ % + % Dat: kpsewhich: $ +% ugly_&_\space \space \space \expandafter\@secondoftwo\string\\% +% \expandafter\@secondoftwo\string\}% +% \expandafter\@secondoftwo\string\%% +% \expandafter\@secondoftwo\string\#% +% \expandafter\@secondoftwo\string\^% +% \expandafter\@secondoftwo\string\^a% +% \expandafter\@secondoftwo\string\^e1% +% \expandafter\@secondoftwo\string\^e9b% +% \expandafter\@secondoftwo\string\{% +% \expandafter\@secondoftwo\string\%% +% \expandafter\@secondoftwo\string\#% +% \expandafter\@secondoftwo\string\^% +% \expandafter\@secondoftwo\string\~% + %\noexpand~% +% \noexpand`tty. + ugly_&_\space \space \space \expandafter\@secondoftwo\string\\\expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.\@@img@defext% +% ugly_&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\\\expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.\@@img@defext% +}% +\fi\fi +Q. + +}% +\shipout\box0 + +\end{document} diff --git a/macros/latex/exptl/graphicp/laxtest.bbx b/macros/latex/exptl/graphicp/laxtest.bbx new file mode 100644 index 0000000000..d35d44992c --- /dev/null +++ b/macros/latex/exptl/graphicp/laxtest.bbx @@ -0,0 +1,18 @@ +\graphicPmeta{f2cletter.eps}{EPS}{3}{-10}{23}{20} +\graphicPmeta{tl.eps}{EPS}{0}{0}{1280}{1024} +\graphicPmeta{ts.eps}{EPS}{0}{0}{1280}{1024} +\graphicPmeta{ugly_$&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\\\expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.eps}{EPS}{3}{-10}{23}{20} +\graphicPmeta{ugly_&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.eps}{EPS}{3}{-10}{23}{20} +\graphicPmeta{ugly_&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\\\expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.eps}{EPS}{3}{-10}{23}{20} +\graphicPmeta{f2cletter.pdf}{PDF}{3}{-10}{23}{20} +\graphicPmeta{f3cletter.pdf}{PDF}{0}{-10}{20}{20} +\graphicPmeta{ficletter.pdf}{PDF}{0}{0}{20}{30} +\graphicPmeta{laltest.pdf}{PDF}{0}{0}{595}{842} +\graphicPmeta{pdfbbox.pdf}{PDF}{0}{0}{612}{792} +\graphicPmeta{pts_img.pdf}{PDF}{0}{0}{595}{841} +\graphicPmeta{t.pdf}{PDF}{0}{0}{20}{30} +\graphicPmeta{ts.pdf}{PDF}{0}{0}{1280}{1024} +\graphicPmeta{tt.pdf}{PDF}{?}{?}{?}{?} +\graphicPmeta{ugly_$&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\\\expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.pdf}{PDF}{3}{-10}{23}{20} +\graphicPmeta{ugly_&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.pdf}{PDF}{3}{-10}{23}{20} +\graphicPmeta{ugly_&_\iftrue\space\fi \iftrue\space\fi \iftrue\space\fi \expandafter\@secondoftwo\string\\\expandafter\@secondoftwo\string\}\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\^a\expandafter\@secondoftwo\string\^^e1\expandafter\@secondoftwo\string\^^e9b\expandafter\@secondoftwo\string\{\expandafter\@secondoftwo\string\%\expandafter\@secondoftwo\string\#\expandafter\@secondoftwo\string\^\expandafter\@secondoftwo\string\~\expandafter\@secondoftwo\string\`.pdf}{PDF}{3}{-10}{23}{20} diff --git a/macros/latex/exptl/graphicp/pdfboxes.pl b/macros/latex/exptl/graphicp/pdfboxes.pl new file mode 100755 index 0000000000..361817cff1 --- /dev/null +++ b/macros/latex/exptl/graphicp/pdfboxes.pl @@ -0,0 +1,863 @@ +#! /bin/sh +eval '(exit $?0)' && eval 'PERL_BADLANG=x;export PERL_BADLANG;: \ +;exec perl -x -S -- "$0" ${1+"$@"};#'if 0; +eval 'setenv PERL_BADLANG x;exec perl -x -S -- "$0" $argv:q;#'.q+ +#!perl -w +package Htex::pdfboxes; $0=~/(.*)/s;unshift@INC,'.';do($1);die$@if$@;__END__+if !1; +# This Perl script was generated by JustLib2 at Sun Feb 9 23:57:15 2003. +# Don't touch/remove any lines above; http://www.inf.bme.hu/~pts/justlib +package just; BEGIN{$INC{'just.pm'}='just.pm'} +BEGIN{ $just::VERSION=2 } +sub end(){1} +sub main(){} + +BEGIN{$ INC{'strict.pm'}='strict.pm'} { +package strict; +use just; +# by pts@fazekas.hu at Wed Jan 10 12:42:08 CET 2001 +require 5.002; +sub bits { + (grep{'refs'eq$_}@_ && 2)| + (grep{'subs'eq$_}@_ && 0x200)| + (grep{'vars'eq$_}@_ && 0x400)| + ($@ || 0x602) +} +sub import { shift; $^H |= bits @_ } +sub unimport { shift; $^H &= ~ bits @_ } +just::end} + +BEGIN{$ INC{'integer.pm'}='integer.pm'} { +package integer; +use just; +# by pts@fazekas.hu at Wed Jan 10 12:42:08 CET 2001 +sub import { $^H |= 1 } +sub unimport { $^H &= ~1 } +just::end} + +BEGIN{$ INC{'Pts/string.pm'}='Pts/string.pm'} { +package Pts::string; +# by pts@fazekas.hu at Sat Dec 21 21:32:18 CET 2002 +use just; +use integer; +use strict; + +#** @param $_[0] a string +#** @param $_[1] index of first bit to return. Bit 128 of byte 0 is index 0. +#** @param $_[2] number of bits to return (<=32) +#** @return an integer (negative on overflow), bit at $_[1] is its MSB +sub get_bits_msb($$$) { + # assume: use integer; + my $loop=$_[1]; + my $count=$_[2]; + my $ret=0; + ($ret+=$ret+(1&(vec($_[0],$loop>>3,8)>>(7-($loop&7)))), $loop++) while $count--!=0; + $ret +} + +#** @param $_[0] a string +#** @return value if $_[0] represents a floating point numeric constant +#** in the C language (without the LU etc. modifiers) -- or undef. Returns +#** undef for integer constants +sub c_floatval($) { + my $S=$_[0]; + no integer; # very important; has local scope + return 0.0+$S if $S=~/\A[+-]?(?:[0-9]*\.[0-9]+|[0-9]+\.])(?:[eE][+-]?[0-9]+)?\Z(?!\n)/; + undef +} + +#** @param $_[0] a string +#** @return value if $_[0] represents a floating point or integer numeric +#** constant in the C language (without the LU etc. modifiers) -- or undef +sub c_numval($) { + my $S=$_[0]; + no integer; # very important; has local scope + return 0+$S if $S=~/\A[+-]?(?:[0-9]*\.[0-9]+(?:[eE][+-]?[0-9]+)?|[0-9]+\.?)\Z(?!\n)/; + undef +} + +#** @param $_[0] a string +#** @return the integer value of $_[0] in C -- or undef +sub c_intval($) { + my $S=$_[0]; + my $neg=1; + $neg=-1 if $S=~s@\A([+-])@@ and '-'eq$1; + return $neg*hex $1 if $S=~/\A0[xX]([0-9a-fA-F]+)\Z(?!\n)/; + return $neg*oct $1 if $S=~/\A0([0-7]+)\Z(?!\n)/; + return $neg*$1 if $S=~/\A([0-9]+)\Z(?!\n)/; + undef +} + +sub import { + no strict 'refs'; + my $package = (caller())[0]; + shift; # my package + for my $p (@_ ? @_ : qw{get_bits_msb c_floatval c_numval c_intval}) { *{$package."::$p"}=\&{$p} } +} + +just::end} + +BEGIN{$ INC{'vars.pm'}='vars.pm'} { +package vars; +use just; +# by pts@fazekas.hu at Wed Jan 10 12:42:08 CET 2001 +require 5.002; +sub import { + my $callpack = caller; + my ($sym, $ch, $sym9); + shift; + for $sym0 (@_) { + die("Can't declare another package's variables") if $sym0 =~ /::/; + ($ch, $sym) = unpack('a1a*', $sym0); + *{"${callpack}::$sym"} = + ( $ch eq "\$" ? \$ {"${callpack}::$sym"} + : $ch eq "\@" ? \@ {"${callpack}::$sym"} + : $ch eq "\%" ? \% {"${callpack}::$sym"} + : $ch eq "\*" ? \* {"${callpack}::$sym"} + : $ch eq "\&" ? \& {"${callpack}::$sym"} + : die("'$ch$sym' is not a valid variable name\n") + ); + } +} +just::end} + +BEGIN{$ INC{'Htex/PDFread.pm'}='Htex/PDFread.pm'} { +package Htex::PDFread; +# by pts@fazekas.hu at Sat Dec 21 21:28:09 CET 2002 +use just; +use integer; +use strict; +use Pts::string; +use vars qw($pdf_last_ref0); + +my @pdf_classify; +#** @param $_[0] a string in PDF source format +#** @return a rewritten string, or "" if $_[0] is truncated, or undef if +#** there is a parse error +sub pdf_rewrite($;$) { + my $explicit_term_p=$_[1]; + my $L=length($_[0]); + return "" if $L==0; + my $S="$_[0]\n>> "; # add sentinel + my $I=0; + my $O; + my $RET=""; + if (!@pdf_classify) { + # Dat: PDF whitespace(0) is [\000\011\012\014\015\040] + # Dat: PDF separators(10) are < > { } [ ] ( ) / % + # Dat: PDF regular(40) character is any of [\000-\377] which is not whitespace or separator + @pdf_classify=(40)x256; + @pdf_classify[ord('<'),ord('>'),ord('{'),ord('}'),ord('['),ord(']'), + ord('('),ord(')'),ord('/'),ord('%')]=(10,11,12,13,14,15,16,17,18,19); + @pdf_classify[000,011,012,014,015,040]=(0,0,0,0,0,0); + } + while ($I<$L) { + $O=$pdf_classify[vec($S,$I,8)]; + if ($O==0) { # whitespace + } elsif (12<=$O and $O<=15) { # one-char token + $RET.=" ".substr($S,$I,1); + } elsif ($O==18 or $O==40) { # name or /name + my $P=0; + if ($O==18) { $I++; $RET.=" /" } else { $RET.=" "; $P=1 } + my $T=""; + $T.=chr($O) while $pdf_classify[$O=vec($S,$I++,8)]==40; + $I--; + ## die $I; + $T=~s@([^A-Za-z0-9_.-])@sprintf"#%02x",ord$1@ge; # make name safe + $RET.=$T; + return $RET if $P and ($T eq "stream" or $T eq "endobj" or $T eq "startxref"); + next + } elsif ($O==11) { # `>' + return "" if ++$I==$L; # only `>' has arrived + return undef if vec($S,$I,8)!=62; # err(">> expected"); + $RET.=" >>"; + } elsif ($O==16) { # string + my $T=""; + my $depth=1; $I++; + while ($I<$L) { + $O=vec($S,$I++,8); bcont: + ## print chr($O),":$depth\n"; + if ($O==40) { $depth++ } + elsif ($O==41) { last unless --$depth } + elsif ($O==92) { # a backslash + $O=vec($S,$I++,8); + if (48<=$O && $O<=55) { + my $P=$O-48; $O=vec($S,$I++,8); + if (48<=$O && $O<=55) { + my $Q=$O-48; $O=vec($S,$I++,8); + if (48<=$O && $O<=55) { $T.=chr(255&($P<<6|$Q<<3|($O-48))) } + else { $T.=chr($P<<3|$Q); goto bcont } + } else { $T.=chr($P); goto bcont } + } elsif ($O==110) { $O=10 } + elsif ($O==114) { $O=13 } + elsif ($O==116) { $O=9 } + elsif ($O== 98) { $O=8 } + elsif ($O==102) { $O=12 } + } + $T.=chr($O) + } # WHILE + return "" if $depth; # err("unterminated string") + $T=~s@([^A-Za-z0-9_.-])@sprintf"\\%03o",ord$1@ge; # make string safe + $RET.=" ($T)"; next + } elsif ($O==10) { # hex string + $O=vec($S,++$I,8); + if ($O==60) { $RET.=" <<"; $I++; next } + # parse hexadecimal string + my $half=0x100; + my $T=""; + while (1) { + 1 until $pdf_classify[$O=vec($S,$I++,8)]; # skip whitespace + if ($O==62) { $T.=chr($half&0xFF) if $half&0x1000; last } # '>' + return undef if $pdf_classify[$O]!=40; # err("unexpected token in hex") + if (65<=$O and $O<=70) { $half+=$O-55 } + elsif (97<=$O and $O<=102) { $half+=$O-87 } + elsif (48<=$O and $O<=57) { $half+=$O-48 } + else { return undef } # err("illegal hex digit") + if ($half&0x1000) { $T.=chr($half&0xFF); $half=0x100 } + else { $half<<=4 } + } + $T=~s@([^A-Za-z0-9_.-])@sprintf"\\%03o",ord$1@ge; # make string safe + $RET.=" ($T)"; next + } elsif ($O==19) { # single-line comment + $I++ while ($O=vec($S,$I,8))!=13 && $O!=10; + ## print STDERR "I=$I L=$L\n"; + next + } else { return undef } # err("token expected") # $O==11, $O==17 + $I++ + } ## WHILE + ## print STDERR "XI=$I L=$L\n"; + # die $explicit_term_p; + return "" if $explicit_term_p; + ($I>$L) ? "" : $RET +} + +# Unit test: +#die unless pdf_rewrite("hello \n\t world\n\t") eq " hello world"; +#die unless pdf_rewrite('(hel\)lo\n\bw(or)ld)') eq ' (hel\051lo\012\010w\050or\051ld)'; +#die unless pdf_rewrite('(hel\)lo\n\bw(orld)') eq ''; +#die unless pdf_rewrite('[ (hel\)lo\n\bw(or)ld)>>') eq ' [ (hel\051lo\012\010w\050or\051ld) >>'; +#die unless pdf_rewrite('>') eq ""; +#die unless pdf_rewrite('<') eq ""; +#die unless pdf_rewrite('< ') eq ""; +#die unless !defined pdf_rewrite('< <'); +#die unless !defined pdf_rewrite('> >'); +#die unless pdf_rewrite('[ (hel\)lo\n\bw(or)ld) <') eq ""; +#die unless pdf_rewrite("<\n3\t1\r4f5C5 >]") eq ' (1O\134P) ]'; +#die unless pdf_rewrite("<\n3\t1\r4f5C5") eq ""; +#die unless !defined pdf_rewrite("<\n3\t1\r4f5C5]>"); +#die unless pdf_rewrite("% he te\n<\n3\t1\r4f5C5 >]endobj<<") eq ' (1O\134P) ] endobj'; +#die unless pdf_rewrite("") eq ""; +#die unless pdf_rewrite("<<") eq " <<"; +#die unless pdf_rewrite('%hello') eq ''; +#die unless pdf_rewrite("alma\n%korte\n42") eq ' alma 42'; +#die unless pdf_rewrite('/Size 42') eq ' /Size 42'; +#die "OK"; + +#** Reads a single PDF indirect object (without its stream) from a PDF file. +#** Does some trivial transformations on it to make later regexp matching +#** easier. Stops at `stream', `endobj' and `startxref'. +#** @param $_[0] a filehandle (e.g \*STDIN), correctly positioned in the PDF +#** file to the beginning of the object data (i.e just before `5 0 obj') +#** @return string containing PDF source code, or undef on error +sub pdf_read_obj($) { + my $F=$_[0]; my $L=1024; my $M; my $S=""; my $RET; + while (1) { # read as much data as necessary + return undef if 0>($M=read $F, $S, $L, length($S)); + $RET=pdf_rewrite($S,1); + ## print "($S)\n"; + return undef if !defined $RET; # parse error + return $RET if length $RET; # OK, found object + return undef if $M==0; # cannot read more, reached EOF + $L<<=1; + } + #$S=~m@[\000\011\012\014\015\040]*( + # %[^\r\n]*[\r\n]| + # /?[^\000\011\012\014\015\040<>{}\[\]()/%]*(?=[\000\011\012\014\015\040<>{}\[\]()/%])| # unterminated + # <<|>>|\{|}|\[|]| + # <[a-fA-F0-9\000\011\012\014\015\040]*>| # hex string + # \((?:[^\\()]+|\\[\000-\377])*\)| # literal string, the easy way + # \( # an unfinished string, needs special care + #)@gx +} + +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file, positioned +#** just before an `xref' table +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4; will be extended +#** @return the `trailer' section after the `xref'; or undef +sub pdf_read_xref($$) { + # made much faster at Wed Dec 18 09:50:23 CET 2002 + my $T; + my $E; + my $F=$_[0]; + my $XREF=$_[1]; + return undef if 8>read $F, $T, 1024; + return undef unless $T=~s@\A\s*xref\s+(\d+)\s+(\d+)\s+(?=\S)@@; + my ($first,$len,$flen); + while (1) { + ($first,$len)=($1+0,$2+0); + ## print " $first + $len\n"; + $flen=($len*=20)-length($T)+20; + return undef unless $flen<1 or $flen==read $F, $T, $flen, length($T); + for (my $I=0;$I<$len;$I+=20, $first++) { + $E=substr($T, $I, 20); + return undef unless $E=~/\A(\d{10})\s(\d{5})\s([nf])\s\s/; + ## print "($1 $2 $3)\n"; + $XREF->[$2+0][$first]=$1+0 if $3 eq 'n'; + } + $E=substr($T, $len); + last if $E!~s@\A\s*(\d+)\s*(\d+)\s+(?=\S)@@; # next section + $T=$E; + } + + # die(-length($T)+$len); + ## die tell($F); + return undef if length($T)!=$len and !seek $F, -length($T)+$len, 1; + ## die tell($F); + return undef unless defined($T=pdf_read_obj($F)); + $XREF->[0][0]=undef if defined $XREF->[0]; + $XREF->[0][0]=$1+0 if $T=~m@ /Prev (\d+)@; # remember /Prev xref table + return undef unless $T=~m@\A trailer( .*) startxref\Z(?!\n)@s; + $1 +} + +$pdf_last_ref0=0; +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4 +#** @param $_[2] an object number +#** @param $_[3] a generation number +#** @return PDF source code of the reference, or undef +sub pdf_ref($$$$) { + my $F=$_[0]; my $XREF=$_[1]; my $ON=$_[2]+0; my $GN=$_[3]+0; + my $T; + $pdf_last_ref0=$ON if $GN==0; + ## print "REF $ON $GN;\n"; + until (ref $XREF->[$GN] and defined ($T=$XREF->[$GN][$ON])) { + return undef if !ref $XREF->[0] or !defined $XREF->[0][0]; # no /Prev entry, `$ON $GN R' not found + return undef unless seek $F, $XREF->[0][0], 0; + return undef if !defined pdf_read_xref($F,$XREF); + } + ## print "REF at $T;\n"; + return undef unless seek $F, $T, 0; + return undef unless defined($T=pdf_read_obj($F)); + ## print "REF=($T);\n"; + return undef unless $T=~s@\A (\d+) (\d+) obj\b(.*) (endobj|stream)\Z(?!\n)@$3@s; + $T +} + +#** Gets a key from a direct dict, and resolves it if it is an indirect object +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4 +#** @param $_[2] a PDF source dict (`<< ... >>') or array +#** @param $_[3] a key (`/...') +sub pdf_get($$$$) { + my $F=$_[0]; my $XREF=$_[1]; my $S=$_[2]; my $KEY=$_[3]; my $POS=0; + my $DEPTH=0; my $IS_DICT; my $C=0; my $N=0; + ## print "\n"; + while ($S=~/\G (\S+)/g) { + $C=vec($1,0,8); $POS=pos($S); + ## print "($1) $DEPTH $N\n"; + if ($1 eq '>>' or $1 eq ']') { + return undef if 0==$DEPTH--; + last if !$DEPTH; + $N++ if 1==$DEPTH; + } + elsif ($DEPTH==1 and !$IS_DICT and $KEY==$N) { $POS=pos($S)-=length($1)+1; goto do_ret } + elsif ($1 eq '<<') { $IS_DICT=1 if 0==$DEPTH++ } + elsif ($1 eq '[') { + if (0==$DEPTH++) { + $IS_DICT=0; + return undef if $KEY!~/\A(\d+)\Z(?!\n)/; # err("non-numeric key in array") + } + } + elsif (0==$DEPTH) { return undef } # not in a composite object + elsif (1!=$DEPTH) { next } + elsif (!$IS_DICT) { $N++ } + elsif ($C==40) { $N++ } # `(': string or bare name + elsif ($C>=47 and $C<=57) { # '/': /name 0..9: number + ## print "TRY ($1) KEY=$KEY.\n"; + next if ($N++&1)==1 or $1 ne $KEY; + do_ret: + ## print substr($S,pos($S)),";;\n"; + return pdf_ref $F, $XREF, $1, $2 if $S=~/\G (\d+) (\d+) R\b/gc; + ## print substr($S,pos($S)),"::\n"; + $DEPTH=0; + while ($S=~/\G( \S+)/g) { + if ($1 eq ' <<' or $1 eq ' [') { $DEPTH++ } + elsif ($1 eq ' >>' or $1 eq ' ]') { + ## die "($1)\n"; + return undef if 0==$DEPTH--; # err("nesting") + return substr($S,$POS,pos($S)-$POS) if 0==$DEPTH; + } elsif ($DEPTH==0) { return $1 } + } + } else { $N++ } # bare name + } + return undef if $POS!=length($S); # err("invalid source dict"); + "" # not found +} + +# Unit test: +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 0) eq ' al'; +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 1) eq ' makorte'; +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 2) eq ' 42'; +#die unless pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', 3) eq ''; +#die unless pdf_get(\*STDIN, 0, ' [ << >> ]', 0) eq ' << >>'; +#die unless pdf_get(\*STDIN, 0, ' [ << >> ]', 1) eq ''; +#die unless pdf_get(\*STDIN, 0, ' [ << >> [ al makorte 42 ] ]', 1) eq ' [ al makorte 42 ]'; +#die unless pdf_get(\*STDIN, 0, ' << /Alma [ 1 2 ] /Korte [ 3 4 ] >>', '/Korte') eq ' [ 3 4 ]'; +#die unless !defined pdf_get(\*STDIN, 0, ' [ al makorte 42 ]', '/Name'); +#die unless !defined pdf_get(\*STDIN, 0, ' << al makorte 42 >>', 42); +#die unless pdf_get(\*STDIN, 0, ' << al makorte 42 137 >>', 42) eq ' 137'; +#die unless pdf_get(\*STDIN, 0, ' << al makorte >>', 'al') eq ""; +#die "OK"; + +#** Reported boxes: /MediaBox /CropBox /BleedBox /TrimBox /ArtBox +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file +#** @param $_[1] an xref table: $_[1][4][56] is the file offset of object 56 +#** from generation 4 +#** @param $_[2] a PDF source dict (`<< ... >>') of /Type/Catalog +#** /Type/Pages or /Type/Page +#** @param $_[3] hashref to update. $_[3]{BleedBox}[2] will be the URX corner +#** of the BleedBox +sub pdf_get_boxes($$$$) { + my $F=$_[0]; my $XREF=$_[1]; my $S=$_[2]; my $bbi=$_[3]; + return if !defined $S; + for my $name (qw{MediaBox CropBox BleedBox TrimBox ArtBox}) { + my $box=pdf_get($F, $XREF, $S, "/$name"); + next if !defined $box or !length $box + or $box!~m@ \[ ([0-9eE.-]+) ([0-9eE.-]+) ([0-9eE.-]+) ([0-9eE.-]+) \]\Z(?!\n)@ + or !defined c_numval($1) or !defined c_numval($2) or !defined c_numval($3) or !defined c_numval($4); + ($bbi->{LLX},$bbi->{LLY},$bbi->{URX},$bbi->{URY})=($1+0,$2+0,$3+0,$4+0) if $name eq 'MediaBox'; + my $name2="Info.$name"; + ($bbi->{$name2}[0],$bbi->{$name2}[1],$bbi->{$name2}[2],$bbi->{$name2}[3])=($1+0,$2+0,$3+0,$4+0); + } +} + +sub import { + no strict 'refs'; + my $package=(caller())[0]; + shift; + for my $p (@_ ? @_ : qw{pdf_get_boxes pdf_get pdf_read_xref pdf_read_obj + pdf_rewrite pdf_ref}) { *{$package."::$p"}=\&{$p} } +} + +just::end} + +BEGIN{$ INC{'Htex/pdfboxes.pm'}='Htex/pdfboxes.pm'} + +package Htex::pdfboxes; +# pdfboxes.pl -- extract bounding box information from PDFs and update them +# see perldoc(1) POD documentation later +# by pts@fazekas.hu at Sat Jan 25 14:26:26 2003 +# docs at Tue Jan 28 11:29:55 CET 2003 +# + +use just +1; +use strict; +use integer; +use Htex::PDFread; +BEGIN { $Htex::pdfboxes::VERSION=0.05 } + +#** Derived from pdf_read_xref() +#** @param $_[0] a filehandle (e.g \*STDIN), containing a PDF file, positioned +#** just before an `xref' table +#** @param $_[1] a file offset +#** @param $_[2] number to add to /Size +#** @param $_[3] arrayref containing xref20 intervals +#** @param $_[4] retval for original trailer length +#** @param $_[5] retval for original trailer offset +#** -param $_[6] arrayref, trailer offsets (not the topmost) will be pushed to +#** @return the `trailer' section after the `xref'; or undef +sub my_read_xref($$$$$$) { + # made much faster at Wed Dec 18 09:50:23 CET 2002 + my $T; + my $E; + my($F,$fofs,$addsize,$xrefs)=@_; + my($first,$len,$flen); + my $ret_trailer; + prev_xref: + return undef unless seek $F, $fofs, 0; + return undef if 8>read $F, $T, 1024; + $fofs+=length($T); + return undef unless $T=~s@\A\s*xref\s+(\d+)\s+(\d+)\s+(?=\S)@@; + $fofs-=length($T); + while (1) { + ($first,$len)=($1+0,$2+0); + # Now: ($fofs ... $fofs+20*$len) contains xref enties + push @$xrefs, $fofs, $fofs+20*$len; + ## print " $first + $len\n"; + $flen=($len*=20)-length($T)+20; # +20: two-number header of next section + return undef unless $flen<1 or $flen==read $F, $T, $flen, length($T); + for (my $I=0;$I<$len;$I+=20, $first++) { + $E=substr($T, $I, 20); + return undef unless $E=~/\A(\d{10})\s(\d{5})\s([nf])\s\s/; + ## print "($1 $2 $3)\n"; + # $XREF->[$2+0][$first]=$1+0 if $3 eq 'n'; + } + $E=substr($T, $len); + $fofs+=length($T); + last if $E!~s@\A\s*(\d+)\s*(\d+)\s+(?=\S)@@; # next section + $fofs-=length($E); + $T=$E; + } + return undef if length($T)!=$len and !seek $F, -length($T)+$len, 1; + $fofs+=$len-length($T); + return undef if 20>read $F, $T, 2048; # read trailer + $T=~s@%.*@ @g; # assume there are no strings + return undef unless $T=~s@(\s*>>\s*).*@@s; + ($_[4],$_[5])=(length($T)+length($1),$fofs) if !defined $ret_trailer; + # push @{$_[6]}, $fofs+length($1), $fofs+length($1)+length($2) + push @$xrefs, $fofs+length($1), -($fofs+length($1)+length($2)) + if defined($ret_trailer) + and $T=~m@\A(\s*trailer\s*<<.*?)(\s*/Prev\s+\d+[\000\011\012\014\015\040]*[<>{}\[\]()/]?)@s; + return undef if $T!~s/\A\s*trailer\s*<<\s*//; + if (!defined $ret_trailer) { + return undef if $T!~s@/Size\s+(\d+)@"/Size ".($1+$addsize)@e; + ## $T=~y/\r/\n/; die "$T"; + $ret_trailer=$T; + } + if ($T=~m@/Prev\s+(\d+)@) { $fofs=$1+0; goto prev_xref } + $ret_trailer +} + +#** Modifies the /Prev value in a PDF trailer, tries not to increase length +#** of $_[0]. +#** @param $_[0] string containing a PDF trailer /Prev entry +#** @param $_[1] coderef to calculate modification +#** @return the modified string, or undef +sub modify_prev($$) { + my($S,$N)=@_; + my $lenS=length($S); + my $T=$S; + return $T unless $T=~s@(/Prev\s+)(\d+)@$1.$N->($2)@e; # preserve spaces + if (length($T)>$lenS) { # Imp: test this + $T=$S; + die unless $T=~s@\s*/Prev\s+(\d+)[\000\011\012\014\015\040]*([<>{}\[\]()/]?)@ + "/Prev ".$N->($1).(length$2 ? $2 : " ") + @; + # ^^^ don't check for comments: $T=~s@\s*/Prev\s+(\d+)\s*(?:%.*)* + } + die unless length($T)>=$lenS or $T=~s@(/Prev\s+\d+)@$1.(" "x(length($T)-$lenS))@e; + # Now: length($T)>=$lenS + $T +} + +#** @param $_[0] $bbi hashref +#** @return a multiline dump of all key--value pairs, sorted by key +sub all2($) { + my $bbi=$_[0]; + my $RET=""; + for my $key (sort keys %$bbi) { if ($key=~/\AInfo[.](\w+Box)\Z(?!\n)/) { #1<length $key + my $val=$bbi->{$key}; + $RET.="/$1 ".(ref($val)eq'ARRAY' ? "[@$val]\n" : "$val\n"); + } } + $RET +} + +sub usage() { + die "This is pdfboxes.pl by pts\@fazekas.hu, version $Htex::pdfboxes::VERSION +This program is free software, licensed under the GNU GPL. +This software comes with absolutely NO WARRANTY. Use at your own risk! + +I can extract /MediaBox, /CropBox and other bounding box information from PDF +files, and write back this information to the begininning of the PDF. Run this +to get more docs: + perldoc '$0' + +Usage: $0 [<action>] <input.pdf> [<output.pdf>]\n +Action is one of: -- --show\n" +} + +just::main; + +my $outfilename; +my $infilename; +my $show_p=0; +usage if !@ARGV; +if (@ARGV==1) { + $show_p=1; +} else { + if ($ARGV[0] eq '--') { shift @ARGV; } + elsif ($ARGV[0] eq '--show') { $show_p=1; shift @ARGV; } + elsif ($ARGV[0]=~/\A-/) { print STDERR "$0: unknown option: $ARGV[0]"; usage } +} +($infilename,$outfilename)=@ARGV; # $outfilename possibly undef + +# Dat: reading PDF from STDIN not supported, because it is probably unseekable +die "$0: open $infilename: $!\n" if !open F, "< $infilename"; +die unless binmode F; + +my $head; +# vvv 2048: file header + max length(/Type/pdfboxes) +if (32>read F, $head, 2048) { + IOerr: die "$0: I/O error in $infilename: $!\n" +} +if ($head!~/\A(%PDF-[!-~]+)/) { + SYerr: die "$0: syntax error in $infilename. Not a PDF?\n"; +} +my $firstline=$1; + +my $binary_p=($head=~/\A[^\r\n]+[\r\n]+[ -~]*[^\n\r -~]/) ? 'Binary' : 'Clean7Bit'; +#$head=pdf_rewrite($head,1); +$head=~s@\A(.*?)(\bendobj\s*).*@$1@s; # The first obj decides whether it is linearized +my $headprelen=length($1)+length($2); +goto SYerr if $head!~/[\n\r](\d+\s+\d+\s+obj)/g; +my $obj1ofs=pos($head)-length($1); +$head=substr($head,$obj1ofs); +my $page1obj; +my $linearized_p=0; +my $was_pdfboxes=0; # the obj # of the pdfboxes.pl already applied +#if ($head=~s@\A((\d+)\s+\d+\s+obj\s*<<.*?/Type\s*/pdfboxes\b.*?\bendobj\s*)@@s) { +if ($head=~m@\A(\d+)\s+\d+\s+obj\s*<<.*?/Type\s*/pdfboxes\b@s) { + goto SYerr if !defined $headprelen; + $obj1ofs=$headprelen; $head=""; + # ^^^ remove previous instance of /pdfboxes + # ^^^ might not be a real obj at $obj1ofs + $was_pdfboxes=$1+0; +} elsif ($head=~m@/Linearized\b@ and $head=~m@/O\s+(\d+)@) { + $linearized_p=1; + $page1obj=$1+0; +} +goto IOerr if !seek F, -1024, 2 and !seek F, 0, 0; +my $tailofs=tell F; +goto IOerr if 1>read F, $head, 1024; +goto SYerr if $head!~/startxref\s+(\d+)\s*%%EOF\s*\Z(?!\n)/ + and $head!~/startxref\s+(\d+)\s*%%EOF/; +# ^^^ Dat: some PDF files contain binary junk at the end + +my $xref_ofs=$1+0; +my $xrefs=[]; +my $oldtrailerlen; +my $oldtrailerofs; +# my @trailersofs; +my $trailerx=my_read_xref(\*F, $xref_ofs, $was_pdfboxes==0, $xrefs, $oldtrailerlen, $oldtrailerofs); # , \@trailersofs); +## print "(@trailersofs)\n"; +goto SYerr if !defined $trailerx; +goto SYerr if $trailerx!~m@/Size\s+(\d+)@; +my $oldSize=$1-1; + +# Imp: remove code duplication with package Htex::ImgBBox +goto IOerr if !seek \*F, $xref_ofs, 0; +my $xref=[]; +my $trailer=pdf_read_xref(\*F,$xref); +goto SYerr if !defined $trailer; +my $pages; +my $type; +my $bbi={}; +if (!defined $page1obj) { do_pdf_slow: + my $root=pdf_get(\*F,$xref,$trailer,'/Root'); + goto IOerr if !defined $root; goto SYerr if !length $root; + $type=pdf_get(\*F,$xref,$root,'/Type'); + goto IOerr if !defined $type; goto SYerr if $type ne ' /Catalog'; + # die $root; + # vvv Dat: reading xref for /Pages in a linearized PDF is quite slow + $pages=pdf_get(\*F,$xref,$root,'/Pages'); + goto IOerr if !defined $pages; goto SYerr if !length $pages; + ## die $pages; + my $kids; + while (1) { + $type=pdf_get(\*F,$xref,$pages,'/Type'); + goto IOerr if !defined $type; + last if $type ne ' /Pages'; + pdf_get_boxes(\*F, $xref, $pages, $bbi); + $kids=pdf_get(\*F,$xref,$pages,'/Kids'); + goto IOerr if !defined $kids; goto SYerr if !length $kids; + ## die $kids; + $pages=pdf_get(\*F,$xref,$kids,0); + ## die $pages; + goto IOerr if !defined $pages; goto SYerr if !length $pages; + } + goto SYerr if $type ne ' /Page'; + # Dat: cannot set $page1obj properly here, because it might be a direct object + $bbi->{'Info.page1obj'}=$Htex::PDFread::pdf_last_ref0; +} else { + # die $page1obj; + $pages=pdf_ref(\*F, $xref, $page1obj, 0); + goto IOerr if !defined $pages; + $type=pdf_get(\*F,$xref,$pages,'/Type'); + goto IOerr if !defined $type; + goto SYerr if $type ne ' /Page'; + my $mediabox=pdf_get(\*F,$xref,$pages,'/MediaBox'); + goto IOerr if !defined $mediabox; + goto do_pdf_slow if !length $mediabox; +} +pdf_get_boxes(\*F, $xref, $pages, $bbi); +print all2($bbi) if $show_p; + +# -- write it back + +my @tmpfiles; +END { unlink @tmpfiles } + +if (defined $outfilename) { + my $inplace_p=0; + + if ($outfilename eq $infilename) { + # die "$0: cannot modify file in place: $outfilename\n" + $inplace_p=1; + do { $outfilename.=".tmp.$$" } while -e $outfilename; + push @tmpfiles, $outfilename; + } + if ($outfilename eq '-') { + die unless open O, ">&STDOUT"; + } else { + die "$0: open_w $outfilename: $!\n" if !open O, "> $outfilename"; + } + die unless binmode O; + # Dat: $newobj destroys the /Linearized property, but never mind. + # my $newobj="$oldSize 0 obj\n<</Type/pdfboxes\n/Kis (".scalar(localtime).")>>\nendobj\n"; + my $newobj="$oldSize 0 obj\n<</Type/pdfboxes%\n".all2($bbi).">>\nendobj\n"; + + my $outhead="$firstline\n"; + $outhead.="%\307\354\217\242\n" if $binary_p; + my $delta=length($outhead)+length($newobj)-$obj1ofs; + my $newxrefentry=sprintf"%d 1\n%010d 00000 n \n", + $oldSize, length($outhead); + my $newtrailer="trailer\n<<\n$trailerx\n>>\n"; + my $newtrailerlen; + my $trailerdelta; + + do { # iterate until lengths are right + $newtrailerlen=length($newtrailer); + $trailerdelta=length($newxrefentry)+$newtrailerlen-$oldtrailerlen; + $newtrailer=modify_prev($newtrailer, sub { $_[0]+$delta+($_[0]>$xref_ofs ? $trailerdelta : 0) } ); + } until length($newtrailer)==$newtrailerlen; + + if (!print O $outhead, $newobj) { + OOerr: die "$0: write $outfilename: $!\n" + } + + # die unless seek F, $obj1ofs, 0; + my %xrefs=@$xrefs; + ## print STDERR "@$xrefs\n"; + #** F has been dumped 0...$doneofs + my $doneofs=$obj1ofs; + goto IOerr unless seek F, $doneofs, 0; + for my $from (sort {$a<=>$b} keys %xrefs) { + ## print STDERR "xrefs $from $xrefs{$from} ($doneofs)\n"; + my $to=$xrefs{$from}; + + # Copy + die "$0: inconsistent offsets: $doneofs > $from" if $doneofs>$from; + my $O=$from-4096; + my $S; + while ($doneofs<$O) { + goto IOerr unless 4096==read F, $S, 4096; + goto OOerr unless print O $S; + $doneofs+=4096; + } + if ($doneofs<$from) { + goto IOerr unless $from-$doneofs==read F, $S, $from-$doneofs; + goto OOerr unless print O $S; + $doneofs=$from; + } + if ($to<0) { # /Prev correction for the 2nd, 3rd etc. /Prevs + # Example file: examples/lm2.pdf + ## print STDERR "/Prev correction $from ... $to ($doneofs)\n"; + goto IOerr unless -$to-$doneofs==read F, $S, -$to-$doneofs; + $S=modify_prev($S, sub { $_[0]+$delta+($_[0]>$xref_ofs ? $trailerdelta : 0) } ); + die "$0: modified /Prev too long\n" if length($S)!=-$to-$doneofs; + goto OOerr unless print O $S; + $doneofs=-$to; + } else { # xref offset correction + die "$0: inconsistent xref interval: $from > $to " if $from>$to or 0!=($to-$from)%20; + while ($doneofs<$to) { # Imp: speed up with larger read bursts? + goto IOerr unless 20==read F, $S, 20; + goto SYerr unless $S=~/\A\d{10} \d{5} [nf]\s\s/; + if ($was_pdfboxes and $doneofs==$oldtrailerofs-20) { + $S=substr($newxrefentry,-20); + } else { + my $ofs=0+substr($S,0,10); + $ofs+=$trailerdelta if $ofs>$xref_ofs; + substr($S,0,10)=sprintf("%010d",$ofs+$delta); + } + goto OOerr unless print O $S; + $doneofs+=20; + } + if ($doneofs==$oldtrailerofs) { # the xref entry we modify the trailer of + ## print "$doneofs -> $oldtrailerofs\n"; + goto IOerr unless seek F, $oldtrailerlen, 1; + $doneofs+=$oldtrailerlen; + goto OOerr unless print O ($was_pdfboxes==0 ? $newxrefentry : ""), $newtrailer; + } + } + } + + my $extra_trailer="trailer\n<<\n>>\n"; + $extra_trailer="" if $doneofs==$oldtrailerofs+$oldtrailerlen; + { my $O=$tailofs-4096; + my $S; + while ($doneofs<$O) { + goto IOerr unless 4096==read F, $S, 4096; + goto OOerr unless print O $S; + $doneofs+=4096; + } + if ($doneofs<$tailofs) { + goto IOerr unless $tailofs-$doneofs==read F, $S, $tailofs-$doneofs; + goto OOerr unless print O $S; + $doneofs=$tailofs; + } + goto IOerr if 16>read(F, $S, 1025) or length($S)>1024; + # ^^^ $tailofs is at most 1024 bytes before EOF + goto SYerr unless $S=~s@ + ((?:\btrailer\s*<<.*?>>\s*)?) startxref\s+(\d+)\s*%%EOF + ( \s*\Z(?!\n) | ) + @@sx; + # @length($1)?($extra_trailer=""):""@sex; + goto OOerr unless print O $S; + } + + die unless printf O "${extra_trailer}startxref\n%d\n%%%%EOF\n", $xref_ofs+$delta; + die unless close O; + if ($inplace_p) { + die "$0: rename $outfilename -> $infilename: $!\n" if !rename $outfilename, $infilename; + } +} + +just::end __END__ + +=begin man + +.ds pts-dev \*[.T] +.do if '\*[.T]'ascii' .ds pts-dev tty +.do if '\*[.T]'ascii8' .ds pts-dev tty +.do if '\*[.T]'latin1' .ds pts-dev tty +.do if '\*[.T]'nippon' .ds pts-dev tty +.do if '\*[.T]'utf8' .ds pts-dev tty +.do if '\*[.T]'cp1047' .ds pts-dev tty +.do if '\*[pts-dev]'tty' \{\ +.ll 79 +.pl 33333v +.nr IN 2n +.\} +.ad n + +=end + +=head1 NAME + +pdfboxes.pl - extract bounding box information from PDFs and update them + +=head1 SYNOPSIS + +C<B<pdfboxes.pl>> + S<[ C<-->> + S<| C<--show> ]> + S<I<input.pdf> I<output.pdf>> + +=head1 DESCRIPTION + +pdfboxes.pl is a standalone Perl script that can extract /MediaBox, +/CropBox and other bounding box information from PDF files, and +write back this information to the begininning of the PDF, so other programs, +such as pdftex.def of the graphicx package of LaTeX can read the bounding +box by simply reading the first few lines of the PDF output of pdfboxes.pl. + +To get the bounding box from other file formats, use img_bbox.pl from the same +author. + +=head1 COMMENTS + +Breaks a linearized PDF (as defined by Appendix F of PDFRef.pdf) into a +non-linearized one. diff --git a/macros/latex/exptl/graphicp/pts_bbox.sty b/macros/latex/exptl/graphicp/pts_bbox.sty new file mode 100644 index 0000000000..d4f5a1a548 --- /dev/null +++ b/macros/latex/exptl/graphicp/pts_bbox.sty @@ -0,0 +1,418 @@ +% +% pts_bbox.sty -- open an image and read BoundingBox info +% modified by pts@fazekas.hu at Sun Feb 2 17:07:43 CET 2003 +% + +\expandafter\ifx\csname ifLaTeX\endcsname\relax\input laemu.sty\relax\fi% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{pts_bbox}[2003/02/02 v0.2 determine BoundingBox] + +\def\@@imgread@sPS{PS}% +\def\@@imgread@sEPS{EPS}% +\def\@@imgread@sMetaPost{MetaPost}% + +\def\@tempa{}% +\def\@tempb{}% + +%** `\@@imgread@stripps FF..\\' set \@tempa to `FF' with `EPS.' and `PS.' +%** stripped from the beginning. FF is a FileFormat such as `TIFF' or +%** `EPS.MPS'. +\def\@@imgread@stripps#1.#2.#3\\{% + \def\@tempa{#1}% + \def\@tempb{#2}% + \ifx\@tempb\@empty\else% + \ifx\@tempa\@@imgread@sPS \def\@tempa{#2}% + \else\ifx\@tempa\@@imgread@sEPS \def\@tempa{#2}% + \else \def\@tempa{#1.#2}\fi\fi% + \fi% +}% + +%%** `\@@imgread@strpqbp#\\' expands to `#' if `#' begins with `?'; else +%%** it expands to `#bp' +%\def\@@imgread@stripqbp#1#2\\{% +% \if\noexpand#1?% +% #1#2% +% \else +% #1#2bp% +% \fi +%}% + +%** Process output of external command `img_bbox.pl --tex'. Strips EPS.* +%** -> * and PS.* -> *. +%** Example: \graphicPmeta{f2cletter.pdf}{PDF}{3}{-10}{23}{20} +\def\graphicPmeta#1#2#3#4#5#6{% + %\message{meta{#1}{#2}{#3}{#4}{#5}{#6};}% + \begingroup% + \@@imgread@stripps#2..\\% returns \@tempa, ruins \@tempb + \edef\@tempa{% + \noexpand\def% + \expandafter\noexpand\csname @@xb@#1\endcsname% + %{{\@tempa}{\@@imgread@stripqbp#3\\}{\@@imgread@stripqbp#4\\}% + % {\@@imgread@stripqbp#5\\}{\@@imgread@stripqbp#6\\}}% + {{\@tempa}{#3}{#4}{#5}{#6}}% + }% + \expandafter\endgroup\@tempa% + %\expandafter\edef\csname @@xb@#1\endcsname{{\@tempa}{#3bp}{#4bp}{#5bp}{#6bp}}% +}% + +%\graphicPmeta{a}{PS.MPS}{3}{4}{5}{6}\message{<\@@xb@a>}\end + +%** Opens the external image file, reads the bounding box information, and +%** calls #1{LLX}{LLY}{URX}{URY}. Failure is indicated by setting any of +%** LLX, LLY, URX or URY to ?. +%** @param #1 a \cs#1#2#3#4 that records the bounding box information +%** @param #2 a filename +\def\@@GetBBox#1#2{% + % Imp: unset temporary variables (@@gp@xb) + \edef\@@gp@xb{@@xb@#2}% \ @@xb@foo.eps + \expandafter\ifx\csname\@@gp@xb\endcsname\relax% no cached value yet + %\PackageError{pts_img}{BBox read unimplemented}\@ehc% + \@@imgread@afile\graphicPmeta{#2}% + \fi% + \edef\@@gp@xc{\csname\@@gp@xb\endcsname}% full expansion of cached value + %\message{;\@@gp@xc;}% + %\expandafter\expandafter\expandafter#1\expandafter\@gobble\@@gp@xc% gobble FileFormat + \expandafter#1\@@gp@xc% report FileFormat and bbox +}% + +\expandafter\ifx\csname @tempcnta\endcsname\relax% + \newcount\@tempcnta +\fi +%\def\@makeother#1{\catcode`#1=12\relax} +%\chardef\@inputcheck0 +% Dat: uses \newread\@inputcheck + +\newif\if@@imgread@ +%\def\@latex@error{\errmessage{#1}} +%\message{\@@imgread@BBox}% +%*** The DOS EPSF header +\edef\@@imgread@DOSEPSF{% + % Imp: specify shorter + \expandafter\@secondoftwo\string\^^c5% + \expandafter\@secondoftwo\string\^^d0% + \expandafter\@secondoftwo\string\^^d3% + \expandafter\@secondoftwo\string\^^c6% +}% +%** A dot, and the first 3 bytes of a JPEG file +\edef\@@imgread@JPEG{% + % Imp: specify shorter + .% + \expandafter\@secondoftwo\string\^^ff% + \expandafter\@secondoftwo\string\^^d8% + \expandafter\@secondoftwo\string\^^ff% +}% +\edef\@@imgread@PNG{\expandafter\@secondoftwo\string\^^89PNG}% +\edef\@@imgread@TIFFMM{MM..}% MSB first TIFF header is "MM\0*" +\edef\@@imgread@TIFFII{II*.}% LSB first TIFF header is "II*\0" +\def\@@imgread@atend{atend} +\edef\@@imgread@PDF{\expandafter\@secondoftwo\string\%PDF} +\edef\@@imgread@EPS{\expandafter\@secondoftwo\string\%!PS} +%\def\@@img@sPDF{PDF}% +%\def\@@img@sEPS{EPS}% +%\def\@@img@sQ{?}% + +%** \@@imgread@setfour\cs...\\ \def's \cs to be the first four tokens of +%** `...'. `...' must have at least 4 tokens +\long\def\@@imgread@setfour#1#2#3#4#5#6\\{% + \def#1{#2#3#4#5}% +}% +% vvv also defined in other files +{\catcode`p=12\catcode`t=12\gdef\@@mkb#1pt{#1}}% no p,t in @@mkb + +%** Find and process %%BoundingBox ADSC comment in an EPS file, or the first +%** occurence of `/Mediabox [' (at BOL) in a PDF file. The PDF case is not +%** perfect, but cannot be, since TeX is unable to read binary files +%** properly; preprocess the PDF file with pdfboxes.pl to make sure. +%** @param #1 a \cs. calls #1{FileName}{Fileformat}{LLX}{LLY}{URX}{URY} +%** @param #2 filename +\def\@@imgread@afile#1#2{% + % Dat: EPS with DOS-style binary preview is not supported + \begingroup + \@tempcnta0 + % 0 Escape character (|\| in this manual) + % 1 Beginning of group (|{| in this manual) + % 2 End of group (|}| in this manual) + % 3 Math shift (|$| in this manual) + % 4 Alignment tab (| | in this manual) + % 5 End of line (\<return> in this manual) + % 6 Parameter (|#| in this manual) + % 7 Superscript (|^| in this manual) + % 8 Subscript (|_| in this manual) + % 9 Ignored character (\<null> in this manual) + %10 Space (\] in this manual) + %11 Letter (|A|, \dots, |Z| and |a|, \dots, |z|) + %12 Other character (none of the above or below) + %13 Active character (|~| in this manual) + %14 Comment character (|%| in this manual) + %15 Invalid character (\<delete> in this manual) + % + % (by pts@fazekas.hu at Sun Feb 2 18:27:56 CET 2003) + % The TeX \read primitive works like this: low-level line separators are + % "\012", "\015" and "\015\012". \read reads a single line, as ended by + % a single low-level line-separator. Two extra separators are assumed to be + % at EOF. Space tokens (10) at the beginning of the line are ignored. A + % series of empty lines are read as \par + space. The first end-of-line (5) + % token is converted to a space, and the rest is ignored. The first + % command (14) character and the rest is ignored. + % \ifeof is true between \openin and the first \read iff \open failed. + % Thus, we set all unprintable characters to ignored (9). We set both + % '\012' and '\015' to be comment (14), so no space would be appended at + % EOLs. Space and tab will be set to space (10). Thus real spaces won't be + % ignored at the beginning of the lines, and \par will never be read. + % It is impossible to read the %!PS header of some DOS EPSF files, + % because it might be before the first low-level line separator, but + % ignored because of how we read the EPSF header. + % + \@tempcnta0 + \loop\ifnum\@tempcnta<32 % + \catcode\@tempcnta9 % ignored + \advance\@tempcnta\@ne + \repeat + \@tempcnta127 + \loop\ifnum\@tempcnta<256% + \catcode\@tempcnta9 % ignored + \advance\@tempcnta\@ne + \repeat + \catcode`\\12% other + \catcode`\{12% other + \catcode`\}12% other + \catcode`\}12% other + \catcode`\$12% other + \catcode`\&12% other + \catcode`\#12% other + \catcode`\^12% other + \catcode`\_12% other + \catcode`\%12% other + \catcode`\~12% other + \catcode`\:12% other + \catcode`\-12% other + \catcode32=10% ' ': space, ignored at BOL + \catcode9=10% '\t': space, ignored at BOL + \catcode`\]10% ']': space, so we can parse /MediaBox correctly + \catcode\endlinechar14% '\015': end-of-line + \catcode10=14% + \catcode13=14% + \catcode0=14% important for tiff + \catcode198=12% last byte of DOS EPSF header + \catcode211=12% third byte of DOS EPSF header + \catcode208=12% second byte of DOS EPSF header + \catcode197=12% first byte of DOS EPSF header + \catcode137=12% first byte of PNG header + \catcode255=12% JPEG marker-header + \catcode216=12% JPEG SOI marker + %\endlinechar=-1% + \immediate\openin\@inputcheck#2 % + \def\@@imgread@fmt{?}% + \def\@@imgread@bbox{}% not found yet + \ifeof\@inputcheck + %\@latex@error% + \PackageError{bbox}{Image file `#2' not found}\@ehc + \else + \read\@inputcheck to\@tempa% first line + \catcode137=9 % first byte of PNG header + \catcode255=9 % JPEG marker-header + \catcode216=9 % JPEG SOI marker + \expandafter\@@imgread@setfour\expandafter\@tempb\@tempa....\\% + \expandafter\@@imgread@setfour\expandafter\@tempa\expandafter.\@tempb\\% \@tempb == ABCD -> @tempa = .ABC + % Now \@tempb contains the first 4 chars, and \@tempa is the first line + %\message{[\@tempb]}% + \let\@@imgread@test@end\@@imgread@test@yesend + \ifx\@tempb\@@imgread@PNG% + \def\@@imgread@fmt{PNG}% + \@@imgread@pdftexgetwh{#2}% + \else\ifx\@tempb\@@imgread@TIFFII% + \def\@@imgread@fmt{TIFF}% + \@@imgread@pdftexgetwh{#2}% + \else\ifx\@tempb\@@imgread@TIFFMM% + \def\@@imgread@fmt{TIFF}% + \@@imgread@pdftexgetwh{#2}% + \else\ifx\@tempb\@@imgread@DOSEPSF% + % Emit a warning, since these DOS EPSF files cannot be embedded + % properly by dvips, and even reading the bounding box is quite + % unstable. + \PackageWarning{pts_img}{DOS EPSF header in file `#2'\@gobble}% + \let\@tempb\@@imgread@EPS% + \let\@@imgread@test@end\@@imgread@test@noend + \def\@@imgread@fmt{EPS}% or PS + \else\ifx\@tempb\@@imgread@EPS% + \else\ifx\@tempb\@@imgread@PDF% + \else\ifx\@tempa\@@imgread@JPEG% \@tempa + \def\@@imgread@fmt{JPEG}% + \@@imgread@pdftexgetwh{#2}% + %\else% unknown image format + \fi\fi\fi\fi\fi\fi\fi% + \ifx\@tempb\@@imgread@EPS% + \def\@@imgread@fmt{EPS}% or PS + \edef\@percentchar{\expandafter\@secondoftwo\string\%}% LaTeX has it + \edef\@@imgread@BBox{\@percentchar\@percentchar BoundingBox}% + \edef\@@imgread@BBoh{\@percentchar\@percentchar HiResBoundingBox}% + \edef\@@imgread@BBoe{\@percentchar\@percentchar ExactBoundingBox}% + \edef\@@imgread@BBoc{\@percentchar\@percentchar Creator}% + \let\@@imgread@find@bb\@@imgread@find@eps% + \@@imgread@lines% + \else\ifx\@tempb\@@imgread@PDF% + \def\@@imgread@fmt{PDF}% + \edef\@@imgread@BBox{/MediaBox}% `/MediaBox [' or `/MediaBox[' + \let\@@imgread@find@bb\@@imgread@find@pdf% + \@@imgread@lines% + \else% unknown + \fi\fi% + %\message{format:\@@imgread@fmt.}% + \immediate\closein\@inputcheck% + \fi% \ifeof\@inputcheck + \edef\@tempa{\noexpand#1{#2}{\@@imgread@fmt}\@tempa}% + \expandafter\endgroup\@tempa% end the group and call output command +} + +%** Use pdfTeX to define \@tempa to be a bounding box of the image. +%** @param #1 filename +\def\@@imgread@pdftexgetwh#1{% !! Imp: use pdfTeX (if present) to get BBox + \def\@tempa{{?}{?}{?}{?}}% not pdfTeX. Cannot read binary files. Give up. + \expandafter\ifx\csname pdfoutput\endcsname\relax% + \else\ifnum0<\pdftexversion% + % Newer versions of pdfTeX can embed PNG, JPEG and TIFF images directly. + % Just load the image into a \hbox, and measure its dimensions. + \begingroup\setbox0=\hbox{% + \expandafter\ifx\csname pdfximage\endcsname\relax + \ifnum\pdftexversion<13% older, Debian Slink + \pdfimage#1\noexpand\noexpand\noexpand\@empty \relax% #1 may start with `width' + \else + \pdfimage{#1}% + \fi + \else% quite new pdfTeX + %\immediate\pdfximage would include the image file unnecessarily. + % Without \immediate, only a single PDF xref entry is occupied per + % image. This call to \pdfximage doesn't make the bug in + % pdftex_bug.tex manifest. What a luck. + \pdfximage{#1}% + \pdfrefximage\pdflastximage + \fi + }% + % Now \ht0 etc. have the width in bp. We convert it to pt first, and + % then remove the `pt' unit. The orinal dimension (in bp) was an integer, + % so we round to the nearest integer to compensate errors of fixed point + % arithmetic. + \dp0=-.99626400996264\dp0% *-72/72.27 + \wd0=.99626400996264\wd0% + \ht0=.99626400996264\ht0% + \count0=\dp0\advance\count0 32768\divide\count0 65536% + \count1=\wd0\advance\count1 32768\divide\count1 65536% + \count2=\ht0\advance\count2 32768\divide\count2 65536% + %\message{pdfbbox=(0,\the\count0,\the\count1,\the\count2)}% + \edef\@tempa{\noexpand\def\noexpand\@tempa{{0}{\the\count0}{\the\count1}{\the\count2}}}% + \expandafter\endgroup\@tempa + \fi\fi% +} + +%** Read the file line-by-line, stop at the first line containing BBox info. +\def\@@imgread@lines{% + \@@imgread@true + \let\@tempb\@@imgread@false + \loop + %\endlinechar=65 \relax% doesn't work, a space will be appended + %\catcode13=9 % doesn't work, a space will be appended + \read\@inputcheck to\@tempa + \ifeof\@inputcheck + \@@imgread@false + \else + %\message{t(\@tempa)}% + \expandafter\@@imgread@find@bb\@tempa:[.\\% + \fi + \if@@imgread@\repeat + \ifx\@@imgread@bbox\@empty + \def\@tempa{{?}{?}{?}{?}}% + \else% found BBox -- maybe not syntactically correct + %\message{///\@tempa***}% + \expandafter\@@imgread@parse@bb\@@imgread@bbox\\% + \fi% +} +\def\@@imgread@find@eps#1:#2#3\\{% + \def\@tempa{#1}% + %\message{find(\@tempa)}% + \@@imgread@test@end#1.....\\% modifies \@tempa + \ifx\@tempa\@@imgread@BBox% + \@@imgread@test@atend#2#3()\\% + \else\ifx\@tempa\@@imgread@BBoh% + \@@imgread@test@atend#2#3()\\% + \ifx\@@imgread@bbox\@empty\else% + \def\@@imgread@BBox{:}% don't recognise subsequent %%BoundingBox after %%HiResBoundingBox + \fi% + \else\ifx\@tempa\@@imgread@BBoe% + \@@imgread@test@atend#2#3()\\% + \ifx\@@imgread@bbox\@empty\else% + \def\@@imgread@BBox{:}% don't recognise subsequent %%BoundingBox after %%HiResBoundingBox + \def\@@imgread@BBoh{:}% don't recognise subsequent %%HiResBoundingBox after %%ExactBoundingBox + \fi% + \else\ifx\@tempa\@@imgread@BBoc% + \@@imgread@test@creator#2#3\\% + \fi\fi\fi\fi% +} +%** In normal mode. Runs \@tempb if about to end +%** @param #1..#5 single chararacter tokens +\def\@@imgread@test@yesend#1#2#3#4#5#6\\{% + %\message{end(#1#2#3#4#5)}% + \if\noexpand#1\@percentchar% + \if\noexpand#2\@percentchar% + \if\noexpand#3E% + \if\noexpand#4n% + \if\noexpand#5d% + \@tempb% + \fi% + \fi% + \fi% + \else% + \@tempb% + \fi% + \else% + \@tempb% + \fi% +}% +%** In MetaPost mode. Runs \@tempb if about to end. +%** The %%HiResBoundingBox comment emitted by ConTeXt is usually after +%** %%EndProlog. So we stop at the first line not beginning with `%' +%** @param #1..#5 single chararacter tokens +\def\@@imgread@test@mpend#1#2#3#4#5#6\\{% + \if\noexpand#1\@percentchar% + \else% + \@tempb% + \fi% +}% +%** Used as \@@imgread@test@end when reading a DOS EPSF file +\def\@@imgread@test@noend#1\\{}% + +\def\@@imgread@find@pdf#1[#2#3\\{% + \def\@tempa{#1}% + %\message{find(\@tempa)}% + \ifx\@tempa\@@imgread@BBox \@@imgread@test@atend#2#3()\\\fi% +} +%** Recognise the ``%%Creator: MetaPost'' ADSC comment. Ruins @tempa +\def\@@imgread@test@creator#1:#2\\{% + %\message{cr(#1)}% + \def\@tempa{#1}% + \ifx\@tempa\@@imgread@sMetaPost% + \def\@@imgread@fmt{MPS}% + \let\@@imgread@test@end\@@imgread@test@mpend% find late %%HiresBoundingBox + \fi% +}% +\def\@@imgread@test@atend#1(#2)#3\\{% + %\message{atend(#2)}% + \ifx\@tempb\relax\else% don't allow early ending for (atend) + \let\@@imgread@test@end\@@imgread@test@yesend + \fi% + \def\@tempa{#2}% + \ifx\@tempa\@@imgread@atend + \@@imgread@true + \let\@tempb\relax% read till EOF + \else + %\message{gotit(#1)}% + \def\@@imgread@bbox{#1}% + % Don't do \@@imgread@false, because better %%BoundingBox may come before %%End + \fi% +} +%** Sets \@tempa to the BBox info, ruins \dimen[1234] +\def\@@imgread@parse@bb#1 #2 #3 #4:#5\\{% + \dimen1=#1pt \dimen2=#2pt \dimen3=#3pt \dimen4=#4pt% simplify and pre-round + % ^^^ important to remove spaces after #4 + \edef\@tempa{{\expandafter\@@mkb\the\dimen1}{\expandafter\@@mkb\the\dimen2}{\expandafter\@@mkb\the\dimen3}{\expandafter\@@mkb\the\dimen4}}% + %\message{bbox(#1)(#2)(#3)(#4)[\@tempa]}% +}% diff --git a/macros/latex/exptl/graphicp/pts_img.sty b/macros/latex/exptl/graphicp/pts_img.sty new file mode 100644 index 0000000000..75d123cc6a --- /dev/null +++ b/macros/latex/exptl/graphicp/pts_img.sty @@ -0,0 +1,801 @@ +% +% pts_img.sty -- better include image files (EPS or PDF) into TeX documents +% by pts@fazekas.hu at Wed Jan 8 16:12:53 CET 2003 +% +% pdftex at Fri Jan 10 02:21:17 CET 2003 +% laemu.sty at Fri Jan 24 13:19:59 CET 2003 +% at Sun Jan 26 20:44:09 CET 2003 +% +% The routines in this file don't need the image to be present. +% + +\expandafter\ifx\csname ifLaTeX\endcsname\relax\input laemu.sty\relax\fi% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{pts_img}[2003/01/24 v0.0 include images] +\RequirePackage{div16b} +%\input div16b.tex +%\catcode`\@=11 % \makeatletter + +% --- utilities + +% by pts@fazekas.hu at Fri Jan 10 00:38:14 CET 2003 +% +%** Places a box of width #1, height #2, depth #3. A rectangular dot of size +%** `1sp' will be placed to the llx and ury corners. The reference point is +%** not moved. The dots will have white color. +%** Don't pass \dimen0 as arguments! +\def\@@spbox#1#2#3{\hbox to0sp{% + \@@img@push@white%\special{color push White}% + \dimen0=#3 \relax\dimen0-\dimen0\advance\dimen0 1sp% + \vrule width1sp height\dimen0 depth#3% + \kern#1 \kern-2sp% + \dimen0=#2 \relax\dimen0-\dimen0\advance\dimen0 2sp% + \vrule width1sp height#2 depth\dimen0% + \@@img@pop%\special{color pop}% + \hss% +}}% + +% \def\@empty{}% not needed for LaTeX, needed for plain TeX + +\def\@@one{1}% must be a macro + +{\catcode`p=12\catcode`t=12\gdef\@@mkb#1pt{#1}}% no p,t in @@mkb +{\catcode`p=12\catcode`t=12\gdef\@@mkbi#1.#2pt{#1}}% no p,t in @@mkb + +%** by pts@fazekas.hu at Fri Jan 10 01:14:31 CET 2003 +%** Expands to the result of the division #1/100. +%** @param #1 a possibly negative decimal integer (-12) or real number +%** (34.56), or a possibly negated \count register specification (-\count5) +\def\@@divhundred#1{% + \expandafter\@@divhundred@c\number#1..\end% +}% +\def\@@divhundred@c#1{% + % Dat: \number will gobble extra leading zeroes after expansion + \if#1-% + -\number\expandafter\@@divhundred@d% + \else% + \number\expandafter\@@divhundred@e% + \fi% + #1% +}% +\def\@@divhundred@d#1{\@@divhundred@a00}% +\def\@@divhundred@e{\@@divhundred@a00}% +\def\@@divhundred@a#1#2#3{% + \if#3.% + .#1#2\expandafter\@@divhundred@b% + \else% + #1\expandafter\@@divhundred@a% + \fi% + #2#3% +}% +\def\@@divhundred@b#1#2#3.#4\end{#3}% Dat: gobble #1 and #2 + +% Regression test: +%\count0=42 +%\count1=-7 +%%\@@divhundred\alma{123}% +%\message{\@@divhundred{1.45}}% +%\message{\@@divhundred{12.45}}% +%\message{\@@divhundred{123.45}}% +%\message{\@@divhundred{1234.5}}% +%\message{\@@divhundred{12345.}}% +%\message{\@@divhundred{-\count0}}% +%\message{\@@divhundred{-0137}}% +%\message{\@@divhundred{-\count1}}% +%\message{\@@divhundred{100}}% 1.00 + +%** `\@@img@pdfsq#\@empty' expands to #, but `\' changed to `\\', `\(' changed +%** to `\(' and `)' changed to '\)'. This is suitable for encoding something +%** inside a PDF string. Discards space tokens, so the user should call +%** \@@quotespace first. +\def\@@img@pdfsq#1{% + \ifx\@empty#1% + \else + %\ifx\space#1\noexpand\space\else% would preserve \space + \if(\noexpand#1\@@img@pdfsq@bs\fi + \if)\noexpand#1\@@img@pdfsq@bs\fi + \if\@@img@pdfsq@bs\noexpand#1\@@img@pdfsq@bs\fi + #1% + %\fi + \expandafter\@@img@pdfsq + \fi +}% +\edef\@@img@pdfsq@bs{\expandafter\@gobble\string\\}% a backslash + +%** Expands to #1, but all space tokens are replaced by the `\space' control +%** sequence. +%** Doesn't work if the space is inside curly braces, but this condition can +%** never happen, because beginning-of-group tokens are prohibited in #1. +%** @param #1 must not contain characters of category beginning-of-group, +%** end-of-group, active-chararacter or control-sequence (not even \space) +\def\@@quotespace#1{% + \@@quotespace@lowa#1 \hsize\@gobble: % + % ^^^ \hsize is an arbitrary non-character token for which \ifx\hsize\hsize is true +}% +\def\@@quotespace@lowa#1 {% + \ifx\hsize#1\@empty% + \else% + #1% gobble the very first space (to balance the extra space added to the end by \@@quotespace) + \expandafter\@@quotespace@lowb + \fi +}% +\def\@@quotespace@lowb#1 {% + \ifx\hsize#1\@empty% + % ^^^ doesn't matter if #1 is more than one token unless \ifx is true + % ^^^ \@empty is there in case #1 is empty, so `\ifx\hsize\@empty' will be called + \else% + \noexpand\space#1% + \expandafter\@@quotespace@lowb + \fi +}% + +% Regression test: +%\message{s[\@@quotespace{}]}% s[] +%\message{s[\@@quotespace{ }]}% s[\space ] +%\message{s[\@@quotespace{a }]}% s[a\space ] % Note that ` ' is a single space token! +%\message{s[\@@quotespace{ b}]}% s[\space b] +%\message{s[\@@quotespace{\space b}]}% s[ b] % arument of \@@quotespace must not contain any control sequence +%\message{s[\@@quotespace{aa bb}]}% s[aa\space bb] +%\edef\@tempa{{a\space\space bc }}% +%\message{s[\expandafter\@@quotespace\@tempa]}% s[a\space \space bc\space ] + + +%\message{(\@@img@pdfsq a)l(ma\\;}% + +%** \edef#1{} if #1 == expand(#2) +%** @param #1 must not be \@tempa +\def\@@img@supportsit#1#2{% + \begingroup% + \edef\@tempa{#2}% + \ifx#1\@tempa% + \edef\@tempa{\noexpand\def\noexpand#1{}}% + \expandafter\endgroup\@tempa + \else + \endgroup + \fi +}% +%\def\@tempb{EPS}% +%\@@img@supportsit\@tempb{EPST} +%\message{(\@tempb)} + +% --- driver selection + +\def\@@img@driver{}% + +\expandafter\ifx\csname pdfoutput\endcsname\relax \chardef\pdfoutput=0 \fi +\expandafter\ifx\csname pdftexversion\endcsname\relax \chardef\pdftexversion=0 \fi + +%** @param #1 desired driver name; examples: +\def\@@img@setdriver#1{% + %\message{setdriver}% + \ifx\@@img@driver\@empty% + \edef\@@img@driver{#1}% + \ifx\@@img@driver\@empty% empty arg + \expandafter\ifx\csname graphicPdriver\endcsname\relax% guess the driver + \def\@@img@driver{dvi}% compatible with dvipdfm, dvips and xdvi + % \expandafter\ifx\csname pdfoutput\endcsname\relax\else% we have already defined it + \ifnum\pdfoutput>0 % + \def\@@img@driver{pdftex}% + \fi% + \else% Example: latex '\def\graphicPdriver{dvipdfm}\input laltest.tex' + \edef\@@img@driver{\graphicPdriver}% + \fi% + \fi% + %\errmessage{\@@img@driver}% + % vvv do driver intitializations + % vvv Imp: meaningful error if not found + \expandafter\ifx\csname @@imgdriver@\@@img@driver\endcsname\relax% + %\errmessage{img driver unknown: "#1"}% + \@@img@warnerr0{driver unknown: `\@@img@driver'}\@ehc% + \def\@@img@driver{dvi}% fallback + \fi + \csname @@imgdriver@\@@img@driver\endcsname% c@r@y@p@t@i@c, eh? + \else% + \edef\@tempa{#1}% + \ifx\@tempa\@@img@driver\else + \errmessage{cannot override img driver: `\@@img@driver' -> `#1'}% + \fi + \fi% +}% + +% +% The Driver interface expects the following macros from the driver: +% +%** Divides by 65536 +%** @param #1 \cs to be defined +%** @param #2 number to be divided +%\def\@@img@divword#1#2{...} +%\def\@@img@div#1#2#3{...} +%** Obsolete. +%\def\@@img@mul#1#2#3{...} +%** @deprecated +%** @param #1 key +%** @param #2 value +%\def\@@img@kv#1#2{...} +%** @param #1 expands to filename +%** @param #2 xscale (number in percent, 100 == no scale) +%** @param #3 yscale (number in percent, 100 == no scale) +%** @param #4 expands to FileFormat (not in \@@img@ff) +%\def\@@img@special#1#2#3{...}#4 +%** \edef#1{} iff the FileFormat specified in the contents of #1 is supported +%** by the driver. +%** @param #1 a macro \cs +%\def\@@img@supported##1 +%** "eps", "pdf" etc. +%\def\@@img@defext{...} +%** Does the driver translate the image automatically as if bbox.llx==0 && +%** bbox.lly=0? "1" or "0" +%\def\@@img@zeroll{...} + +% --- Implementations of the Driver interface + +\def\@@imgdriver@dvips{% dvips, xdvi + \def\@@img@supported##1{% + \@@img@supportsit##1{EPS}% + \@@img@supportsit##1{MPS}% + }% + \def\@@img@zeroll{0}% + \def\@@img@defext{eps}% + \def\@@img@push@white{\special{color push White}}% + \def\@@img@pop{\special{color pop}}% + \def\@@img@divword##1##2{% + \edef##1{##2\space 65536 div}% + }% + \def\@@img@div##1##2##3{% + \edef\@@img@tmp{##3}% + \ifx\@@img@tmp\@@one% do not divide by 1 + \edef##1{##2}% + \else% + \edef##1{##2\space ##3\space div}% + \fi% + }% + %\def\@@img@kv##1##2{##2\space @##1}% + \def\@@img@special##1##2##3##4{{% + \def\@@tmp@c{100}% + \edef\@@tmp@x{##2}% + \edef\@@tmp@y{##3}% + \special{ps: @beginspecial % + \ifx\@@tmp@c\@@tmp@x\else##2 @hscale \fi% Imp: cmp w/o limits + \ifx\@@tmp@c\@@tmp@y\else##3 @vscale \fi% Imp: cmp w/o limits + @setspecial% + }% + \special{ps: plotfile "##1"}% + \special{ps: @endspecial}% + }}% +}% </driver dvips} + +\def\@@imgdriver@dvipdfm{% + \def\@@img@MPS{MPS}% helper for \ifx + \def\@@img@EPS{EPS}% helper for \ifx + \def\@@img@PDF{PDF}% helper for \ifx + \def\@@img@supported##1{% v0.13.2b + \@@img@supportsit##1{EPS}% via the command in -D in dvipdfm/config + \@@img@supportsit##1{MPS}% natively (without HiReSB*), even with .ps extension + \@@img@supportsit##1{PDF}% + \@@img@supportsit##1{JPEG}% + \@@img@supportsit##1{PNG}% + }% + \def\@@img@zeroll{0}% + \def\@@img@defext{pdf}% + \def\@@img@push@white{\special{color push White}}% + \def\@@img@pop{\special{color pop}}% + \def\@@img@divword##1##2{{% + \dimen0 ##2 sp% + \edef##1{\expandafter\@@mkb\the\dimen0}% + \@@keepdefaftergroup##1% + }}% + %\def\@@img@kv##1##2{##1=##2}% + \def\@@img@suppCount{0}% + \def\@@img@special##1##2##3##4{{% + % This could be easy, but we do the hard way because + % -- PNG and JPEG images have to be scaled up by a factor of 100/72. This + % seems to be an intentional misfeature of dvipdfm, because the ebb(1) + % utility outputs bounding boxes scaled down by 72/100. + % -- for PNG and JPEG images \special{pdf: usexobj @N} doesn't work + % properly if N represents an Image XObject. (it outputs a + % scaled-down, square-shaped image) So we create a Form XObject. + % -- a Form XObject crops the negative left sidebearing of its contents, + % so we must not use it for MPS, EPS and PDF images. We use an Image + % XObject then. + % -- MPS seems to work fine, nothing is cropped by PSfile=... (it is + % obviously not an Image XObject, as defined by PDFRef.pdf) + \def\@@tmp@c{1.00}% 100 --\@@divhundred--> 1.00 + \edef\@@tmp@x{\@@divhundred##2}% + \edef\@@tmp@y{\@@divhundred##3}% + \edef\@@tmp@ff{##4}% + \edef\@@tmp@ff{% + \ifx\@@tmp@ff\@@img@MPS 1\else% + \ifx\@@tmp@ff\@@img@EPS 1\else% + \ifx\@@tmp@ff\@@img@PDF 1\else% + \ifx\@@tmp@ff\@empty 1\else% + 0\fi\fi\fi\fi + }% + % vvv need additional scaling for non-MPS, non-EPS, non-PDF images + \if0\@@tmp@ff% not a scalable format (PNG or JPEG) + % stupid dvipdfm 0.13.2b: PNG and JPEG images must be upscaled 100/72 + % Do an equivalent of \special{pdf: bt scale 1.38888888} + \begingroup + \dimen0=\@@tmp@x pt \dimen0=1.3888888\dimen0 % Imp: more accurate?? + \dimen1=\@@tmp@y pt \dimen1=1.3888888\dimen1 % + %\message{##4;}% + \edef\@@tmp@x{\noexpand\def\noexpand\@@tmp@x{\expandafter\@@mkb\the\dimen0}% + \noexpand\def\noexpand\@@tmp@y{\expandafter\@@mkb\the\dimen1}}% + \expandafter\endgroup\@@tmp@x + \def\@@tmp@c{1.0}% 1 --\the--> 1.0pt + \fi% + % vvv define \special{pdf: bt ...} and \special{pdf: et} + \edef\@@tmp@xy{% + \ifx\@@tmp@c\@@tmp@x\else\space xscale \@@tmp@x\fi% + \ifx\@@tmp@c\@@tmp@y\else\space yscale \@@tmp@y\fi% + }% + \ifx\@@tmp@xy\@empty% + \let\@@tmp@xy\@empty + \let\@@tmp@et\@empty + \else + \edef\@@tmp@xy{\noexpand\special{pdf: bt\@@tmp@xy}}% + \def\@@tmp@et{\special{pdf: et}}% + \fi + %\message{[\@@tmp@xy]}% + % + \edef\@@img@cs{@@xi@##1}% remember only the filename, because of the bug + \@@tmp@xy + \expandafter\ifx\csname\@@img@cs\endcsname\relax% + \count0=\@@img@suppCount\relax% + %\message{tc0=\the\count0;\@@img@suppCount}% + \advance\count0 1% + %\edef\@@img@suppCount{\noexpand\def\noexpand\@@img@suppCount{\the\count0}}% + \global\edef\@@img@suppCount{\the\count0}% + \global\expandafter\edef\csname\@@img@cs\endcsname{\@@img@suppCount}% + %\message{alloced(\csname\@@img@cs\endcsname)}% + \if0\@@tmp@ff% not a scalable format (PNG or JPEG) + % vvv crops if bbox.llx is negative + \special{pdf: bxobj @p_i\@@img@suppCount\space width 16383pt height 16383pt depth 16383pt}% + \special{PSfile="##1"}% safely omit \@@img@pdfsq + \special{pdf: exobj}% + \special{pdf: uxobj @p_i\csname\@@img@cs\endcsname}% + \else + %\edef\@@tmp@ff{\expandafter\string\csname\@@img@cs\endcsname}% do the expansion before \@@img@pdfsq + %\chardef\space=0 % + \edef\@@tmp@ff{##1}% must be fully expanded before \@@tmp@ff. Imp: \string + \edef\@@tmp@ff{\expandafter\@@quotespace\expandafter{\@@tmp@ff}}% do the expansion before \@@img@pdfsq + %\def\space{ }% + %\show\@@tmp@ff% + %\message{pdf: image @p_i\@@img@suppCount(\expandafter\@@img@pdfsq\@@tmp@ff\@empty)}% + \special{pdf: image @p_i\@@img@suppCount(\expandafter\@@img@pdfsq\@@tmp@ff\@empty)}% + \fi + \else% + \special{pdf: uxobj @p_i\csname\@@img@cs\endcsname}% + \fi% + \@@tmp@et + %\if0\@@tmp@ff% not a scalable format (PNG or JPEG) + % \special{pdf: et}% + %\fi + }}% +}% </driver dvipdfm> + +\def\@@imgdriver@dvi{% + \@@imgdriver@dvipdfm% + \def\@@img@defext{eps}% + \def\@@img@supported##1{% v0.13.2b + \@@img@supportsit##1{EPS}% + \@@img@supportsit##1{MPS}% + }% + \def\@@img@special##1##2##3##4{{% works for both dvips and dvipdfm + \def\@@tmp@c{100}% + \edef\@@tmp@x{##2}% + \edef\@@tmp@y{##3}% + \edef\@@tmp@ff{##4}% + \special{PSfile="##1"% + \ifx\@@tmp@c\@@tmp@x\else\space hscale=##2\fi% Imp: cmp w/o limits + \ifx\@@tmp@c\@@tmp@y\else\space vscale=##3\fi% Imp: cmp w/o limits + }% + }}% +}% +\def\@@imgdriver@invisible{% + \def\@@img@push@white{}% + \def\@@img@pop{}% + \def\@@img@divword##1##2{{% + \dimen0 ##2 sp% + \edef##1{\expandafter\@@mkb\the\dimen0}% + \@@keepdefaftergroup##1% + }}% + \def\@@img@zeroll{1}% + \def\@@img@defext{eps}% + \def\@@img@supported##1{% + \let##1\@empty% supports all file formats + }% + \def\@@img@special##1##2##3##4{}% works for all dvips, dvipdfm and pdftex :-) +}% +\def\@@imgdriver@blackbox{% + \@@imgdriver@invisible% inherit + \def\@@img@special##1##2##3##4{% works for all dvips, dvipdfm and pdftex :-) + %\vrule width\DW sp height\URY sp depth\DP sp % if not lowered + \vrule width\DW sp height\DH sp % if already lowered + } +}% +\def\@@imgdriver@frame{% + \@@imgdriver@invisible% inherit + \def\@@img@special##1##2##3##4{% works for all dvips, dvipdfm and pdftex :-) + %\vrule width\DW sp height\URY sp depth\DP sp % if not lowered + \hbox to0sp{\vrule height\@@img@framewidth width\DW sp\hss}% bottom + \raise\DH sp\hbox to0sp{\vrule height0sp depth\@@img@framewidth width\DW sp\hss}% top + \hbox to\DW sp{% + \vrule height\DH sp width\@@img@framewidth \hss% left + \vrule height\DH sp width\@@img@framewidth% right + }% + %\vrule width\DW sp height\DH sp % if already lowered + } +}% +\def\@@imgdriver@namedframe{% + \@@imgdriver@invisible% inherit + \def\@@img@special##1##2##3##4{% works for all dvips, dvipdfm and pdftex :-) + %\vrule width\DW sp height\URY sp depth\DP sp % if not lowered + \hbox to0sp{\vrule height\@@img@framewidth width\DW sp\hss}% bottom + \raise\DH sp\hbox to0sp{\vrule height0sp depth\@@img@framewidth width\DW sp\hss}% top + \hbox to\DW sp{% + \vrule height\DH sp width\@@img@framewidth \hss% left + \vrule height\DH sp width\@@img@framewidth% right + }% + \kern-\DW sp% + % vvv Imp: use \textascii to typeset \textbar etc. in the filename + \setbox0=\hbox{\@@img@framefont\raise1ex\hbox{\expandafter\expandafter\expandafter\@gobble\expandafter\string\csname##1\endcsname}}% + \wd0=0sp \ht0=0sp \dp0=0sp \copy0% + %\vrule width\DW sp height\DH sp % if already lowered + } +}% +\def\@@img@framewidth{.4pt}% used by the frameonly and namedframe drivers +\def\@@img@framefont{\ttfamily\space}% Dat: \space: don't overwrite the frame + +\def\@@imgdriver@pdftex{% + \expandafter\ifx\csname graphicPnopdftexmpost\endcsname\relax% + % Don't load \convertMPtoPDF support in ConTeXt supp-pdf.tex if + % \usepackage[nopdftexmpost]{graphicP} was specified, because supp-pdf + % uses plenty of TeX resources. + \edef\@tempa{% Imp: allow user not load this + \catcode`\noexpand\!\the\catcode`\! + \catcode`\noexpand\@\the\catcode`\@ + \catcode`\noexpand\?\the\catcode`\? + \catcode`\noexpand\`\the\catcode`\` + \catcode`\noexpand\"\the\catcode`\" + }% + % Dat: \unprotect is the macro that fails without \catcode96=12 + \catcode96=12% ` is active in Babel magyar.ldf; does many harm on supp-pdf + \catcode34=12% " is active in Babel germanb.ldf; no harm on supp-pdf, but play it safe + \LaemuInputQuiet{supp-pdf}% + \@tempa% + \fi% + \@@imgdriver@@pdftexlow + % ^^^ must be a separate macro, otherwise supp-pdf won't load (limit exceeded) +}% + +\def\@@imgdriver@@pdftexlow{% + \def\@@img@MPS{MPS}% helper for \ifx + \expandafter\ifx\csname convertMPtoPDF\endcsname\relax% + \def\@@img@suppMPS##1{}% + \else + \def\@@img@suppMPS##1{% + \ifx##1\@@img@MPS% + \def\@@img@zeroll{1}% \convertMPtoPDF assumes it, overrides when \pdftexversion<13 + \let##1\@empty% + \fi% + }% + \fi + \def\@@img@supported##1{% + \@@img@supportsit##1{PDF}% + \@@img@supportsit##1{PNG}% + \@@img@supportsit##1{TIFF}% + \@@img@supportsit##1{JPEG}% + \@@img@suppMPS##1% + }% + \def\@@img@zeroll{1}% + \def\@@img@defext{pdf}% + % Imp: implement a real color _stack_ + \def\@@img@@curcolor{0 g}% Dat: pdftex.def sets `0 g 0 G' + \def\@@img@push@white{\pdfliteral {1 g}}% + \def\@@img@pop{\pdfliteral {\@@img@@curcolor}}% + \def\@@img@divword##1##2{{% + \dimen0 ##2 sp% + \edef##1{\expandafter\@@mkb\the\dimen0}% + \@@keepdefaftergroup##1% + }}% + %\def\@@img@tobp##1##2{{% + % \dimen0 ##2 sp% + % \dimen0 0.996264\dimen0% pt -> bp + % \edef##1{\expandafter\@@mkb\the\dimen0}% + % \@@keepdefaftergroup##1% + %}}% + \def\@@img@kv##1##2{##1=##2}% + \def\@@img@special##1##2##3##4{{% + \def\@@tmp@c{1.00}% + \edef\@@tmp@x{\@@divhundred##2}% + \edef\@@tmp@y{\@@divhundred##3}% + \edef\@@tmp@ff{##4}% + %\message{\@@tmp@x*\@@tmp@y}% + \ifx\@@tmp@ff\@@img@MPS% + %\errmessage{embedding MetaPost to PDF}% + % vvv Use ConTeXt supp-pdf.tex + \convertMPtoPDF{##1}{\@@tmp@x}{\@@tmp@y}% Dat: fine, does --below margins right + \else% + \pdfliteral{ q \@@tmp@x\space 0 0 \@@tmp@y\space 0 0 cm}% + \hbox to0sp{% + \@@pdfimagecompat{}{##1}% + \hss}% + %\pdfliteral direct{q h 0 0 m 0 1 l h W* Q}% SUXX: cannot set clipping path :-( + \pdfliteral{ Q}% + \fi% + %\special{PSfile="##1"% + % \ifx\@@tmp@c\@@tmp@x\else\space hscale=##2\fi% Imp: cmp w/o limits + % \ifx\@@tmp@c\@@tmp@y\else\space vscale=##3\fi% Imp: cmp w/o limits + %}% + }}% + % + % This is how pdftex.def detects pdftex version: + %\ifx\pdftexversion\@undefined + % \def\@@pdftex@release{1}% + %\else + % \ifnum\pdftexversion<12 + % \def\@@pdftex@release{2}% + % \else + % \ifnum\pdftexversion<13 + % \ifnum \expandafter `\pdftexrevision < `n + % \def\@@pdftex@release{3}% + % \else + % \def\@@pdftex@release{4}% + % \fi + % \else + % \ifnum\pdftexversion=13 + % \def\@@pdftex@release{5}% + % \else + % \ifnum\pdftexversion=14 + % \def\@@pdftex@release{6}% + % \else + % \def\@@pdftex@release{7}% + % \fi + % \fi + % \fi + % \fi + %\fi + % + %\ifnum\pdftexversion<13% older, Debian Slink + %\else\ifnum\pdftexversion<15% newer, SuSE 6.2 and Debian Potato + %\else\ifnum\pdftexversion>99% newest, Debian Woody + % + % vvv before Sun Feb 9 20:06:01 CET 2003 + %\ifnum\pdftexversion<13% older, Debian Slink + % \def\@@img@zeroll{0}% + % \def\@@pdfimagecompat##1##2{\pdfimage##1\noexpand\noexpand\noexpand\@empty ##2 \relax}% + % % Note the magic in front of the file name after \pdfimage, to + % % prevent it fouling up with file names starting with "depth". + %\else% + % \ifnum\pdftexversion<15% newer, SuSE 6.2 and Debian Potato + % \def\@@pdfimagecompat##1##2{\pdfimage##1 {##2}}% + % \else% newest, Debian Woody + % \def\@@pdfimagecompat##1##2{% + % \edef\@@img@cs{@@xi@##2}% remember only the filename, because of the bug + % \expandafter\ifx\csname\@@img@cs\endcsname\relax% + % \immediate\pdfximage##1{##2}% Dat: \immediate\pdfteximage solved a bug in pdftex_bug.tex + % \global\expandafter\edef\csname\@@img@cs\endcsname{\the\pdflastximage}% + % \fi% + % %\expandafter\expandafter\expandafter\pdfrefximage% + % \expandafter\pdfrefximage\csname\@@img@cs\endcsname% + % }% + % \fi% + %\fi% + % I have evaluated the use of \pdfxform / \pdfform instead of \pdfximage + % on older pdfTeXes (Debian Slink), and I got terrible results. pdfTeX + % insists on cropping the image to the size of the \hbox, and there are + % also other strange, excess cropping effects (especially on + % f2mletter.pdf), so I gave up and reverted to \pdfimage. Currently I + % don't know of any solution that uses \pdfxform, and doesn't embed the + % same image multiple times. + \expandafter\ifx\csname pdfximage\endcsname\relax + \expandafter\ifx\csname pdfimage\endcsname\relax + \@@img@warnerr0{Need either \string\pdfximage or \string\pdfimage.}\@ehc + \fi + \ifnum\pdftexversion<13% older, Debian Slink + \def\@@img@zeroll{0}% + \def\@@pdfimagecompat##1##2{\pdfimage##1\noexpand\noexpand\noexpand\@empty ##2 \relax}% + \else + \def\@@pdfimagecompat##1##2{\pdfimage##1 {##2}}% + \fi + \else + %** param ##1 attrs "width ... height ... depth ..." + %** param ##2 expands to filename + \def\@@pdfimagecompat##1##2{% + % pdfTeX, Version 3.14159-1.00a-pretest-20011114-ojmw (Web2C 7.3.7) + % has a bug that prevents including the same image with different + % /XObject numbers. (Actually, \immediate\pdfximage also solves the + % problem. + % So we cache /XObject numbers already allocated. + % Caching is a good idea anyway, so the output PDF file will be + % smaller. + \edef\@@img@cs{@@xi@##2}% remember only the filename, because of the bug + \expandafter\ifx\csname\@@img@cs\endcsname\relax% + \immediate\pdfximage##1{##2}% Dat: \immediate\pdfteximage solved a bug in pdftex_bug.tex + \global\expandafter\edef\csname\@@img@cs\endcsname{\the\pdflastximage}% + \fi% + %\expandafter\expandafter\expandafter\pdfrefximage% + \expandafter\pdfrefximage\csname\@@img@cs\endcsname% + }% + \fi +}% </driver pdftex> + +% ---- main PutImage code + +\expandafter\ifx\csname @@img@forceunknown\endcsname\relax + %** What to do if the FileFormat is unknown/unsupported by the driver? + %** 0: PackageError, skip + %** 1: PackageWarning, skip + %** 2: PackageWarning, include the image + \def\@@img@forceunknown{0}% \let and \chardef are not good (both \if and \ifnum) +\fi + +%** @param #1 error if 0; warning otherwise +\def\@@img@warnerr#1#2#3{% + \if0#1% + \PackageError{pts_img}{#2}{#3}% + \else + \PackageWarning{pts_img}{#2}% + \fi +}% + +%** @param #1..#4 \count register spec +%** @param #5..#8 dimensions +\def\@@img@letbbox#1#2#3#4#5#6#7#8{% + \@@letdimcountany{#1}{#5}{bp}% + \@@letdimcountany{#2}{#6}{bp}% + \@@letdimcountany{#3}{#7}{bp}% + \@@letdimcountany{#4}{#8}{bp}% +}% + +%\def\@@gobblecomma#1,#2\end{}% +\def\@@img@minus{-}% + +%** Puts a \hbox containing the specified image. Doesn't open the image file. +%** New arguments may be added in subsequent versions +%** @param #1 dimension (in image pixels or image bp) to raise above the +%** baseline. May contain a double minus sign. Default metric unit is `bp'. +%** If omitted, then negative bbox.lly will be converted to a lowering. +%** @param #2 empty or overrides \@@img@forceunknown +%** @param #3 ignored +%** @param #4 {llx}{lly}{urx}{ury} +%** @param #5 desired width, or 0pt +%** @param #6 desired height+depth, or 0pt +%** @param #7 0 if noclip, 1 if clip [ignored] +%** @param #8 filename +%** @param #9 FileFormat +\def\@@PutImage#1#2#3#4#5#6#7#8#9{% + \ifx\@@img@driver\@empty% + \@@img@setdriver{}% guess a resonable default + \fi% + {% + \def\@tempa{#2}% + \ifx\@tempa\@empty\else \edef\@@img@forceunknown{#2}\fi% + \countdef\LLX1 \countdef\LLY2 \countdef\URX3 \countdef\URY4 % + \@@img@letbbox\LLX\LLY\URX\URY#4% + %\countdef\LLX1 \@@letdimcount\LLX{#1}% old default: sp + \countdef\DW 5 \@@letdimcount\DW {#5}% + \countdef\DH 6 \@@letdimcount\DH {#6}% + \countdef\WD 7 \WD\URX \advance\WD-\LLX% + % Imp: check for \ifnum\WD<0, the same for height + \countdef\UP 8 \UP0% + \edef\@tempa{#1}% + \ifx\@tempa\@@img@minus \let\@tempa\@empty\fi + \ifx\@tempa\@empty% calculate lowering from the image + \ifnum0<\LLY \UP-\LLY \advance\URY-\LLY \LLY0 \fi + % ^^^ Dat: LLY<0 and LLY>=0 are treated quite differently + % ^^^ -\LLY BUGFIX at Sun Feb 9 21:50:23 CET 2003 + \else + \UP-\LLY \advance\URY-\LLY % + \@@letdimcountany\LLY{#1}{bp}% + \advance\URY\LLY% + \advance\UP\LLY% + \fi + \countdef\DP 9 \DP-\LLY% + \countdef\MLX10 \MLX-\LLX% + \countdef\TC 11% temporary count register + \countdef\TH 12 \TH\URY \advance\TH\DP% total height+depth + \countdef\SW 13 % width scale facter + \countdef\SH 14 % height scale factor + % Now: LLY=-depth URY=height + \def\DOhscale{100}% horizontal scale + \def\DOvscale{100}% vertical scale + \ifnum0>\DW + \PackageError{pts_img}{Desired width must be positive}\@ehc + \DW0% + \fi% + \ifnum0>\DH + \PackageError{pts_img}{Desired height must be positive}\@ehc + \DH0% + \fi% + \ifnum\DH>0% + \@@muldivletposdim\SH{100pt}\DH\TH% + \ifnum\DW>0% both \DW and \DH are given + \@@muldivletposdim\SW{100pt}\DW\WD% + %\message{100pt*\the\DH/\the\TH=\the\SH;100pt*\the\DW/\the\WD:\the\SW}% + % ^^^ 100*5594039/1973452=18577140;100*3729359/1315635:18577134 + % I've verified that \@@muldivletposdim works accurately, but the input + % values are inaccurate! + \@@muldivletposdim\MLX\MLX\DW\WD% + \else% \DH given, calculate \DW from it + \@@muldivletposdim\DW\DH\WD\TH% + % if initially DW==0: TC:=(DH*WD/TH)/WD; should be: TC:=DH/TH + \SW\SH% + \@@muldivletposdim\MLX\MLX\DH\TH% + \fi% + \@@muldivletposdim\UP\UP\DH\TH% + \ifnum\DP=0% \DP=0 <=> \URY=\TH + \URY=\DH% + \else% + \@@muldivletposdim\URY\URY\DH\TH% + \@@muldivletposdim\DP\DP\DH\TH% + \fi% + \else% + \ifnum\DW>0% \DW given, calculate \DH from it + \@@muldivletposdim\SW{100pt}\DW\WD% + \SH\SW% + \@@muldivletposdim\DH\TH\DW\WD% + \@@muldivletposdim\UP\UP\DW\WD% + \ifnum\DP=0% \DP=0 <=> \URY=\TH + \URY=\DW% + \else% + \@@muldivletposdim\URY\URY\DW\WD% + \@@muldivletposdim\DP\DP\DW\WD% + \fi% + \@@muldivletposdim\MLX\MLX\DH\TH% + \else% \DW and \DH are not given + \DW=\WD \DH=\TH% + \fi% + \fi% + % + \ifnum\DW=\WD\else% vvv scale width + \@@img@divword\DOhscale{\the\SW}% + %\edef\DOhscale{\@@img@kv{hscale}{\DOhscale} }% + \fi% + \ifnum\DH=\TH\else% vvv scale height + \@@img@divword\DOvscale{\the\SH}% + %\edef\DOvscale{\@@img@kv{vscale}{\DOvscale} }% + \fi% + % Dat: we replace `@beginspecial @hoffset' with \raise...\hbox{\kern...}', + % because dvipdfm version 0.13.2b ignores @hoffset and @voffset + %\ifnum\MLX=0\else% + % %\@@img@div\TMP{\the\MLX}{65781.76}% Dat: 65781.76 == 65536/72*72.27 + % % Dat: dvipdfm doesn't support @hoffset + %\fi% + %\ifnum\UP=0\else% Imp: create test case + %\fi% + % + % vvv aid `dvips -E' bbox calculation + \@@spbox{\DW sp}{\URY sp}{\DP sp}% + % vvv Dat: \special{PSfile=...} calculates bbox incorrectly with + % dvips 5.86e, and xdvi the bbox even if it shouldn't. So I decided to + % use \special{ps: plotfile}, which is understood by both dvips and + % xdvi. + % ^^^ is this still true? (test it!) (how is a bbox calculated) + \edef\@@img@ff{#9}% FileFormat + \@@img@supported\@@img@ff% driver sets it to empty if supported + %\message{ffsupp=(\@@img@ff)}% + \ifx\@@img@ff\@empty\else% + % Only a warning, because further implementations may support it in fact. + %\message{\@@img@forceunknown!}% + \@@img@warnerr\@@img@forceunknown{Unsupported FileFormat `#9' for driver `\@@img@driver'\MessageBreak in image file `#8'}\@ehc% + \expandafter\ifnum\@@img@forceunknown>1 \let\@@img@ff\@empty\fi + \fi% + \ifx\@@img@ff\@empty% include the image only if FileFormat is known + %\edef\@@img@ff{#9}% + \ifnum\@@img@zeroll=1 % + \vrule width0pt % leave vertical mode + \lower\DP sp\hbox to0pt{\@@img@special{#8}\DOhscale\DOvscale{#9}\hss}% + \else% + %\message{#8:::\the\UP;;; }% + \setbox1=\hbox{\raise\UP sp\hbox to0pt{\kern\MLX sp + \@@img@special{#8}\DOhscale\DOvscale{#9}% + \hss}}% + \dp1=0sp \ht1=0sp \copy1% TeX overestimates box size because of \raise + \fi% + \fi + % vvv Really put the \hbox there + \hbox to\DW sp{\vrule width0sp height\URY sp depth\DP sp\hss}% +}}% + +%\@@imgdriver@pdftex |