HOWTO · Pygame

How to Scale Images in Pygame

Learn how to load and scale images in Pygame with pygame.transform.scale() and pygame.transform.scale2x(), preserve proportions, and resize in response to user input.

On this page

To resize an image in Pygame, pass its surface and the target (width, height) to pygame.transform.scale(). The function returns a new surface with those dimensions. Use a shared scale factor for proportional resizing, or update the factor when input or game state changes. (pygame.transform.scale2x())

Load an image in Pygame

pygame.image.load() reads an image file and returns a Surface, which you can pass to a transform and draw with screen.blit(). Create the display before calling convert() or convert_alpha() to match the surface to that display. Use convert_alpha() when the image needs per-pixel transparency, and keep the original surface so later resizes do not compound earlier scaling.

For example, load a project asset with image = pygame.image.load("assets/ship.png").convert_alpha(). Replace the path with the location of your own image; the file must be available when the program runs.

Scale an image to a specific size

Call pygame.transform.scale(image, (400, 300)) to request a 400-by-300 surface. The width and height are independent: if that pair has a different aspect ratio from the source, the image will stretch or compress. Choose dimensions with the same ratio when the shape must stay unchanged.

For pixel art that should become exactly twice as wide and tall, pygame.transform.scale2x(image) is a concise option. It doubles each dimension and is useful when that two-times size suits the layout; it is not a general replacement for choosing arbitrary dimensions with pygame.transform.scale().

Scale an image proportionally

Start with the original surface dimensions and multiply both by the same factor. Convert the calculated dimensions to integers before passing them to pygame.transform.scale(). To fit an image inside a box without changing its shape, use the smaller ratio of the available width to source width and available height to source height. This keeps the scaled surface within both limits.

For example, if the source is 640 by 400 and the maximum box is 320 by 240, the limiting factor is min(320 / 640, 240 / 400), or 0.5. The resulting dimensions are 320 by 200. Calculate from the original dimensions each time so repeated changes do not progressively reduce detail.

Resize an image dynamically

A game can change a scale factor in response to keys, a zoom setting, or another game-state value. Calculate each requested size from the original surface so earlier transforms do not affect later ones. This standalone example shows the dimension calculation for an image that is 48 by 32 pixels; it uses only Python’s standard library.

original_size = (48, 32)
scale_factor = 2.0
scaled_size = tuple(int(dimension * scale_factor) for dimension in original_size)
print(f"Scaled size: {scaled_size[0]} x {scaled_size[1]}")
Scaled size: 96 x 64

In a Pygame loop, use the calculated dimensions in pygame.transform.scale(original, scaled_size), draw the returned surface with screen.blit(), and update the display. Handle pygame.QUIT to leave the loop, then call pygame.quit() during shutdown. When a key changes the factor, recalculate the surface once and reuse it on other frames. For a continuously changing size, compare the requested dimensions with the previous size before transforming. Scaling repeatedly can add work, so cache and reuse transformed surfaces for sizes used often; no performance measurement is implied here.

This complete example creates a small surface in code, so it has no image-file prerequisite. It handles window events and the + and - keys, and uses one frame so the sample also exits on its own. In a game, remove the frame limit to keep the window open; replace the generated surface with one returned by pygame.image.load().

import os

os.environ.setdefault("SDL_VIDEODRIVER", "dummy")
os.environ.setdefault("SDL_AUDIODRIVER", "dummy")

import pygame

pygame.display.init()
try:
    screen = pygame.display.set_mode((320, 240))
    original = pygame.Surface((48, 32), pygame.SRCALPHA)
    original.fill((40, 150, 220, 255))
    pygame.draw.rect(original, (245, 210, 60, 255), (8, 8, 32, 16))

    scale_factor = 2.0
    scaled = pygame.transform.scale(
        original,
        (int(original.get_width() * scale_factor), int(original.get_height() * scale_factor)),
    )
    running = True
    frame_count = 0

    while running and frame_count < 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_PLUS, pygame.K_EQUALS):
                    scale_factor += 0.25
                elif event.key == pygame.K_MINUS:
                    scale_factor = max(0.25, scale_factor - 0.25)
                else:
                    continue

                size = (
                    int(original.get_width() * scale_factor),
                    int(original.get_height() * scale_factor),
                )
                scaled = pygame.transform.scale(original, size)

        screen.fill((30, 30, 30))
        screen.blit(scaled, (20, 20))
        pygame.display.flip()
        frame_count += 1
finally:
    pygame.display.quit()
    pygame.quit()