Working with Images
Sprites, Transparency & Assets
Flat shapes only get you so far. This module covers loading real image files, resizing and rotating them at runtime, handling transparency correctly, and organizing your growing asset folder before it becomes a mess.
Loading Images & Formats
pygame.image.load(path) reads an image file into a Surface object — the same kind of object your screen is. Once loaded, an image behaves exactly like anything you'd draw with pygame.draw: you position it and blit() (draw) it onto the screen.
player_img = pygame.image.load("assets/images/player.png").convert_alpha()
player_rect = player_img.get_rect(center=(400, 300))
# in the game loop, after screen.fill():
screen.blit(player_img, player_rect)
Always call .convert() (for opaque images) or .convert_alpha() (for images with transparency) right after loading. Pygame stores raw image files in whatever format they were saved in — converting matches the pixel format to your display, which can make blitting 10-40x faster.
| Format | Transparency | Best for |
|---|---|---|
| PNG | ✔ Yes (alpha) | Sprites, UI, anything with transparent edges |
| JPG | ✘ No | Full backgrounds, photos — never sprites |
| BMP | ✘ No | Legacy, rarely used — large file size |
Scaling, Rotating & Flipping
All transform operations live in pygame.transform and return a brand-new Surface — they never modify the original image, so you should cache the result rather than transforming every frame.
# Scale to an exact size (width, height)
big_img = pygame.transform.scale(player_img, (128, 128))
# Scale by a multiplier — keeps aspect ratio
zoomed = pygame.transform.scale_by(player_img, 2.0)
# Rotate by degrees, counter-clockwise
tilted = pygame.transform.rotate(player_img, 15)
# Flip: (surface, flip_x, flip_y)
mirrored = pygame.transform.flip(player_img, True, False) # face the other way
pygame.transform.rotate() every single frame (e.g. for a spinning object) is expensive. Pre-generate a list of rotated frames once at startup and cycle through them instead of rotating live.Transparency & the Alpha Channel
Transparency in Pygame comes in two flavors: colorkey transparency (one exact color becomes fully invisible — used for old-style images with no real alpha data) and true per-pixel alpha (each pixel has its own 0-255 opacity, stored in PNGs).
img.set_colorkey((255,0,255)) — makes that exact color invisible. Simple but gives hard, jagged edges..convert_alpha() preserves real per-pixel transparency from PNGs — smooth, soft edges.img.set_alpha(128) makes the ENTIRE image 50% see-through — great for fade-in/fade-out effects.Optimization & Organizing Assets
As a project grows past a handful of images, two habits save you hours of pain later:
assets/images/, assets/sounds/, assets/fonts/ separate from your code. Never hardcode a bare filename — always build the path from a shared ASSETS_DIR constant.pygame.image.load() inside the game loop — it's a disk read and will tank your frame rate.import os
import pygame
ASSETS_DIR = os.path.join(os.path.dirname(__file__), "assets", "images")
def load_image(filename, alpha=True):
path = os.path.join(ASSETS_DIR, filename)
img = pygame.image.load(path)
return img.convert_alpha() if alpha else img.convert()
IMAGES = {
"player": load_image("player.png"),
"enemy": load_image("enemy.png"),
"coin": load_image("coin.png"),
}
A Simple Sprite Preview Screen
Build a small screen that loads one image and lets arrow keys scale it up/down and rotate it, printing the current scale and angle to the console — a hands-on way to confirm you understand load → transform → blit before Module 6 introduces the full Sprite class.
A Transform Pipeline, Step by Step
Because every pygame.transform function returns a new Surface, transforms chain naturally: you can take the original image, scale it, rotate the scaled result, then flip that — each step building on the last, with the original left untouched.
scale_by() → rotate() → flip().