Skalieren und Zuschneiden von Bildern mit Python

Bildquelle: USGS on Unsplash (bearbeitet)

Python

Skalieren und Zuschneiden von Bildern mit Python

Da ich sehr viele Bilder (und anfangs auch sehr große) Bilder hier verwendet habe, hat sich das enorm auf die Geschwindigkeit der Seite ausgewirkt. Seit Juli 2018 ist PageSpeed ein Ranking-Faktor fĂŒr Suchmaschinen wie Google und Co und man möchte ja nicht irgendwo auf Seite 50 in den Suchergebnissen rumdĂŒmpeln sondern vorne mit dabei sein.

Die hier verwendeten Bilder sind hauptsĂ€chlich Satellitenbilder von ESA, die unter der Lizenz CC BY-SA 3.0 IGO IGO) veröffentlich wurden und somit auch fĂŒr eigene Zwecke unter bestimmten Bedingungen genutzt werden dĂŒrfen.

Diese Bilder sind gerne auch mal ~30MB groß, was etwas zu groß fĂŒr eine Website ist. + Da ich nicht alle Bilder manuell zuschneiden wollte, habe ich mich entschieden dieses Problem mit Python bzw. Pillow zu lösen.

Pillow Bibliothek

Pillow ist eine Python Bibliothek zur Bildverarbeitung, die man sich unter Windows mit

pip install Pillow

installieren und mit

from PIL import Image

in ein Python Script importieren kann.

Alle Bilder fĂŒr Posts liegen in einem seperaten "images/" Ordner im Rootverzeichnis des Projekts. Als Erstes werden alle ".jpg" Dateien in einem bestimmten Verzeichnis mit Pillow geöffnet und alle Dateinamen in einen Array gespeichert. Außerdem wird eine Variable benötigt und spĂ€ter auf jeden Namen in dem Array zugreifen zu können.

count = 0
image_list = []

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

GrĂ¶ĂŸen definieren und SeitenverhĂ€ltnis berechnen

Nun solltem man wissen, auf welche GrĂ¶ĂŸen die Bilder zugeschnitten und ob zum Beispiel GrĂ¶ĂŸenverhĂ€ltnisse beibehalten werden sollen. Bei allen "PostCover" (Bilder in BeitrĂ€gen) wird das SeitenverhĂ€ltnisse ignoriert und das Bild einfach auf eine bestimmte GrĂ¶ĂŸe zugeschnitten, die in einer globalen Variable deklariert wird.

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

Bei allen "PostThumbnails" (Bilder Vorschau) soll das SeitenverhĂ€ltnis beibehalten werden und sozusagen nur kleiner skaliert werden. DafĂŒr wird eine globale Standardbreite definiert.

basewidth = 500

Anschließend wird die Originalbreite und -höhe der Bilder ermittelt, da wir diese brauchen um das SeitenverhĂ€ltnis berechnen und beibehalten zu können. Hier wird nur die neue Höhe gebraucht, da die Standardbreite bereits vordefiniert wurde.

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

"Cropping" und "Rescaling"

Nun kann man die Bilder mit Image.cropzuschneiden bzw. mit Image.resize skalieren. Bei der Skalierung werden jetzt die neue Breite "basewidth" und die berechnete Höhe "hsize" als Parameter verwendet.

    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))

Folgend habe ich die das Thumbnail noch umbenannt und beide neuen Dateien unter static/assets/ mit einer QualitÀt von "85" abspeichert. Mit dem zustÀtzlichen Parameter "optimize=True" können auch noch einmal ein paar KB gespart werden.

    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 

Gesamtskript:

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 

Skript automatisch ausfĂŒhren

Um das Skript nicht jedes mal manuell ausfĂŒhren zu mĂŒssen kann man in "package.json" noch folgendes ergĂ€nzen.

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

Somit kann man mit npm run img-optimize alle Bilder automatisch optimieren.

More Articles: