Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
ZR氏による「バッチで作る、劣化版pdfcrop」の改善版
@echo off
echo tcpdfcrop v0.9.4 (2015-08-06)
setlocal
if /I "%~1"=="/h" (
set BBOX=HiResBoundingBox
shift
) else (
set BBOX=BoundingBox
)
set FROMDIR=%~dp1
set FROM=%~n1
set TODIR=%~dp2
set TO=%~n2
set RANGE=%~3
set TPX=_tcpc
set CROPTEMP=croptemp
if "%FROM%"=="" (
echo Usage: tcpdfcrop [/h] in.pdf [out.pdf] [page-range] [left-margin] [top-margin] [right-margin] [bottom-margin]
echo Option /h uses HiResBoundingBox instead of BoundingBox.
)
if not exist "%FROMDIR%%FROM%.pdf" exit /B
if not "%TEMP%"=="" cd "%TEMP%"
copy "%FROMDIR%%FROM%.pdf" "%CROPTEMP%.pdf" 1>nul
if "%TO%"=="" set TO=%FROM%-crop
if "%TODIR%"=="" set TODIR=%FROMDIR%
if "%TODIR%%TO%"=="%FROMDIR%%FROM%" set TO=%FROM%-crop
if exist "%TODIR%%TO%.pdf" del "%TODIR%%TO%.pdf"
if exist "%TODIR%%TO%.pdf" exit /B
extractbb "%CROPTEMP%.pdf"
type "%CROPTEMP%.xbb" | find "%%Pages: " > "%CROPTEMP%-pages.txt"
set /P NUM=<"%CROPTEMP%-pages.txt"
set NUM=%NUM:* =%
type "%CROPTEMP%.xbb" | find "%%PDFVersion: " > "%CROPTEMP%-version.txt"
set /P VERSION=<"%CROPTEMP%-version.txt"
set VERSION=%VERSION:*.=%
del "%CROPTEMP%.xbb" "%CROPTEMP%-pages.txt" "%CROPTEMP%-version.txt"
for /F "tokens=1,2 delims=-" %%m in ("%RANGE%") do (
set FIRST=%%m
set LAST=%%n
)
if "%FIRST%"=="" set FIRST=1
if "%FIRST%"=="*" set FIRST=1
if "%LAST%"=="" (
if "%RANGE%"=="" (
set LAST=%NUM%
) else (
set LAST=%FIRST%
)
)
if "%LAST%"=="*" set LAST=%NUM%
set LMARGIN=%~4
set TMARGIN=%~5
set RMARGIN=%~6
set BMARGIN=%~7
if "%LMARGIN%"=="" set LMARGIN=0
if "%TMARGIN%"=="" set TMARGIN=0
if "%RMARGIN%"=="" set RMARGIN=0
if "%BMARGIN%"=="" set BMARGIN=0
echo \pdfoutput=1 >%TPX%n.tex
echo \pdfminorversion=%VERSION% >>%TPX%n.tex
for /L %%i in (%FIRST%,1,%LAST%) do (
rungs -dBATCH -dNOPAUSE -q -sDEVICE=bbox -dFirstPage=%%i -dLastPage=%%i "%CROPTEMP%.pdf" 2>&1 | find "%%%BBOX%: " >%TPX%%%i.tex
echo {\catcode37=13 \catcode13=12 \def^^^^25^^^^25#1: #2^^^^M{\gdef\do{\proc[#2]}}\input %TPX%%%i.tex\relax}{}^
\def\proc[#1 #2 #3 #4]{\pdfhorigin-#1bp \pdfvorigin#2bp \pdfpagewidth=\dimexpr#3bp-#1bp\relax\pdfpageheight\dimexpr#4bp-#2bp\relax}\do^
\advance\pdfhorigin by %LMARGIN%bp\relax \advance\pdfpagewidth by %LMARGIN%bp\relax \advance\pdfpagewidth by %RMARGIN%bp\relax^
\advance\pdfvorigin by -%BMARGIN%bp\relax \advance\pdfpageheight by %BMARGIN%bp\relax \advance\pdfpageheight by %TMARGIN%bp\relax^
\setbox0=\hbox{\pdfximage page %%i mediabox{%CROPTEMP%.pdf}\pdfrefximage\pdflastximage}^
\ht0=\pdfpageheight \shipout\box0\relax >>%TPX%n.tex
)
echo \end >>%TPX%n.tex
pdftex -no-shell-escape -interaction=batchmode %TPX%n.tex 1>nul
for /L %%i in (%FIRST%,1,%LAST%) do del %TPX%%%i.tex
del %TPX%n.tex %TPX%n.log %CROPTEMP%.pdf
if not exist %TPX%n.pdf exit /B
move "%TPX%n.pdf" "%TODIR%%TO%.pdf" 1>nul
echo ==^> %FIRST%-%LAST% page(s) written on "%TODIR%%TO%.pdf".
@aminophen
Owner

「Perl 無しの Windows」で pdfcrop(のオプション無し)と同じことをする(W32TeX ユーザに有用かも)。ZR 氏のバッチファイルの2箇所のバグ修正と、オリジナルの Perl スクリプトの挙動に近づける改訂1箇所。

tcpdfcrop in.pdf out.pdf

において、out.pdf が指定されない場合は接尾辞として in.pdf のファイル名に -crop が付くようにした(この変更で、単に PDF ファイルをバッチファイルに向かってドラッグ&ドロップするだけで余白をなくすことが可能となった)。

さらに改善を加え、元の PDF ファイル名に空白文字を含む場合も正しく処理できるようになった。
現時点 (v0.4) でこのバッチファイルでできることは「単一ページ PDF の余白を0にする」ことだけである。オリジナル(Perl スクリプト)は、複数ページ PDF を入力した場合に各ページを正常にクロップして複数ページ PDF を出力するが、このバッチファイルではそのような処理はできない。

@aminophen
Owner

v0.5 で複数ページ処理を実装してみた。ただし、実行時に第三引数に総ページ数を与えなければならない(指定しなければ最初の 1 ページだけをクロップ)。

tcpdfcrop in.pdf out.pdf <pagenum>

v0.6 で余白を付与できるようにしてみた。実行時に第四から七引数に、左・上・右・下の順で余白を bp 単位で与えると、たぶん余白がその通りにつくと思う。

@aminophen
Owner
aminophen commented Mar 15, 2015 edited

今気づいている点 (v0.6) :

  • 引数の指定の仕方が異なる
  • 余白以外のオプションは本家 Perl スクリプトと違って変更できない
  • pdfcrop の本家 Perl スクリプト版はデフォルトで元の PDF version を保持する(ユーザ指定も可)が、バッチファイル tcpdfcrop.bat では自動的に 1.5 になる → v0.8.2 で改善
  • 微妙に余白の付き方が異なる(見た目ではほとんどわからないが、ディスプレイ上で重ねると微妙にずれる) → v0.9 で解消
  • ファイル名に Shift_JIS のダメ文字が入っていると不可(中間生成の TeX ソースが Shift_JIS になるため、正しく画像を読み込めない) → v0.9.1 で解消
  • ディレクトリ指定不可(カレントディレクトリに元の PDF がある場合に限定する) → v0.7 で解消

なお、このバッチファイルの目的は Perl がない Windows で pdfTeX + Ghostscript を使ってクロップすることなので gswin32c 決め打ちだが(TeX Live には Perl 内蔵のため実質 W32TeX を想定)、rungs に置き換えれば TeX Live でも使えることを確認済み。

# W32TeX にも TeX Live にも rungs.exe はあるので、はじめからそうしてもいいのだが。 → v0.8 で変更

@doraTeX
doraTeX commented Mar 16, 2015

提案1

\input _tcpc%%i.tex

この部分の _tcpc も %TPX% に変更した方がよいのではないでしょうか。

提案2

for ループに入る前に %TPX%n.tex に \pdfoutput=1 を書き込んでおくと,DVI-mode がデフォルトになっている pdfTeX の場合にも対応できます。

提案3

実行時に第三引数に総ページ数を与えなければならない

この部分は,extractbb の出力を解析することでPDFの総ページ数を取得できます。

extractbb "%FROM%.pdf"
type "%FROM%.xbb" | find "Pages" > "%FROM%-pages.txt"
set /p NUM=<"%FROM%-pages.txt"
set NUM=%NUM:* =%
del "%FROM%.xbb" "%FROM%-pages.txt"

とすれば,変数 NUM に %FROM%.pdf の総ページ数が入ります。

@aminophen
Owner

doraTeX さんのコメントを元に、v0.7 を公開。指摘された3点に加え、ディレクトリ指定もできるようにしたつもり。ちなみにページ数オプションであった第三引数は、今後ページ範囲を指定できるようにしたいと思って残している。

@aminophen
Owner

ページ範囲指定を v0.8 で実装。第三引数で開始ページと終了ページをハイフンで結んで指定する。アスタリスクを使えば「最後まで」「最初から」を指定できるはず。

  • tcpdfcrop in.pdf out.pdf 3-10 : 3 ページ目から 10 ページ目までを処理
  • tcpdfcrop in.pdf out.pdf 3-* : 3 ページ目から(最後まで)を処理
  • tcpdfcrop in.pdf out.pdf *-10 : (最初から)10 ページ目までを処理
  • tcpdfcrop in.pdf out.pdf 3 : 3 ページ目のみを処理

この機能はオリジナルの Perl スクリプトには存在せず、本バッチファイルの有利な点となった。このため TeX Live ユーザにも一定の有用性が見込めると判断し、従来は Perl なしの W32TeX での利用を仮定して gswin32c 固定だったものを、両方で利用可能な rungs に変更した。

なお、v0.6 で余白処理を追加した際に入ったバグを修正(余白にあたる引数が空白の場合に出る ! Missing number, treated as zero. なるエラーを回避する初歩的なハンドリングが不足していた…)。

@doraTeX
doraTeX commented Mar 24, 2015

すみません,

type "%FROM%.xbb" | find "Pages" > "%FROM%-pages.txt"

だとファイル名に Pages という単語が入っている場合に失敗しますね。

type "%FROM%.xbb" | find "%%Pages: " > "%FROM%-pages.txt"

とすべきでした。

@aminophen
Owner

ファイル名に Pages という単語が入っている場合に失敗

修正しました (v0.8.1) 。

@aminophen
Owner

本家 Perl スクリプト版はデフォルトで元の PDF version を保持するので、その仕様に合わせた (v0.8.2) 。これで、クロップすると PDF version が勝手に上がってしまって画像が使えなくなる可能性を排除。

ちなみにこの変更 (v0.8.2) により、多くの場合で従来の v0.8.1 に比べて低い PDF version で出力されるはず。このとき、高い version に比べてファイルサイズが大きくなるのは(たぶん)仕様。

@aminophen
Owner
aminophen commented Mar 31, 2015 edited

v0.8.2 以前は HiResBoundingBox を使っていたが、オリジナルの Perl スクリプトはデフォルトで BoundingBox を使っている(つまり hires ではない)ので、微妙に余白の付き方が異なっていた。v0.9 で tcpdfcrop.bat のデフォルトを変更してオリジナルに統一。とりあえず従来版 (v0.8.2) を tcpdfcrophires.bat として残した。

# これ以上のオプション実装は Windows バッチファイルでは難しいので、別々のバッチファイルにしてみた。

@aminophen
Owner

v0.9.1 で、一時ファイルを環境変数 TEMP で指定されたフォルダ内に生成するようにした。これに伴い「ファイル名に Shift_JIS のダメ文字が入っていると不可」という問題も解消。

今気づいている点・制限事項 (v0.9.2) :

  • 引数の指定の仕方が異なる
  • 余白以外のオプションは本家 Perl スクリプトと違って変更できない
  • 空白ページが含まる場合の扱いが異なる(本家 Perl スクリプト版は元のサイズを維持して取り込むが、バッチファイル版は横幅のみ維持して縦幅は 1 mm になる) → bcpdfcrop v0.1.3 と v0.1.9 で解消。
  • 本家 Perl スクリプト版とバッチファイル版で同じ PDF を処理すると、なぜか僕のバッチファイルで作った方がファイルサイズが小さくなる(ただし、Perl 版のほうが処理は高速)
@doraTeX
doraTeX commented Jul 19, 2015

ノーマル版とHiRes版に分かれているのは,オプションで統合してはいかがでしょう。
setlocal の直後に

if /I "%1"=="/h" (
  set BBOX=HiResBoundingBox
  shift
) else (
  set BBOX=BoundingBox
)

として,BBを find する部分を

find "%%%BBOX%: "

としておけば,

Usage: tcpdfcrop [/h] in.pdf [out.pdf] [page-range] [left-margin] [top-margin] [right-margin] [bottom-margin]

と,/h オプションでHiRes版とノーマル版を切り替えることができるのではないかと思います。

@aminophen
Owner

/h オプションでHiRes版とノーマル版を切り替える

早速取り込んで v0.9.3 としました。ついでにインデントを統一しました。

@aminophen
Owner

複数ページ処理時に従来は単一のファイルに出力するようにしていたが、内部処理を変更して /s オプションで各ページを単一ページ PDF としてバラバラに出力できるようにした。その結果として tc らしさがなくなったので(\catcode がなくなった笑)、別途 bcpdfcrop.bat として GitHub にて公開。

というわけで、tcpdfcrop.bat は現状では frozen とします。

@aminophen
Owner

いったん開発終了したつもりでいたが、/h オプションを追加した時点でダブルクオーテーションを除去して展開するのを忘れていて、tcpdfcrop v0.9.3 は正常に動かない場合があることに気づいた。バグがあるまま残しておくのもどうかと思ったので、急遽 v0.9.4 で修正。

tcpdfcrop は“TeX 藝人”的にはおもしろいはずなのでこのまま残しておく。ただし、バグ修正程度しかしない予定(tcpdfcrop はエラーハンドリングが甘い簡易版くらいの位置づけで…)。bcpdfcrop が充実してきたのでそちらをどうぞ。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment