Documentation Menu

Integration Guide

Django

Django's ImageField depends on Pillow for image validation. For more advanced tasks like generating thumbnails or watermarking on upload, use Django signals or a dedicated library like django-imagekit.

Django: Process Upload
# models.py from django.db import models class Photo(models.Model): image = models.ImageField(upload_to="photos/") # signals.py — auto-generate thumbnail on upload from django.db.models.signals import post_save from PIL import Image import os def create_thumbnail(sender, instance, **kwargs): if instance.image: with Image.open(instance.image.path) as img: img.thumbnail((300, 300), Image.Resampling.LANCZOS) thumb_path = instance.image.path.replace("/photos/", "/thumbs/") img.save(thumb_path) post_save.connect(create_thumbnail, sender=Photo)

FastAPI

FastAPI's file upload handling works seamlessly with Pillow via UploadFileBytesIOImage.open().

FastAPI Image Upload Handler
from fastapi import FastAPI, UploadFile, File from fastapi.responses import StreamingResponse from PIL import Image import io app = FastAPI() @app.post("/resize") async def resize_image(file: UploadFile = File(...)): contents = await file.read() img = Image.open(io.BytesIO(contents)) img.thumbnail((800, 800), Image.Resampling.LANCZOS) buf = io.BytesIO() img.save(buf, format="WEBP", quality=85) buf.seek(0) return StreamingResponse(buf, media_type="image/webp")

Flask

Flask Upload + Process
from flask import Flask, request, send_file from PIL import Image import io app = Flask(__name__) @app.post("/convert") def convert(): file = request.files["image"] img = Image.open(file.stream).convert("RGB") buf = io.BytesIO() img.save(buf, "JPEG", quality=90) buf.seek(0) return send_file(buf, mimetype="image/jpeg")

NumPy

Pillow and NumPy arrays can be converted freely. This allows you to apply arbitrary mathematical operations on pixel data and then render back to an image.

Pillow ↔ NumPy
import numpy as np from PIL import Image # PIL → NumPy array img = Image.open("photo.jpg") arr = np.array(img) print(arr.shape) # (height, width, 3) for RGB # Apply NumPy operations inv = 255 - arr # invert all values # NumPy array → PIL Image result = Image.fromarray(inv.astype(np.uint8)) result.save("inverted.jpg")

PyTorch / torchvision

PyTorch uses Pillow as its default image loader. torchvision.transforms accepts PIL Images natively. When you load a dataset with torchvision.datasets.ImageFolder, Pillow does the heavy lifting under the hood.

torchvision Pipeline
from torchvision import transforms from PIL import Image preprocess = transforms.Compose([ transforms.Resize(256), # Pillow resize transforms.CenterCrop(224), # Pillow crop transforms.ToTensor(), # PIL → torch.Tensor [0,1] transforms.Normalize( mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] ) ]) pil_img = Image.open("photo.jpg") tensor = preprocess(pil_img) print(tensor.shape) # torch.Size([3, 224, 224])

OpenCV

OpenCV and Pillow use different colour channel orders. OpenCV is BGR, Pillow is RGB. You must convert when passing data between libraries.

Pillow ↔ OpenCV
import cv2 import numpy as np from PIL import Image # Pillow → OpenCV (RGB → BGR) pil_img = Image.open("photo.jpg") cv_img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) # OpenCV → Pillow (BGR → RGB) cv_img = cv2.imread("photo.jpg") pil_img = Image.fromarray(cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB))

Tkinter

Tkinter's native PhotoImage only supports GIF and PGM. Use ImageTk.PhotoImage from Pillow to display any image format in a Tkinter window.

Tkinter Display
import tkinter as tk from PIL import Image, ImageTk root = tk.Tk() img = Image.open("photo.jpg").resize((400, 300)) photo = ImageTk.PhotoImage(img) label = tk.Label(root, image=photo) label.pack() root.mainloop()

Qt (PyQt5 / PySide6)

Convert Pillow images to Qt's QImage via NumPy as an intermediate layer.

Pillow → QImage
from PyQt5.QtGui import QImage, QPixmap from PIL import Image import numpy as np img = Image.open("photo.jpg").convert("RGBA") data = np.array(img) h, w, ch = data.shape qimage = QImage(data.tobytes(), w, h, ch * w, QImage.Format_RGBA8888) pixmap = QPixmap.fromImage(qimage)