How to scale images to screen size in Pygame
Asked Answered
E

5

52

I was wondering how I would go about scaling the size of images in pygame projects to the resolution of the screen. For example, envisage the following scenario assuming windowed display mode for the time being; I assume full screen will be the same:

  • I have a 1600x900 background image which of course displays natively in a 1600x900 window

  • In a 1280x720 window I can obviously just scale this images' rect to 1280x720

  • What happens, however if I need to add, say a 300x300 px image at x,y 1440,860 (example sizes) that is sized to fit with the original 1600x900 background? Of course for the 1600x900 I can of course use the image natively but what about the smaller/larger window sizes?

How do I scale images to the window size and then position them accordingly? I guess there must be a REALLY easy automated method but right now I can't figure it out.

Efflux answered 15/11, 2013 at 13:31 Comment(0)
B
103

You can scale the image with pygame.transform.scale:

import pygame
picture = pygame.image.load(filename)
picture = pygame.transform.scale(picture, (1280, 720))

You can then get the bounding rectangle of picture with

rect = picture.get_rect()

and move the picture with

rect = rect.move((x, y))
screen.blit(picture, rect)

where screen was set with something like

screen = pygame.display.set_mode((1600, 900))

To allow your widgets to adjust to various screen sizes, you could make the display resizable:

import os
import pygame
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((500, 500), HWSURFACE | DOUBLEBUF | RESIZABLE)
pic = pygame.image.load("image.png")
screen.blit(pygame.transform.scale(pic, (500, 500)), (0, 0))
pygame.display.flip()
while True:
    pygame.event.pump()
    event = pygame.event.wait()
    if event.type == QUIT:
        pygame.display.quit()
    elif event.type == VIDEORESIZE:
        screen = pygame.display.set_mode(
            event.dict['size'], HWSURFACE | DOUBLEBUF | RESIZABLE)
        screen.blit(pygame.transform.scale(pic, event.dict['size']), (0, 0))
        pygame.display.flip()
Beverly answered 15/11, 2013 at 13:33 Comment(2)
OK I get that but if the background image has scaled from say 1600x900 to 1280x720 and a image for say a button from 300x300 to something relative to 1280x720-1600x900 then how I would I work out where the button should be placed on the smaller window? Because obviously 600 pixels down say on a 1280x720 display is more than on a 1280x900 screen, relatively speaking.Efflux
Do you mean how to adjust it for a different aspect ratio? You would have to calculate the aspect ratio itself and multiply every size value by its factor.Ronaronal
T
9

If you scale 1600x900 to 1280x720 you have

scale_x = 1280.0/1600
scale_y = 720.0/900

Then you can use it to find button size, and button position

button_width  = 300 * scale_x
button_height = 300 * scale_y

button_x = 1440 * scale_x
button_y = 860  * scale_y

If you scale 1280x720 to 1600x900 you have

scale_x = 1600.0/1280
scale_y = 900.0/720

and rest is the same.


I add .0 to value to make float - otherwise scale_x, scale_y will be rounded to integer - in this example to 0 (zero) (Python 2.x)

Trix answered 15/11, 2013 at 14:51 Comment(1)
is there any reason to not use pygame.transform.scale?Mosora
I
5

Scaling the background to the size of the window can easily be done with pygame.transform.scale() lor smoothscale. e.g.:

import pygame

pygame.init()
window = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()

background = pygame.image.load('sky.png').convert()
background = pygame.transform.smoothscale(background, window.get_size())

run = True
while run:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.blit(background, (0, 0))
    pygame.display.flip()

pygame.quit()
exit()

However, this does not take into account the aspect ratio of the background. To fit the window into the background, you need to compare the width and height ratio and scale the image by the minimum ratio.
The following function scales an image to the desired size, but retains the aspect ratio. The function returns the scaled image and a rectangle indicating the position of the scaled image in the center of the area:

def transformScaleKeepRatio(image, size):
    iwidth, iheight = image.get_size()
    scale = min(size[0] / iwidth, size[1] / iheight)
    new_size = (round(iwidth * scale), round(iheight * scale))
    scaled_image = pygame.transform.smoothscale(image, new_size) 
    image_rect = scaled_image.get_rect(center = (size[0] // 2, size[1] // 2))
    return scaled_image, image_rect

If you want to fill the entire window with the background, keeping the aspect ratio but cropping the sides of the background, just replace min with max.

scale = min(size[0] / iwidth, size[1] / iheight)

scale = max(size[0] / iwidth, size[1] / iheight)

Minimal example

import pygame

def transformScaleKeepRatio(image, size):
    iwidth, iheight = image.get_size()
    scale = min(size[0] / iwidth, size[1] / iheight)
    #scale = max(size[0] / iwidth, size[1] / iheight)
    new_size = (round(iwidth * scale), round(iheight * scale))
    scaled_image = pygame.transform.smoothscale(image, new_size) 
    image_rect = scaled_image.get_rect(center = (size[0] // 2, size[1] // 2))
    return scaled_image, image_rect

pygame.init()
window = pygame.display.set_mode((300, 300), pygame.RESIZABLE)
clock = pygame.time.Clock()

background = pygame.image.load('parrot.png').convert_alpha()
scaled_bg, bg_rect = transformScaleKeepRatio(background, window.get_size())

run = True
while run == True:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

        elif event.type == pygame.VIDEORESIZE:
            window = pygame.display.set_mode(event.size, pygame.RESIZABLE)
            scaled_bg, bg_rect = transformScaleKeepRatio(background, window.get_size())

    window.fill((127, 127, 127))
    window.blit(scaled_bg, bg_rect)
    pygame.display.flip()

pygame.quit()
exit()
Interfertile answered 17/8, 2022 at 8:9 Comment(0)
G
2

i do not know if you meant this, but this is how to scale to the size of the screen an image at the max that is possible, without losing the aspect ratio of the image among width and height

row = pygame.image.load(f"{image}")
x, y = row.get_size()
rx = 1000 / x
ry = 600 / y
print(rx)
print(ry)
ratio = rx if rx < ry else ry
row = pygame.transform.scale(row, (int(x*rx), int(y*rx)))
Golliner answered 14/4, 2021 at 17:27 Comment(0)
A
0

Here's a recipe that allows scaling image to screen so that it maintains aspect ratio and never extends outside the screen.

screen_resolution = (1920, 1080)
image_path = '/path/to/image.png'
center_image = True
image = pygame.image.load(image_path)

screen_w, screen_h = screen_resolution
image_w, image_h = image.get_size()

screen_aspect_ratio = screen_w / screen_h
photo_aspect_ratio = image_w / image_h

if screen_aspect_ratio < photo_aspect_ratio:  # Width is binding
    new_image_w = screen_w
    new_image_h = int(new_image_w / photo_aspect_ratio)
    image = pygame.transform.scale(image, (new_image_w, new_image_h))
    image_x = 0
    image_y = (screen_h - new_image_h) // 2 if center_image else 0

elif screen_aspect_ratio > photo_aspect_ratio:  # Height is binding
    new_image_h = screen_h
    new_image_w = int(new_image_h * photo_aspect_ratio)
    image = pygame.transform.scale(image, (new_image_w, new_image_h))
    image_x = (screen_w - new_image_w) // 2 if center_image else 0
    image_y = 0

else:  # Images have the same aspect ratio
    image = pygame.transform.scale(image, (screen_w, screen_h))
    image_x = 0
    image_y = 0

display.blit(image, (image_x, image_y))
Alexine answered 14/5, 2021 at 1:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.