Scaling and Cropping images using Python

Since I used a lot of pictures (and also very large ones in the beginning), this had a huge impact on the speed of the page. Since PageSpeed ​​is a not unimportant ranking factor for search engines like Google and Co, you should of course make a page as fast as possible.

The images used here are mainly satellite images from ESA, which are licensed under the CC BY-SA 3.0 IGO IGO) and may therefore also be used for your own purposes under certain conditions.

These pictures are often ~ 30MB, which is a bit too big for a website. Since I didn't want to crop all pictures manually, I decided to solve this problem with Python or Pillow.

Pillow library

Pillow is a Python library for image processing that can be installed on with (assuming you have Python already installed)

pip install Pillow

Finally you can import the library with

from PIL import Image

into your Python script.

All images for posts are in a separate "images /" folder in the root directory of the project.

First, all ".jpg" files in a certain directory are opened with Pillow and all file names are saved in an array. In addition, a variable is required and can later access any name in the array.

count = 0
image_list = []

for file in glob.iglob('path/to/images/*.jpg'):
im=Image.open(file)
image_list.append(os.path.basename(file))

Define sizes and calculate aspect ratio

Now you should know to which sizes the pictures should be cut and whether, for example, the proportions should be retained. For all "PostCover" (pictures in posts) the aspect ratio is ignored and the picture is simply cut to a certain size, which is declared in a global variable.

size = (1903,453) #(width,height)

With all "PostThumbnails" (picture preview) the aspect ratio should be retained and only scaled smaller. A global standard width is defined for this.

basewidth = 500

Then the original width and height of the images are determined, as we need them to be able to calculate and maintain the aspect ratio. Only the new height is needed here, as the standard width has already been predefined.

width, height = im.size
wpercent = (basewidth / float(im.size[0]))
hsize = int((float(im.size[1]) * float(wpercent)))

Cropping and Rescaling

Now you can cut the images with Image.crop or scale them with Image.resize. The new width "basewidth" and the calculated height "hsize" are now used as parameters for scaling.

imThumbnail = im.resize((basewidth, hsize), Image.LANCZOS)
imCover = im.crop(((width-size[0])//2, (height-size[1])//2, (width+size[0])//2, (height+size[1])//2))

Then I renamed the thumbnail and saved both new files under static/assets with a quality of "85" . With the additional parameter "optimize = True" a few KB can be saved.

newCover = 'static/assets/{}'.format(image_list[count])
newThumbnail = 'static/assets/{}_thumbnail.jpg'.format(image_list[count].replace(".jpg", ""))
imCover.save(newCover,optimize=True,quality=85)
imThumbnail.save(newThumbnail,optimize=True,quality=90)
count +=1

Complete script:

from PIL import Image
import glob, os

count = 0
image_list = []
basewidth = 500
size = (1903,453)

for file in glob.iglob('path/to/images/*.jpg'):
im=Image.open(file)
image_list.append(os.path.basename(file))
width, height = im.size
wpercent = (basewidth / float(im.size[0]))
hsize = int((float(im.size[1]) * float(wpercent)))
imThumbnail = im.resize((basewidth, hsize), Image.LANCZOS)
imCover = im.crop(((width-size[0])//2, (height-size[1])//2, (width+size[0])//2, (height+size[1])//2))
newCover = 'static/assets/{}'.format(image_list[count])
newThumbnail = 'static/assets/{}_thumbnail.jpg'.format(image_list[count].replace(".jpg", ""))
imCover.save(newCover,optimize=True,quality=85)
imThumbnail.save(newThumbnail,optimize=True,quality=90)
count +=1

Run script automatically

In order not to have to run the script manually every time, you can add the following to "package.json".

"img-optimize": "py ./src/utils/resize_images.py"

So you can optimize all images automatically with npm run img-optimize.