pyGame image scale does not work as expected - python

I am new into Python and pyGame and i have a problem with scaling an image.
I want to zoom an image in pygame.
The pygame documentation claims that
pygame.transform.scale()
should scale to a new resolution.
But in my example below it does not work - it crops the image instead of resizing it!?
What am i doing wrong?
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = pic.get_rect()
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, pic_position_and_size)
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.scale(pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()

pygame.transform.scale() does not work very well for your case. If you shrink a Surface by such a small amount, the algorithm just crops the last column and row of pixels. If you now repeat this process over and over again with the same Surface, you get the strange behaviour you see.
A better approach would be to keep a copy of your original Surface around, and use that for creating the scaled image. Also, using smoothscale instead of scale may also lead to a better effect; it's up to you if you want to use it.
Here's a "fixed" version of your code:
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
org_pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = org_pic.get_rect()
pic = pygame.transform.scale(org_pic, pic_position_and_size.size)
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, (0,0))
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.smoothscale(org_pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()

Related

How to 'blit' the image to the screen in Pygame

I'm making a game analyser, and I thought it would be nice if I had a user iterface instead of just using text and raw input to communicate. I am having problems with 'blitting' an image to my screen.
My image is inside the pycharm file called 'CATANYLISER' as is my code.
import pygame
pygame.init()
# py-game variables
(width, height) = (1000, 600)
window = pygame.display.set_mode((width, height))
window_title = pygame.display.set_caption('the CATANALYSER')
does_quit = False
# py-game images
empty_board = pygame.image.load('empty_board.png')
# py-game window loop
while not does_quit:
# receives input from window
for event in pygame.event.get():
# stops program when red x clicked
if event.type == pygame.QUIT:
does_quit = True
window.blit(empty_board, (0, 0))
pygame.display.update()
# activates when the loop finishes, just makes sure everything shuts down properly
pygame.quit()
The expected result is the image on the screen in the top left corner. However when I run the program, I have an empty screen (pygame.QUIT still works).
When I run this code there is no error message, and I am completely lost about how to fix this.
first, make sure that the empty_board.png is in your working directory.
Second, you have to clear the screen before each frame using window.fill([255, 255, 255])
Finally, you could try using pygame.display.flip() instead of update()
My code would look like:
import pygame
pygame.init()
window = pygame.display.set_mode([640, 480])
doQuit = False
board = pygame.image.load("empty_board.png")
while not doQuit:
window.fill([255, 255, 255])
window.blit(board, (0, 0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
doQuit = True
pygame.quit()

Load Updated Image Using Pygame

I am making a basic Mandelbrot zoom program using pygame that uses pillow to generate images each time a user zooms in. When this image is updated the pygame window simply loads the original image and not the updated one.
My current solution is to kill the pygame window with each zoom and reinitialize it which adds a fair amount of time to each zoom. Here is my current code
def pg_window(width, height):
pg.init()
fill_color = 255, 255, 255
window = pg.display.set_mode((width, height))
global set_image
set_img = pg.image.load('mandelbrot.png')
# The original load of the image
zoom_x = int(width * .15)
zoom_y = int(height * .15)
while True:
window.fill(fill_color)
... extra code ommitted ...
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
if event.type == pg.MOUSEBUTTONDOWN:
zoom(*zoom_rect.center, width, height, zoom_x, zoom_y)
# The zoom function call modifies the image directly.
set_image = pg.image.load('mandelbrot.png')
# changing the set_image variable just loads the original image, not the updated one
# My current solution involves calling pg.quit() here
# and recalling the pg_window function to reinitialize
window.fill(fill_color)
window.blit(set_img, (0, 0))
pg.display.flip()
Is there anyway to load an updated image without resetting the window?
The name of the image which is blit to the window is set_img rather than set_image.
So you've to set set_img:
while True:
window.fill(fill_color)
# [...]
for event in pg.event.get():
# [...]
if event.type == pg.MOUSEBUTTONDOWN:
# [...]
set_img = pg.image.load('mandelbrot.png') # <--- set_img
window.fill(fill_color)
window.blit(set_img, (0, 0))
pg.display.flip()

Pygame drawing not showing in Pygame window

So I was testing out pygame and I wanted to draw a simple rectangle. There are no error messages when I run the code but the rectangle doesn't show up in the window. What I see is a blank white Pygame window pop up. Does anyone know why?
Currently using Python3 and Pygame 1.9.4 on my mac.
Here is my code,
import pygame
import pygame.font
pygame.init()
# Colours
BLACK = ( 0, 0, 0)
WHITE = (255,255,255)
GREEN = ( 0,255, 0)
RED = (255, 0, 0)
BLUE = ( 0, 0,255)
# Dimensions of screen
size = (400,500)
WIDTH = 500
HEIGHT = 400
screen = pygame.display.set_mode(size)
# Loop Switch
done = False
# Screen Update Speed (FPS)
clock = pygame.time.Clock()
# ------- Main Program Loop -------
while not done:
# --- Main Event Loop ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
screen.fill(GREEN)
pygame.display.flip()
#Setting FPS
clock.tick(60)
#Shutdown
pygame.quit()
You do not want to fill the screen with green every 60 ticks
To fix this, simply put screen.fill(GREEN) outside of the Main loop.
The only time you want screen.fill inside your while loop, is when your adding movement into your program.
I strongly suggest you make a function called draw and draw things outside of your while loop.
I have found the problem:
first of, Glitchd is correct, but you forget to update:
import pygame
import pygame.font
pygame.init()
# Colours
BLACK = ( 0, 0, 0)
WHITE = (255,255,255)
GREEN = ( 0,255, 0)
RED = (255, 0, 0)
BLUE = ( 0, 0,255)
# Dimensions of screen
size = (400,500)
WIDTH = 500
HEIGHT = 400
screen = pygame.display.set_mode(size)
# Loop Switch
done = False
# Screen Update Speed (FPS)
clock = pygame.time.Clock()
# ------- Main Program Loop -------
while not done:
# --- Main Event Loop ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(GREEN)
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
pygame.display.flip()
pygame.display.update()
#Setting FPS
clock.tick(60)
#Shutdown
pygame.quit()
U are drawing a shape and then covering it up with green, swap
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
screen.fill(GREEN)
Those 2 around
The problem is that you draw the shape and after that you 'fill' (cover) it with green, so try something like that:
screen.fill(GREEN) #first fill the screen with green
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5) #and after that draw the rectangle
The error is obvious as first you are drawing a shape then covering it with color . Your code is right but need some rearrangement.
screen.fill("your color") # First you should fill the screen with color
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5) # Then u should draw any shape
Each of the previously given answers fail to properly elaborate why this issue occurs. It is not about the order of drawing, filling operations; it is about your timing on calling the pygame.display.flip function, or shortly: updating the screen. Your code draws a rectangle, fills the screen with green, and then updates the screen. What it should have done instead is draw the rectangle, update the screen and then fill the screen with green. That way the screen is updated after you draw the rectangle before the screen is filled with green, therefore you can see it:
import pygame
import pygame.font
pygame.init()
# Colours
BLACK = ( 0, 0, 0)
WHITE = (255,255,255)
GREEN = ( 0,255, 0)
RED = (255, 0, 0)
BLUE = ( 0, 0,255)
# Dimensions of screen
size = (400,500)
WIDTH = 500
HEIGHT = 400
screen = pygame.display.set_mode(size)
# Loop Switch
done = False
# Screen Update Speed (FPS)
clock = pygame.time.Clock()
# ------- Main Program Loop -------
while not done:
# --- Main Event Loop ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#In each case you draw the rectangle and then fill the screen with green
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
pygame.display.flip()
screen.fill(GREEN)
#Setting FPS
clock.tick(60)
#Shutdown
pygame.quit()
In a nutshell, you should update after you draw the rectangle.
you should add pygame.display.update() in the while not done loop. pygame.display.update updates the screen. You have this problem because you drew all of the drawings but did not update the screen.
You should first cover the screen with green and then draw your shape because otherwise it will get covered.

Pygame Rectangle and Mouse pos Collidepoint not working

I'm making a basic game where I have a surface and everytime I click on the surface it moves 5 pixels to the right. The program is working just fine without the checkCollide(event) function, but when I put the that condition it doesn't move. What is wrong?
My code until now is this
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300,300))
def checkCollide(event):
k = 0
a,b = event.pos
x = P1[0].get_rect()
if x.collidepoint(a,b):
return True
return False
CP1 = [(150, 150)
,(155, 150)
,(160, 150)
,(165, 150)
,(170, 150)
,(175, 150)
,(180, 150)
,(185, 150)
,(190, 150)]
statp1_1 = 0
WHITE = (255,255,255)
DISPLAYSURF.fill(WHITE)
while True: # the main game loop
P1 = [pygame.image.load('PAzul.png'),CP1[statp1_1],statp1_1]
DISPLAYSURF.blit(P1[0], P1[1])
e = pygame.event.get()
for event in e:
if event.type == MOUSEBUTTONUP:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
statp1_1 +=1
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Thank you
Check your logic in these lines of your function:
x = P1[0][0].get_rect()
if x.collidepoint(a,b):
return True
return False
Your code hinges on this bit:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
So you're never evaluating this piece to be true.
I just realized what was wrong. When I do x = P1[0].get_rect() it creates a surface with topleft at (0,0).
What I needed to do was change the position of the rectangle using x.topleft = P1[1]
I've got some tips for you. First store the rect in the P1 list (it contains only the image and the rect in the following example, but maybe you could also add the statp1_1 index to it). Now we can just move this rect, if the user clicks on it (in the example I set the topleft attribute to the next point). Read the comments for some more tips. One thing you need to fix is to prevent the game from crashing when the statp1_1 index gets too big.
import sys
import pygame
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300, 300))
WHITE = (255, 255, 255)
# Don't load images in your while loop, otherwise they have to
# be loaded again and again from your hard drive.
# Also, convert loaded images to improve the performance.
P1_IMAGE = pygame.image.load('PAzul.png').convert() # or .convert_alpha()
# Look up `list comprehension` if you don't know what this is.
CP1 = [(150+x, 150) for x in range(0, 41, 5)]
statp1_1 = 0
# Now P1 just contains the image and the rect which stores the position.
P1 = [P1_IMAGE, P1_IMAGE.get_rect(topleft=CP1[statp1_1])]
clock = pygame.time.Clock() # Use this clock to limit the frame rate.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONUP:
if P1[1].collidepoint(event.pos):
print('clicked')
statp1_1 += 1
# Set the rect.topleft attribute to CP1[statp1_1].
P1[1].topleft = CP1[statp1_1]
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(P1[0], P1[1]) # Blit image at rect.topleft.
pygame.display.update()
clock.tick(30) # Limit frame rate to 30 fps.

