I am trying to make a pixel-art 2d platformer in Pygame-CE. When I use a standard pygame display, the pixels come out as blurry: Image upscaled to remove any filtering
Minimal Reproducible Example:
#Import everything
import pygame, sys
from pygame.locals import QUIT
#Pygame display setup
pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
#Load the image
grid_border = pygame.transform.scale(pygame.image.load('IMAGE.png'), (48, 48)).convert_alpha() #You will need to add your own 24x24 or 48x48 image or you can change the transform dimensions for other images.
#Main loop
while True:
#Quit if you press the x
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
#Fills the screen and then prints the image
screen.fill("white")
screen.blit(grid_border, (100, 100))
#Updates the screen and finishes the loop
pygame.display.flip()
clock.tick(60)
When I add this code after the pygame display setup to enable high DPI rendering on windows, the image is no longer blurry on the screen and loads at it's original resolution:
if sys.platform == 'win32':
# On Windows, the monitor scaling can be set to something besides normal 100%.
# PyScreeze and Pillow needs to account for this to make accurate screenshots.
# TODO - How does macOS and Linux handle monitor scaling?
import ctypes
try:
ctypes.windll.user32.SetProcessDPIAware()
except AttributeError:
pass # Windows XP doesn't support monitor scaling, so just do nothing.
This is what the screen looks like now: Image upscaled to remove filtering
However, this solution only works on Windows.
I looked at other pages to see if there were any existing solutions for this.
1. (https://github.com/pygame-community/pygame-ce/issues/1456) This page had the same issue as me and found the same solution as me - there is no way to enable high DPI rendering for pygame-ce on MacOS/Linux. However, this page was outdated by a few years so I am deciding to post the question again to see if there are any solutions now. Using the pygame.window class does not work in my situation due to a lack of vsync causing major screen tearing.
2. I looked at the official pygame docs. I could not find anything about high DPI rendering.
These are the only pages I could find that related to my question.
I am fine with any solution that removes the blurry rendering, not just solutions that enable high-DPI rendering on other platforms. I do, however, want the solution to work on all three major platforms (Windows, MacOS, Linux).
1 Answer 1
The problem there is in the asset. If you want a pixel-perfect display, you have to provide a pixel-perfect asset. Even for power of 2 scaling, it won't be able to "guess" if you want the scaled up version to retain the jagged pixel outline - it will assume you want interpolation to avoid sharp edges. That said, I believe the 'rotozoom" method (in contrast with scale) uses a different algorithm for scaling - try it instead, and see if you get satisfactory results - otherwise, go to an image editor, and handcraft your assets so you have different versions for the sizes you will use.
(In GIMP, for example, you can select no filter for scaling, preserving the pixels, and retouch what you need with the pencil tool, with a pixel-sized brush for pixel perfect images)
(600,600)
inpygame.transform.scale(..)
there is no blurry rendering at all. I am under Debian bookworm ona Pi5