読者です 読者をやめる 読者になる 読者になる

らっちゃいブログ

日々の学びと気づきを発信するブログ

Pillowで画像を正方形に切り抜く方法

スポンサーリンク

以前 Pillow を使ったサムネイルの作成方法について記事を書きましたが、今回はその続きです。

racchai.hatenablog.com

ユーザー画像等、サムネイルにした上で正方形に切り抜きたいケースが多々ありますよね。ではさっそくやり方を見ていきましょう。

事前準備

お決まりのインストール作業から。

$ pip install pillow

インストールができたら、以下のサムネイル生成コードをベースに解説していきます。

from PIL import Image

img = Image.open('original.jpg', 'r')
thumbnail_size = (100, 100)
img.thumbnail(thumbnail_size)
img.save('thumbnail.jpg', 'JPEG')

解説

Pillow では crop 関数というものが用意されていて、box と呼ばれる(left, top, right, bottom)のような座標を示すタプルを指定することで画像を切り取ることができます。

Image.crop(box=None)

つまり、box の指定を工夫すれば元画像を正方形に切り取ることができるわけですね。それでは実際の座標を計算していきます。

辺の長さを決定する

正方形に切り取るわけですから、まずは一辺の長さを決める必要がありますね。今回は、長方形の短い辺に合わせて長い方の辺を切り取る方式を取ることにします。

縦・横の短い方を採用するわけなので、以下のようにしてベースの長さを取得することができます。

img = Image.open('original.jpg', 'r')
square_size = min(img.size)

簡単ですね。

切り取る座標を決める

Pillow では画像の座標を指定して切り取ることになりますので、長さを取得しておきましょう。

width, height = img.size

次に座標位置を計算するわけですが、縦横どちらが長いかで処理が違ってきます。まずは width が大きい場合の座標を計算してみます。

(left, top, right, bottom)それぞれの座標を計算していくわけですが、width が大きい場合(横長)は縦方向の座標が計算しやすいので先に出してしまいます。

まずは top ですが、縦方向には切り取らないので 0 でOKです。そして bottom は top の位置から一辺の長さを加えた位置になりますので、以下のようになります。

top = 0
bottom = square_size

次は横方向ですが、こちらも複雑な計算は不要です。先に left を算出しますと、切り取る辺の長さから一辺の長さを引き、2で割った位置へ移動させればよいだけです。

left = (width - square_size) / 2

そして right の位置は left に一辺の長さを加えれば良いだけですね。

right = left + square_size

まとめると、以下のようになります。

img = Image.open('original.jpg', 'r')
square_size = min(img.size)

top = 0
bottom = square_size

left = (width - square_size) / 2
right = left + square_size

box = (left, top, right, bottom)

height が大きい場合も同様に考えれば、簡単に座標を決めることができますね。

img = Image.open('original.jpg', 'r')
square_size = min(img.size)

left = 0
right = square_size

top = (height - square_size) / 2
bottom = top + square_size

画像を切り取る

座標さえ決まってしまえば、あとは切り取るだけです。 縦横どちらが大きいかを分岐して座標を計算し、実際に切り取るまでのコードは以下のようになります。

from PIL import Image

img = Image.open('original.jpg', 'r')
square_size = min(img.size)

if width > height:
    top = 0
    bottom = square_size
    left = (width - square_size) / 2
    right = left + square_size
    box = (left, top, right, bottom)
else:
    left = 0
    right = square_size
    top = (height - square_size) / 2
    bottom = top + square_size
    box = (left, top, right, bottom)

img = img.crop(box)

thumbnail_size = (100, 100)
img.thumbnail(thumbnail_size)
img.save('thumbnail.jpg', 'JPEG')

ひとこと

画像を切り取るコードって意外とすっきり書けるものですね。

ただ、実のところ上記の計算方法だと1ピクセルほどずれてしまい、正確な正方形にならない場合がありますので、厳密な計算が必要な方は注意しましょう。