Resize image on mouse click in Pygame

This code displays an image and works:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((900,900))
lion = pygame.image.load("lion.jpg")
while true:
screen.blit(lion, (0,0))
pygame.display.update()
I also want be able to right click the image to adjust its size. For example:
pygame.event.get()
buttonpress = pygame.mouse.get_pressed()
press = pygame.key.get_pressed()
screen.blit(lion,(100-(lion.get_width()/2, 100-(lion.get_height()/2))))
pygame.event.quit
However, as soon as I click on the pygame window, it stops responding and I cannot do anything to it.
screen.blit() takes two arguments, surface and destination. It seems like you are trying to use it to resize your image. You could use pygame.transform.scale() which takes the surface and size arguments. For Example:
done = False
while not done:
for event in pygame.event.get():
if event.type == QUIT: #so you can close your window without it crashing or giving an error
done = True
pressed_buttons = pygame.mouse.get_pressed() #get a tuple of boolean values for the pressed buttons
if pressed_buttons[2]: #if the right mouse button is down
adjusted_lion_image = pygame.transform.scale(lion, (lion.get_wdith() / 2, lion.get_height() / 2)) #set the adjusted image to an image equal to half the size of the original image
else: #if the right mouse button is not down
adjusted_lion_image = lion #set the adjusted image back to the lion image
screen.fill((0, 0, 0)) #fill the screen with black before we draw to make it look cleaner
screen.blit(adjusted_lion_image, (0, 0)) #blit the adjusted image
pygame.display.update() #update the screen
pygame.quit() #make sure this is OUTSIDE of the while loop.
This should accomplish what you want. You also might want to add a .convert() after loading the lion image to convert the image to one pygame can use more readily:
lion = pygame.image.load("lion.jpg").convert()

Categories

Resources