技研のまつけんです。

 

報告書やプレゼン資料などを作成していると、単純な作業の繰り返しが発生することが多々あるかと思います。そういうときは「自動化したい」と思ってしまう性格なので、ときどき自動化したりしています。今回は、PowerPointのファイルをcygwinの bashのシェルスクリプトで処理することで、自動的に画像のトリミングをしてしまおうという記事です。記事中のシェルスクリプトは全て、Windows 10 + Cygwin + bashで動作確認をしています。

用途

画像処理の結果をPowerPointで纏めたりしていると、

のようなスライド (画像と、その一部を拡大したものを提示) を作ることが度々あります。

このような場合、元の画像とトリミングした画像を用意する必要があります。もちろん、手作業でも出来るのですが、このようなスライドを大量に作らなければならないこともあります。unpack_pptx.sh、trim_by_rect.sh、pack_pptx.shという3つのシェルスクリプトを作成することでトリミングを自動化しました。

使い方

まず、以下のような、4枚のスライドからなるPowerPointファイルを作ります:

1枚目のスライドは、画像を貼りつけ、拡大を提示したい部分を矩形で囲みます。そして、矩形の数 (今回は3) の分だけ、スライドを複製します。複製したスライド (今回は2~4枚目) は矩形が1つずつ残るように余分な矩形を削除します。保存します (ここではbefore.pptxとします)。

続いて、Cygwinのbashで以下の通り、実行します:

cp -f before.pptx after.pptx
./unpack_pptx.sh after.pptx
./trim_by_rect.sh after 2
./trim_by_rect.sh after 3
./trim_by_rect.sh after 4
./pack_pptx.sh after
rm -rf after

実行結果

after.pptxとして、以下のファイルが生成されます:

ので、2~4枚目のスライドの画像と矩形を1枚目にカット&ペーストし、大きさを調整して、矢印を付ければ冒頭のスライドが完成します。

今回作成したスクリプト

今回作成したシェルスクリプトは、以下の3つです:

# unpack_pptx.sh
# PowerPointファイルを展開する
TGT=`basename "$1" .pptx`
rm -rf "$TGT" "$TGT-readable"
mkdir "$TGT"
( cd "$TGT" ; unzip ../"$TGT".pptx )
#cp -a "$TGT" "$TGT"_readable
#find "$TGT"_readable -iname "*.xml" | while read FILE
#do
# sed -e 's#([^^])<#1n<#g' -i "$FILE"
#done
# pack_pptx.sh
# ディレクトリからPowerPointファイルを生成
TGT=`basename "$1" .pptx`
rm -rf "$TGT".pptx
( cd "$TGT" ; zip -r ../"$TGT".pptx * )
# trim_by_rect.sh
# 特定のスライドの画像を矩形に合わせてトリミング
FILE="$1"/ppt/slides/slide"$2".xml
TMPFILE=tmp.txt
# 画像と矩形に関する部分の抜き出し
sed -e s'#<p:sp>#n�#g' -e s'#<p:pic>#n�#g' "$FILE" > $TMPFILE
# 画像と矩形の座標情報の取得
grep '<p:pic>' < $TMPFILE | sed
-e 's#.*(<a:off x="[0-9]+" y="[0-9]+"/><a:ext cx="[0-9]+" cy="[0-9]+"/>).*#1#'
-e 's#[^"0-9]##g'
-e 's#""#,#g' -e 's#"##g' > pict-pos-size.csv
grep '<p:sp>' < $TMPFILE | sed
-e 's#.*(<a:off x="[0-9]+" y="[0-9]+"/><a:ext cx="[0-9]+" cy="[0-9]+"/>).*#1#'
-e 's#[^"0-9]##g'
-e 's#""#,#g' -e 's#"##g' > rect-pos-size.csv
grep -n '' pict-pos-size.csv rect-pos-size.csv
# 座標情報の取得とトリミングの比率の計算
PICT_OFF_L=`head -n 1 < pict-pos-size.csv | cut -f 1 -d ,`
PICT_OFF_T=`head -n 1 < pict-pos-size.csv | cut -f 2 -d ,`
PICT_EXT_W=`head -n 1 < pict-pos-size.csv | cut -f 3 -d ,`
PICT_EXT_H=`head -n 1 < pict-pos-size.csv | cut -f 4 -d ,`
PICT_OFF_R=$(( PICT_OFF_L + PICT_EXT_W ))
PICT_OFF_B=$(( PICT_OFF_T + PICT_EXT_H ))
RECT_OFF_L=`head -n 1 < rect-pos-size.csv | cut -f 1 -d ,`
RECT_OFF_T=`head -n 1 < rect-pos-size.csv | cut -f 2 -d ,`
RECT_EXT_W=`head -n 1 < rect-pos-size.csv | cut -f 3 -d ,`
RECT_EXT_H=`head -n 1 < rect-pos-size.csv | cut -f 4 -d ,`
RECT_OFF_R=$(( RECT_OFF_L + RECT_EXT_W ))
RECT_OFF_B=$(( RECT_OFF_T + RECT_EXT_H ))
TRIM_L=$(( ( ($RECT_OFF_L - $PICT_OFF_L) * 200000 / $PICT_EXT_W + 1) / 2 ))
TRIM_T=$(( ( ($RECT_OFF_T - $PICT_OFF_T) * 200000 / $PICT_EXT_H + 1) / 2 ))
TRIM_R=$(( ( ($PICT_OFF_R - $RECT_OFF_R) * 200000 / $PICT_EXT_W + 1) / 2 ))
TRIM_B=$(( ( ($PICT_OFF_B - $RECT_OFF_B) * 200000 / $PICT_EXT_H + 1) / 2 ))
# トリミング実行
sed -i $FILE
-e "s#$PICT_OFF_L#$RECT_OFF_L#"
-e "s#$PICT_OFF_T#$RECT_OFF_T#"
-e "s#$PICT_EXT_W#$RECT_EXT_W#"
-e "s#$PICT_EXT_H#$RECT_EXT_H#"
-e 's#<a:blip r:embed="rId[0-9]+"/>#�<a:srcRect l="'$TRIM_L'" t="'$TRIM_T'" r="'$TRIM_R'" b="'$TRIM_B'"/>#'
# テンポラリファイルを削除
rm -f $TMPFILE pict-pos-size.csv rect-pos-size.csv

詳細説明

pptxファイルをunpack_pptx.shで展開すると各スライドの本体は、ppt/slidesの中にslide1.xml、slide2.xml、…として格納され、矩形や楕円などの「形」は<p:sp>と</p:sp>の中に記述されます[1]。

pptx内のXMLファイルは改行が無いので読みにくいのですが、unpack_pptx.shの最後の4行のコメントアウトを解除すると、after_readableというディレクトリ内に、改行されたXMLファイルを得られます。ただし、インデントは行われないので、XML整形ツール[2]などを用いると読みやすくなります (ちなみに、Cygwinのastyleではうまくいきませんでした)。

矩形の位置とサイズは、それぞれ、

<a:off x="3219451" y="2266951" />
<a:ext cx="685800" cy="609600" />

という形で記述され、単位は1/360 000センチメートルです。offとextはおそらく、offsetとextentionの略と思われます。

画像は <p:pic>~</p:pic>の中に記述され[1]、位置とサイズは矩形と同じフォーマットです。画像のトリミングは

<a:srcRect l="5063" t="46417" r="83687" b="40250"/>

という形で記述され、単位は「十万分率」です (例えば、左側20%、上側10%をトリミングすると<a:srcRect l=”20000″ t=”10000″/>)。

これらを基に、TRIM_Lなどを計算します。十万分率なので、($RECT_OFF_L – $PICT_OFF_L) * 100000 / $PICT_EXT_Wも良いのですが、四捨五入するために、2倍で計算して、1を足したあと、2で割っています。

まとめ

如何でしょうか。矩形の数の分だけ、スライドを複製して、各々、1つだけ残して消したりするのが手間ですが、自動化は出来ました。今後、1枚のスライドに結果を配置して、矢印も自動で付加するなどの改良を行ったら、また紹介したいと思います。

参考

[1] [方法] プレゼンテーションの図形の塗りつぶしの色を変更する https://docs.microsoft.com/ja-jp/office/open-xml/how-to-change-the-fill-color-of-a-shape-in-a-presentation
[2] XML整形ツール https://mk-webtool.com/Xml/