summaryrefslogtreecommitdiff
path: root/macros/latex/exptl/graphicp
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/exptl/graphicp
Initial commit
Diffstat (limited to 'macros/latex/exptl/graphicp')
-rw-r--r--macros/latex/exptl/graphicp/descend.123
-rw-r--r--macros/latex/exptl/graphicp/descend.mp34
-rw-r--r--macros/latex/exptl/graphicp/div16b.sty490
-rwxr-xr-xmacros/latex/exptl/graphicp/epstopdf476
-rw-r--r--macros/latex/exptl/graphicp/f2cletter.eps35
-rw-r--r--macros/latex/exptl/graphicp/f2cletter.pdfbin0 -> 934 bytes
-rw-r--r--macros/latex/exptl/graphicp/f2mletter.eps23
-rw-r--r--macros/latex/exptl/graphicp/f2mletter.pdfbin0 -> 582 bytes
-rw-r--r--macros/latex/exptl/graphicp/ficletter.jpgbin0 -> 590 bytes
-rw-r--r--macros/latex/exptl/graphicp/ficletter.pbmbin0 -> 116 bytes
-rw-r--r--macros/latex/exptl/graphicp/ficletter.pngbin0 -> 199 bytes
-rw-r--r--macros/latex/exptl/graphicp/files22
-rw-r--r--macros/latex/exptl/graphicp/graphicp.sty407
-rw-r--r--macros/latex/exptl/graphicp/graphicpdoc.pdfbin0 -> 86972 bytes
-rw-r--r--macros/latex/exptl/graphicp/graphicpdoc.tex146
-rwxr-xr-xmacros/latex/exptl/graphicp/img_bbox.pl2079
-rw-r--r--macros/latex/exptl/graphicp/keyvalx.sty76
-rw-r--r--macros/latex/exptl/graphicp/laemu.sty206
-rw-r--r--macros/latex/exptl/graphicp/laltest.tex166
-rw-r--r--macros/latex/exptl/graphicp/laxtest.bbx18
-rwxr-xr-xmacros/latex/exptl/graphicp/pdfboxes.pl863
-rw-r--r--macros/latex/exptl/graphicp/pts_bbox.sty418
-rw-r--r--macros/latex/exptl/graphicp/pts_img.sty801
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
new file mode 100644
index 0000000000..267f853dfa
--- /dev/null
+++ b/macros/latex/exptl/graphicp/f2cletter.pdf
Binary files differ
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
new file mode 100644
index 0000000000..4a78a6c166
--- /dev/null
+++ b/macros/latex/exptl/graphicp/f2mletter.pdf
Binary files differ
diff --git a/macros/latex/exptl/graphicp/ficletter.jpg b/macros/latex/exptl/graphicp/ficletter.jpg
new file mode 100644
index 0000000000..958f35809d
--- /dev/null
+++ b/macros/latex/exptl/graphicp/ficletter.jpg
Binary files differ
diff --git a/macros/latex/exptl/graphicp/ficletter.pbm b/macros/latex/exptl/graphicp/ficletter.pbm
new file mode 100644
index 0000000000..13db3eddff
--- /dev/null
+++ b/macros/latex/exptl/graphicp/ficletter.pbm
Binary files differ
diff --git a/macros/latex/exptl/graphicp/ficletter.png b/macros/latex/exptl/graphicp/ficletter.png
new file mode 100644
index 0000000000..6a803b1c91
--- /dev/null
+++ b/macros/latex/exptl/graphicp/ficletter.png
Binary files differ
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
new file mode 100644
index 0000000000..944635ed93
--- /dev/null
+++ b/macros/latex/exptl/graphicp/graphicpdoc.pdf
Binary files differ
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