Twitterで投稿するために4分割された画像を作るシェルスクリプト

プログラム,画像処理シェルスクリプト

Twitter で 1 枚の画像を 4 分割して大きな画像っぽくして投稿する、という方法があります。例えば以下のツイートのようなものです。

この方法、ちょっとググると「Photoshop でやる」とか「スマホアプリを使って」とか出てくるのですが、PC から投稿したいときにそれはめんどくさい。このぐらいならシェルスクリプトで ImageMagick 使えばできるだろう、ということで、作ってみたので紹介します。

必要なことは「4 枚の各画像の縦横比が 16:9 になるように切り出す」ということです。

ソースコード全体

引数に分割したい画像のファイル名を指定することで、「ファイル名_1.jpg」というような画像が 4 枚吐き出されます。

#!/bin/sh
# 一枚の画像を 16:9 のサイズで 4 つに分割するためのスクリプト
# 引数に変換したいファイル名を指定する

# ファイル名取得
filename=$1

# 画像サイズの取得
width=`identify -format "%[width]" $filename`
height=`identify -format "%[height]" $filename`

# 元画像サイズを使って 16:9 となるサイズを求める
if [ $((${width} * 9 / 16)) -ge $height ]; then
    widthLen=$((${height} * 16 / 9))
    heightLen=$height
else
    widthLen=$width
    heightLen=$((${width} * 9 / 16))
fi

# 切り出しサイズを決める
cropsize="${widthLen}x${heightLen}+0+0"

# 16:9 の画像作成 (一時ファイル)
tmpfile=$(mktemp)
convert -verbose $filename -gravity center -crop $cropsize +repage $tmpfile

# ファイル名と拡張子の抜き出し
filename=`basename ${filename}`
name=`echo ${filename} | sed -e "s/\.[^\.]*$//"`
ext=`echo ${filename} | sed -e "s/^.*\.\([^\.]*\)$/\1/"`

# 50% サイズで 4 分割する
convert -verbose $tmpfile -crop 50%x50% ${name}_%d.${ext}

# 一時ファイルの消去
rm $tmpfile

ソースコード解説

簡単にソースコードについて解説を入れておきます。

画像サイズ取得 & 出力サイズ計算

元画像から適切なサイズを求めます。

# 画像サイズの取得
width=`identify -format "%[width]" $filename`
height=`identify -format "%[height]" $filename`

# 元画像サイズを使って 16:9 となるサイズを求める
if [ $((${width} * 9 / 16)) -ge $height ]; then
    widthLen=$((${height} * 16 / 9))
    heightLen=$height
else
    widthLen=$width
    heightLen=$((${width} * 9 / 16))
fi

最初に identity コマンドを使って画像幅 width と画像高さ height を取得します。

最終的には 16:9 のサイズにする必要があるので、ここで元画像から切り出せる 16:9 の最大サイズを決めます。画像幅に 9/16 を掛けたものと画像高さを比較することで、どちらの長さを基準にして画像サイズを決めるか計算しています。(下の例のうち、どちらの切り出しにするかを場合分けする)

画像が縦に大きい場合の切り出し例
画像が横に大きい場合の切り出しサイズ例

16 : 9 の画像に変換

先に求めたサイズを使って、convert コマンドを用いて画像を変換します。

# 切り出しサイズを決める
cropsize="${widthLen}x${heightLen}+0+0"

# 16:9 の画像作成 (一時ファイル)
tmpfile=$(mktemp)
convert -verbose $filename -gravity center -crop $cropsize +repage $tmpfile

convert を使って画像を切り出すオプションは次の通り

convert ${元ファイル名} -gravity center -crop ${幅}x${高さ}+${横開始ピクセル}+${縦開始ピクセル} $${出力ファイル}

ここに先程求めたサイズを入れ、-gravity center オプションをつけることで画像真ん中を指定したサイズで切り出すようにしています(-gravity オプションによる指定がないと画像左上から切り出す)。

さらに +repage オプションを付けています。これがないと切り出した後の画像にキャンバスの余白が設定されてしまい、4 枚に切り出すときに座標がずれて困るのでそれを避けています。

また出力ファイル名として mktemp コマンドで得られたものを使っています。16:9 に切り出した大きい画像は最終的にはいらなくなって消すつもりなので、下手に既存ファイルを上書きしないようにする工夫です。

ファイル名・拡張子の取得

最終出力の際に使うため、ファイル名と拡張子を取得します。

# ファイル名と拡張子の抜き出し
filename=`basename ${filename}`
name=`echo ${filename} | sed -e "s/\.[^\.]*$//"`
ext=`echo ${filename} | sed -e "s/^.*\.\([^\.]*\)$/\1/"`

basename コマンドを使ってファイル名を取得し、その後 sed コマンドで正規表現を使って、拡張子を除いたファイル名と拡張子をそれぞれ取得しておきます。

例えば “src_photo.jpg" というファイル名であれば、$name にはファイル名 “src_photo" が、$ext には拡張子 “jpg" が入ります。

画像を 4 つに分割

再び convert を使います。

# 50% サイズで 4 分割する
convert -verbose $tmpfile -crop 50%x50% ${name}_%d.${ext}

convert の -crop オプションは “${横開始ピクセル}+${縦開始ピクセル}" のように位置を指定せず、大きさだけ指定すると、そのサイズで画像全体をカバーするように切り出してくれるそうです。そのためここでは “50%x50%" と指定することでちょうど 4 分割することができます。

(これを知るまでは $(( (${width} – ${widthLen})/2 )) などと自分で計算しようとしていました……。)

出力ファイル名に “%d" を付けておくと、ファイル名にそれぞれ整数を付けて出力してくれるので、先に取得したファイル名と拡張子を組み合わせて出力するようにしています。"src_photo.jpg" というファイルを変換した場合、以下のようなファイルができあがります。

  • src_photo_1.jpg
  • src_photo_2.jpg
  • src_photo_3.jpg
  • src_photo_4.jpg
切り出し結果のイメージ

これでできた 4 枚の画像を貼れば冒頭で紹介したようなツイートができるはずです。

参考資料

Twitterで4画面の画像でインパクトを出そう! Photoshopを使って! – あおとえま モノデザ

ImageMagick の画像 crop – Qiita

シェルスクリプトによる処理といえば

以下の記事も exiftools コマンドを使って、写真を仕分けるシェルスクリプトを紹介しています。