Created
July 19, 2015 07:35
-
-
Save zr-tex8r/d0e59ad020c85a99f75a to your computer and use it in GitHub Desktop.
LaTeX: to make 'pagebox' option key of \includegraphics available with dvipdfmx/xetex drivers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% tcpagebox.sty | |
% | |
%% Prologue | |
\ifx\tcizIntr\undefined \let\tcizISkip\relax | |
\else \long\def\tcizISkip#1\tcizISkip{} | |
\fi \tcizISkip | |
% When loaded with \usepackage, start from here. | |
%% package declaration | |
\NeedsTeXFormat{LaTeX2e} | |
\ProvidesPackage{tcpagebox}[2015/07/19 v0.2] | |
%% preparations | |
\def\tciz@pkgname{tcpagebox} | |
\def\tciz@error{\PackageError\tciz@pkgname} | |
\def\tciz@warn{\PackageWarning\tciz@pkgname} | |
\providecommand\bxDebug[1]{} | |
%% prerequisite packages | |
\RequirePackage{etoolbox} | |
\RequirePackage{pdftexcmds} | |
%--------------------------------------- settings | |
%% \tciz@temp@base | |
% The base-name of the temporary MetaPost source file. | |
\edef\tciz@temp@base{\jobname-bb} | |
%% \tciz@cmd@mpost | |
% The name of MetaPost command. | |
\def\tciz@cmd@mpost{mpost} | |
%% \tciz@cmd@pdftex | |
\def\tciz@cmd@pdftex{pdftex} | |
%% \iftciz@clean | |
% Is clean-up needed? | |
\newbool{tciz@clean} | |
%% options | |
\DeclareOption{clean}{% | |
\tciz@cleantrue | |
} | |
\DeclareOption{noclean}{% | |
\tciz@cleanfalse | |
} | |
\ExecuteOptions{clean} | |
\ProcessOptions*\relax | |
%--------------------------------------- environment check | |
% e-TeX cehck | |
\ifx\patchcmd\@undefined | |
\expandafter\endinput\fi\relax | |
%% \tciz@driver | |
\let\tciz@driver\relax | |
%% detect graphics driver | |
\@ifpackageloaded{graphicx}{% | |
\ifnum\pdf@strcmp{\Gin@driver}{dvipdfmx.def}=\z@ | |
\def\tciz@driver{dvipdfmx}% | |
\else\ifnum\pdf@strcmp{\Gin@driver}{xetex.def}=\z@ | |
\def\tciz@driver{xetex}% | |
\else | |
\tciz@warn{Unsupported graphics driver '\Gin@driver' is used,\MessageBreak | |
package loading aborted}% | |
\fi\fi | |
}{%else | |
\tciz@error{Package 'graphicx' is not yet loaded}{% | |
The '\tciz@pkgname' package must be loaded after 'graphicx' | |
package.\MessageBreak\@ehc}% | |
} | |
%% check if pagebox is seemingly already supported | |
\ifnum 0\ifdefined\Gin@pagebox 1\fi | |
\ifdefined\Gin@XeTeX@pagebox 1\fi | |
\ifdefined\GTP@pagebox 1\fi >\z@ | |
\let\Gin@driver\relax | |
\fi | |
%% aobrt if wrong | |
\ifx\tciz@driver\relax | |
\expandafter\endinput\fi\relax | |
%--------------------------------------- helpers | |
%% variables | |
\newbool{tciz@ok} | |
\csuse{newwrite}\tciz@out | |
\newbool{tciz@cmd@ok} | |
%% unique tokens | |
\def\tciz@end{\tciz@end@} | |
\def\tciz@mt{\tciz@mt@} | |
\let\tciz@stop\relax | |
%% \tciz@PC: the string '%' | |
%% \tciz@BS: the string '\' | |
\begingroup \escapechar\m@ne | |
\xdef\tciz@PC{\string\%} | |
\xdef\tciz@BS{\string\\} | |
\endgroup | |
%% \if\tciz@eq{<str1>}{<str2>}...\fi | |
\def\tciz@eq#1#2{% | |
\ifnum\pdf@strcmp{#1}{#2}=\z@ T\else F\fi T% | |
} | |
%% tciz@avail@shell | |
% shell escape availablity | |
\let\tciz@avail@shell\m@ne | |
\ifdefined\pdf@shellescape | |
\chardef\tciz@avail@shell=\pdf@shellescape\relax | |
\fi | |
\begingroup | |
\ifnum\tciz@avail@shell=\z@ | |
\if\tciz@eq{\tciz@driver}{dvipdfmx}% | |
\tciz@error{Shell escape is entirely disabled}% | |
{Package loading is aborted.\MessageBreak\@ehc}% | |
\aftergroup\endinput | |
\fi | |
\fi | |
\endgroup | |
%% \tciz@drop@dot | |
% (fully-expandable) | |
\def\tciz@drop@dot#1{% | |
\expandafter\tciz@drop@dot@a#1\tciz@end#1% | |
} | |
\def\tciz@drop@dot@a#1#2\tciz@end#3{\def#3{#2}} | |
%% \tciz@write@to@file{<filename>}{<content>} | |
\def\tciz@write@to@file#1#2{% | |
\begingroup | |
\catcode10=12 \newlinechar=10 | |
\let\%\tciz@PC \let\\\tciz@BS | |
\def\n{^^J}\let\ \@space | |
\immediate\openout\tciz@out=#1\relax | |
\immediate\write\tciz@out{#2}% | |
\immediate\closeout\tciz@out | |
\endgroup | |
} | |
%% \tciz@empty@mark : empty-file marker | |
\edef\tciz@empty@mark{\string\empty} | |
%% \tciz@if@file@empty{<filename>}{<true>}{<false>} | |
\def\tciz@if@file@empty#1{% | |
\openin\@inputcheck#1\relax | |
\ifeof\@inputcheck | |
\global\let\@gtempa\@firstoftwo | |
\else | |
\begingroup \endlinechar\m@ne | |
\readline\@inputcheck to\tciz@tmpa | |
\if\tciz@eq{\tciz@tmpa}{\tciz@empty@mark}% | |
\global\let\@gtempa\@firstoftwo | |
\else | |
\global\let\@gtempa\@secondoftwo | |
\fi | |
\endgroup | |
\fi | |
\@gtempa | |
} | |
%% \tciz@clobber@file{<filename>} | |
\def\tciz@clobber@file#1{% | |
\tciz@write@to@file{#1}{\tciz@empty@mark}% | |
} | |
%--------------------------------------- graphics parameters | |
%% \tciz@base | |
\let\tciz@base\relax | |
%% \tciz@ext | |
\let\tciz@ext\relax | |
%% \tciz@page | |
\let\tciz@page\@empty | |
%% \tciz@pagebox | |
\let\tciz@pagebox\@empty | |
%% \tciz@set@imgfile{<file>} | |
% Sets \tciz@base and \tciz@ext. | |
\def\tciz@set@imgfile#1{% | |
\edef\tciz@tmpa{#1}% | |
\IfFileExists\tciz@tmpa{% | |
\filename@parse\tciz@tmpa | |
\edef\tciz@base{\filename@area\filename@base}% | |
\edef\tciz@ext{\filename@ext}% | |
}{%else | |
\tciz@error{File '\tciz@tmpa' not found}\@ehc | |
\tciz@okfalse | |
}% | |
} | |
%% \tciz@set@imgfileext{<base>}{.<ext>} | |
% Sets \tciz@base and \tciz@exr. | |
\def\tciz@set@imgfileext#1#2{% | |
\IfFileExists{#1#2}{% | |
\edef\tciz@base{#1}% | |
\edef\tciz@ext{#2}\tciz@drop@dot\tciz@ext% | |
}{%else | |
\tciz@error{File '#1#2' not found}\@ehc | |
\tciz@okfalse | |
}% | |
} | |
%% \tciz@set@page{<page>} | |
% Sets \tciz@page. | |
\def\tciz@set@page#1{% | |
\unless\if\tciz@eq{#1}{}% | |
\afterassignment\tciz@set@page@a\count@=#1\tciz@stop{#1}% | |
\fi | |
} | |
\def\tciz@set@page@a#1\tciz@stop#2{% | |
\ifx\tciz@mt#1\tciz@mt | |
\edef\tciz@page{\the\count@}% | |
\else | |
\tciz@error{Invalid number format (#2)}\@ehc | |
\fi | |
} | |
%% \tciz@set@pagebox{<box-spec>} | |
% Sets to \tciz@pagebox. | |
\def\tciz@set@pagebox#1{% | |
\unless\if\tciz@eq{#1}{}% | |
\ifcsundef{tciz@box/#1}{% | |
\tciz@error{Invalid pagebox value (#1)}\@ehc | |
}{%else | |
\edef\tciz@pagebox{#1}% | |
}% | |
\fi | |
} | |
\@for\tciz@x:={media,crop,bleed,trim,art}\do{% | |
\csedef{tciz@box/\tciz@x box}{\tciz@x}% | |
} | |
%--------------------------------------- oatch to graphics driver | |
\if\tciz@eq{\tciz@driver}{dvipdfmx}% | |
%% \tciz@bbox : the result | |
\let\tciz@bbox\relax | |
%% tciz@g@clean | |
\chardef\tciz@g@clean=0 | |
%% add Gin parameters | |
\AtBeginDocument{% | |
\tciz@oktrue | |
% 'page' may or may not exist | |
\unless\ifdefined\KV@Gin@page | |
\define@key{Gin}{page}{}% | |
\fi | |
%NB. \patchcmd fails to do with '#1' in replacement... | |
\let\tciz@KV@page\KV@Gin@page | |
\def\KV@Gin@page#1{% | |
\tciz@set@page{#1}% added | |
\tciz@KV@page{#1}}% | |
% 'pagebox' must not exist | |
\ifdefined\KV@Gin@pagebox | |
\Gin@ok@false | |
\else | |
\define@key{Gin}{pagebox}{% | |
\tciz@set@pagebox{#1}}% | |
\fi | |
\unless\iftciz@ok | |
\PackageError{Patch to graphics driver has failed}\@ehc | |
\fi | |
} | |
%% rewrite \Gread@pdf | |
\let\tciz@Gread@pdf\Gread@pdf | |
\def\Gread@pdf#1{% | |
\if\tciz@eq{\tciz@pagebox}{}% | |
\tciz@Gread@pdf{#1}% do original | |
\else | |
\begingroup | |
\edef\tciz@base{\Gin@base}% | |
\edef\tciz@ext{\Gin@ext}% | |
\let\tciz@bbox\relax | |
\tciz@measure@pagebox | |
\ifx\tciz@bbox\relax | |
\tciz@error{Cannot determine size of image (no BoundingBox)}% | |
\@ehc | |
\gdef\@gtempa{0 0 72 72 }% | |
\else | |
\xdef\@gtempa{\tciz@bbox\space}% | |
\fi | |
\endgroup | |
\expandafter\Gread@parse@bb\@gtempa\\% | |
\fi | |
} | |
%% \tcizIntrResult{<text>} | |
% The result handler. | |
\def\tcizIntrResult#1{% | |
\def\tciz@bbox{#1}% | |
} | |
%% \tciz@measure@pagebox@mpost | |
\def\tciz@measure@pagebox@mpost{% | |
\tciz@write@to@file{\tciz@temp@base.tex}{% | |
\% \tciz@temp@base.mp\n | |
verbatimtex\n | |
\%&pdftex -translate-file=natural\n | |
\\let\\tcizIntr=t \\input \tciz@pkgname.sty\\relax\n | |
\\tcizIntrMPProcess{\tciz@base\tciz@ext}% | |
{\tciz@page}{\tciz@pagebox}{\tciz@temp@base.aux}\n | |
etex\n | |
label(btex \\relax etex, (0, 0));\n | |
bye}% | |
\tciz@exec@sub{\tciz@cmd@mpost}{2}% | |
} | |
%% \tciz@measure@pagebox@pdftex | |
\def\tciz@measure@pagebox@pdftex{% | |
\tciz@write@to@file{\tciz@temp@base.tex}{% | |
\% \tciz@temp@base.tex\n | |
\\let\\tcizIntr=t \\input \tciz@pkgname.sty\\relax\n | |
\\tcizIntrProcess{\tciz@base\tciz@ext}% | |
{\tciz@page}{\tciz@pagebox}{\tciz@temp@base.aux}\n | |
\\bye}% | |
\tciz@exec@sub{\tciz@cmd@pdftex}{1}% | |
} | |
%% \tciz@exec@sub{<command>}{<clear>} | |
\def\tciz@exec@sub#1#2{% | |
\tciz@clobber@file{\tciz@temp@base.log}% | |
\tciz@clobber@file{\tciz@temp@base.aux}% | |
\pdf@system{#1 \tciz@temp@base.tex}% | |
\tciz@if@file@empty{\tciz@temp@base.log}{% not executed | |
\tciz@cmd@okfalse | |
}{%else | |
\tciz@cmd@oktrue | |
\global\chardef\tciz@g@clean=#2\relax | |
\input{\tciz@temp@base.aux}% | |
}% | |
} | |
%% \tciz@measure@pagebox@disabled | |
\def\tciz@measure@pagebox@disabled{% | |
\tciz@warn{Process feiled, perhaps because shell is\MessageBreak | |
disabled}% | |
} | |
%% \tciz@measure@pagebox@trial | |
\def\tciz@measure@pagebox@trial{% | |
\tciz@measure@pagebox@pdftex | |
\iftciz@cmd@ok | |
\tciz@resolve@proc\tciz@measure@pagebox@pdftex | |
\else | |
\tciz@measure@pagebox@mpost | |
\iftciz@cmd@ok | |
\tciz@resolve@proc\tciz@measure@pagebox@mpost | |
\else | |
\tciz@measure@pagebox@disabled | |
\tciz@resolve@proc\tciz@measure@pagebox@disabled | |
\fi | |
\fi | |
} | |
%% \tciz@resolve@proc | |
\def\tciz@resolve@proc#1{% | |
\global\let\tciz@measure@pagebox=#1\relax | |
\global\undef\tciz@measure@pagebox@disabled | |
\global\undef\tciz@measure@pagebox@pdftex | |
\global\undef\tciz@measure@pagebox@mpost | |
\global\undef\tciz@measure@pagebox@trial | |
\global\undef\tciz@resolve@proc | |
} | |
\ifcase\tciz@avail@shell | |
\tciz@resolve@proc\tciz@measure@pagebox@disabled | |
\or \tciz@resolve@proc\tciz@measure@pagebox@pdftex | |
\or \tciz@resolve@proc\tciz@measure@pagebox@mpost | |
\else \let\tciz@measure@pagebox\tciz@measure@pagebox@trial | |
\fi | |
%% clean-up | |
\iftciz@clean | |
\AtEndDocument{% | |
\ifcase\tciz@g@clean | |
\relax % nothing to do | |
\or % 'pdftex' is done | |
\tciz@write@to@file{\tciz@temp@base.lua}{% | |
os.remove([=[\tciz@temp@base.tex]=])\n | |
os.remove([=[\tciz@temp@base.aux]=])\n | |
os.remove([=[\tciz@temp@base.log]=])\n | |
os.remove([=[\tciz@temp@base.pdf]=])\n | |
os.remove([=[\tciz@temp@base.lua]=])\n | |
}% | |
\pdf@system{texlua \tciz@temp@base.lua}% | |
\or % 'mpost' is done | |
% shell is restricted, so files cannot be removed | |
\tciz@clobber@file{\tciz@temp@base.tex}% | |
\tciz@clobber@file{\tciz@temp@base.aux}% | |
\tciz@clobber@file{\tciz@temp@base.log}% | |
\tciz@clobber@file{\tciz@temp@base.mpx}% | |
\fi | |
} | |
\fi | |
\fi | |
%--------------------------------------- oatch to graphics driver (Xetex) | |
\if\tciz@eq{\tciz@driver}{xetex}% | |
%% add Gin parameters | |
\AtBeginDocument{% | |
\tciz@oktrue | |
% 'page' must exist | |
\ifdefined\KV@Gin@page | |
\let\tciz@KV@page\KV@Gin@page | |
\def\KV@Gin@page#1{% | |
\tciz@set@page{#1}% added | |
\tciz@KV@page{#1}}% | |
\else | |
\tciz@okfalse | |
\fi | |
% 'pagebox' must not exist | |
\ifdefined\KV@Gin@pagebox | |
\Gin@ok@false | |
\else | |
\define@key{Gin}{pagebox}{% | |
\tciz@set@pagebox{#1}}% | |
\fi | |
% \Ginclude@ for pdf | |
\@gobble\if \@gobble\if | |
\patchcmd{\Ginclude@QTm}{% | |
{ page\Gin@XeTeX@page}\fi | |
}{% | |
{ page\Gin@XeTeX@page}\fi | |
\tciz@pagebox@info | |
}{}{\tciz@okfalse}% | |
% \Gread@ for pdf | |
\@gobble\if \@gobble\if | |
\patchcmd{\G@measure@QTm}{% | |
{ page\Gin@XeTeX@page}\fi | |
}{% | |
{ page\Gin@XeTeX@page}\fi | |
\tciz@pagebox@info | |
}{}{\tciz@okfalse}% | |
% check | |
\unless\iftciz@ok | |
\PackageError{Patch to graphics driver has failed}\@ehc | |
\let\tciz@pagebox@info\relax | |
\fi | |
} | |
%% \tciz@pagebox@info | |
\def\tciz@pagebox@info{% | |
\unless\ifx\tciz@pagebox\@empty | |
\edef\picpage{\picpage\space | |
\@nameuse{tciz@box/\tciz@pagebox}}% | |
\fi | |
} | |
\fi | |
%--------------------------------------- done | |
\endinput | |
\tcizISkip | |
%======================================= | |
% The code below is employed on plain pdfTeX spawned | |
% inside the run of MetaPost. | |
%--------------------------------------- intra-MetaPost procedures | |
%% code guards | |
\edef\tcizIRestore{% | |
\catcode64=\the\catcode64%<@> | |
\relax} | |
\catcode64=11 %\makeatletter | |
%% variables | |
\newwrite\tciz@out | |
%%<+> \tcizIntrMPProcess{<file>}{<page>}{<page_box>}{<out_file>} | |
\def\tcizIntrMPProcess#1#2#3#4{% | |
\begingroup | |
\edef\tciz@imgfile{#1}% | |
\edef\tciz@outfile{#4}% | |
\edef\tciz@page{#2}% | |
\edef\tciz@pagebox{#3}% | |
\tciz@get@bbox | |
\tciz@write@out | |
\tciz@write@dvi | |
\endgroup | |
} | |
%%<+> \tcizIntrProcess{<file>}{<page>}{<page_box>}{<out_file>} | |
\def\tcizIntrProcess#1#2#3#4{% | |
\begingroup | |
\edef\tciz@imgfile{#1}% | |
\edef\tciz@outfile{#4}% | |
\edef\tciz@page{#2}% | |
\edef\tciz@pagebox{#3}% | |
\tciz@get@bbox | |
\tciz@write@out | |
\endgroup | |
} | |
%% \tciz@get@bbox | |
% Obtains the bbox of the target image. | |
\def\tciz@get@bbox{% | |
\edef\tciz@tmpa{% | |
\ifx\tciz@page\empty\else page \tciz@page\space\fi | |
\tciz@pagebox}% | |
\pdfximage\tciz@tmpa{\tciz@imgfile}% | |
\edef\tciz@bbox{% | |
\pdfximagebbox\pdflastximage 1 \space | |
\pdfximagebbox\pdflastximage 2 \space | |
\pdfximagebbox\pdflastximage 3 \space | |
\pdfximagebbox\pdflastximage 4}% | |
} | |
%% \tciz@write@out | |
% Writes the result file. | |
\def\tciz@write@out{% | |
\begingroup | |
\immediate\openout\tciz@out=\tciz@outfile\relax | |
\immediate\write\tciz@out{% | |
\string\tcizIntrResult{\tciz@bbox}}% | |
\immediate\closeout\tciz@out | |
\endgroup | |
} | |
%% \tciz@dummy@dvi | |
% The desired procedure requires features that are available | |
% only in PDF-mode. MetaPost that spawned pdfTeX, however, | |
% expects that there will be a DVI file output as result. | |
% Thus I prepare a dummy DVI file to fake "output". | |
% Here is the hex-dump of the file. | |
\edef\tciz@dummy@dvi{\pdfunescapehex{% | |
F702018392C01C3B0000000003E8008B% | |
00000001000000000000000000000000% | |
00000000000000000000000000000000% | |
0000000000000000FFFFFFFF8D840000% | |
0001000000018E8CF80000000F018392% | |
C01C3B0000000003E800000000000000% | |
0100010001F90000004802DFDFDFDFDF% | |
}} | |
%% \tciz@write@dvi | |
% Writes the dummy DVI file. | |
\def\tciz@write@dvi{% | |
\immediate\openout\tciz@out=\jobname.dvi\relax | |
\immediate\write\tciz@out{\tciz@dummy@dvi}% | |
\immediate\closeout\tciz@out | |
} | |
%--------------------------------------- done | |
\tcizIRestore | |
\endinput | |
%% EOF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% LaTeX document | |
\documentclass[a4paper,dvipdfmx]{article}% dvipdfmx! | |
\usepackage{graphicx} | |
% Load it after graphicx. | |
\usepackage{tcpagebox} | |
%\includegraphics[width=2cm]{testimg.pdf} | |
\begin{document} | |
% 'pagebox' is respected. (.xbb file is not used.) | |
\includegraphics[width=2cm,pagebox=mediabox]{image.pdf} | |
\includegraphics[width=2cm,page=2,pagebox=artbox]{image.pdf} | |
% When 'pagebox' is absent, the command will work exactly | |
% the same when tcpagebox is not loaded. | |
% Note that 'page' key is not (fully) supported in some old | |
% version of the dvipdfmx driver. | |
\includegraphics[width=2cm]{image.pdf} | |
\includegraphics[width=2cm,page=2]{image.pdf} | |
\end{document} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment