I'm using Pyglet and I have a little that includes an object moving over a background. Both of them are represented by images (png and jpg).
I've created a non-fullscreen window with size 800x600 and it works fine, but when I toggle to fullscreen... background and object have the same size as before and the rest of the screen is filled with black (empty color).
What I want to do is to "scale" the images or change the resolution when I toggle fullscreen mode.
I've read the documentation, but I can't find the answer to this.
I know that with Pygame, this problem solves itself automatically (if you change the window size, everything rescales automatically)... but how do you do this with pyglet?
This is my relevant code:
import pyglet
WIDTH = 800
HEIGHT = 600
working_dir = '/where/i/have/my/images/'
window = pyglet.window.Window(WIDTH, HEIGHT)
background = pyglet.image.load(working_dir + 'background.jpg')
flying_thing = pyglet.image.load(working_dir + 'flying_thing.png')
#window.event
def on_draw():
window.clear()
background.blit(0, 0)
flying_thing.blit(WIDTH // 2, HEIGHT // 2)
#window.event
def on_key_press(symbol, modifiers):
if symbol == pyglet.window.key.SPACE:
window.set_fullscreen(not window.fullscreen)
pyglet.app.run()
You can try this code changing working_dir, background.jpg and flying_thing.png to a working directory of yours and two images in it.
I didn't tried, but from pyglet docs, blit supports width and height. Its signature is
blit(self, x, y, z=0, width=None, height=None)
Have you tried using
background.blit(width=window.width, height=windows.height)
instead? (I'm not sure the window.width changes on full_screen, let's see...).
This answer can also be relevant to your question: https://stackoverflow.com/a/11183462/931303.
Related
I am trying to screenshot a Microsoft Edge window using pywin32. This screenshot will then be used to a machine learning algorithm to play a game in Microsoft Edge. As you might guess, the program will be taking a screenshot multiple times, so I needed the screenshot to be fast as possible. To increase the speed, my program will resize the Microsoft Edge window to a small resolution (specifically, to 600 by 600). However, when the screenshot doesn't show the entire window even though I have moved it to a specified location.
My program:
import win32gui
import win32ui
import win32con
import win32api
from PIL import Image
import time
# grab a handle to the main desktop window
hdesktop = win32gui.GetDesktopWindow()
# determine the size of all monitors in pixels
width = 600
height = 600
left = 0
top = 0
# set window to correct location
print("You have 3 second to click the desired window!")
for i in range(3, 0, -1):
print(i)
time.sleep(1)
hwnd = win32gui.GetForegroundWindow()
win32gui.MoveWindow(hwnd, 0, 0, width, height, True)
# create a device context
desktop_dc = win32gui.GetWindowDC(hdesktop)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
# create a memory based device context
mem_dc = img_dc.CreateCompatibleDC()
# create a bitmap object
screenshot = win32ui.CreateBitmap()
screenshot.CreateCompatibleBitmap(img_dc, width, height)
mem_dc.SelectObject(screenshot)
# copy the screen into our memory device context
mem_dc.BitBlt((0, 0), (width, height), img_dc, (left, top),win32con.SRCCOPY)
bmpinfo = screenshot.GetInfo()
bmpstr = screenshot.GetBitmapBits(True)
im = Image.frombuffer(
'RGB',
(bmpinfo['bmWidth'], bmpinfo['bmHeight']),
bmpstr, 'raw', 'BGRX', 0, 1)
im.show()
# free our objects
mem_dc.DeleteDC()
win32gui.DeleteObject(screenshot.GetHandle())
My program first move and resizes the desired window (taken from win32gui.GetForegroundWindow()) by win32gui.MoveWindow(hwnd, 0, 0, width, height, True) Then, it tries to screenshot the window by taking the whole desktop window (hdesktop = win32gui.GetDesktopWindow() ) and then cropping it to the desired coordinates (mem_dc.BitBlt((0, 0), (width, height), img_dc, (left, top),win32con.SRCCOPY) ). I then convert the win32 screenshot to a PIL image so I could look at it. Note that the desired coordinates are the SAME coordinates used to move the window in the first place. However, when I try to run this program, the screenshot doesn't capture the entire window!
I have tried looking at the documentation of the MoveWindow and the BitBlt function, but I couldn't find the issue. The destination and source rectangle parameters is suppose to be (0,0), since of the MoveWindow function. The width and height parameters are the same. I also have tried experimenting with the bRepaint parameter, but it didn't make a difference.
Any Suggestions?
After experimenting with this question a little bit more, I finally found the problem.
In the comments, I said that ctypes.windll.shcore.SetProcessDpiAwareness(1) doesn't work. However, it did. When I upscale the height and width, then the dimensions between the screenshot and the window fits perfectly. However, the reason why width and height doesn't work for smaller dimensions (I was originally setting width and height to 500) is because Microsoft Edge doesn't allow it. If the width goes within a certain threshold, then the actual width of the window would go to the smallest width Microsoft Edge wants it to be. An easy work around was the set the width and height to a larger resolution, and it worked!
Thank you so much for everyone in the comments, especially #IInspectable.
So, couple hours ago I found Pyglet best for me for rendering gif animations, so I', new in this. My problem is that the animated gif renders at its original size in fullscreen window, I need to make it match, but I can't figure out how I should do this, any help? My code:
import sys
import pyglet
from pyglet.window import Platform
if len(sys.argv) > 1:
animation = pyglet.image.load_animation(sys.argv[1])
bin = pyglet.image.atlas.TextureBin()
animation.add_to_texture_bin(bin)
else:
animation = pyglet.resource.animation('gaben.gif')
sprite = pyglet.sprite.Sprite(animation)
screen = Platform().get_default_display().get_default_screen()
window = pyglet.window.Window(width=screen.width, height=screen.height)
window.set_fullscreen(True)
pyglet.gl.glClearColor(1, 1, 1, 1)
#window.event
def on_draw():
window.clear()
sprite.draw()
pyglet.app.run()
The result what I get
The easiest way is to use the sprite object's .scale.
It has the ability to scale the image in proportion to it's original dimensions and you don't need to worry about mapping data or filling in pixel-gaps if you resize the image yourself some how.
To help you get going, this is a simple example of a implementation:
(And it looks like this: https://youtu.be/Ly61VvTZnCU)
import pyglet
from pyglet.window import Platform
monitor = Platform().get_default_display().get_default_screen()
sprite = pyglet.sprite.Sprite(pyglet.resource.animation('anim.gif'))
H_ratio = max(sprite.height, monitor.height) / min(sprite.height, monitor.height)
W_ratio = max(sprite.width, monitor.width) / min(sprite.width, monitor.width)
sprite.scale = min(H_ratio, W_ratio) # sprite.scale = 2 would double the size.
# We'll upscale to the lowest of width/height
# to not go out of bounds. Whichever
# value hits the screen edges first essentially.
window = pyglet.window.Window(width=monitor.width, height=monitor.height, fullscreen=True)
pyglet.gl.glClearColor(1, 1, 1, 1)
#window.event
def on_draw():
window.clear()
sprite.draw()
pyglet.app.run()
I removed some of your code for demo/testing purposes.
The code is by no means perfect, but it will hopefully give you an insight as to how this works).
So i am making a game in python and pygame and i have the indow setup like this
display = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
which makes the size of the window about 1334 X 800 so i based all the sprites and backgrounds on that size of screen but as you know not everyone has the same sized screen as me so my question is how can i make images scale with how big the monitor screen is
(P.S The game is in fullscreen mode)
First, how do you get the resolution and the scaling factor?
This is tricky, because someone's screen may not have the same aspect ratio as your 1334x800. You can letterbox (in various different ways) or stretch the sprites; you need to decide what you want, but I'll show one letterboxing possibility:
NOMINAL_WIDTH, NOMINAL_HEIGHT = 1334., 800.
surface = display.get_surface()
width, height = surface.get_width(), surface.get_height()
xscale = width / NOMINAL_WIDTH
yscale = height / NOMINAL_HEIGHT
if xscale < 1 and yscale < 1:
scale = max(xscale, yscale)
elif xscale > 1 and yscale > 1:
scale = min(xscale, yscale)
else:
scale = 1.0
Now, how do you scale each sprite and background?
Well, first, are you sure you want to? It may be simpler to just transform the whole surface. Whether this is slower or faster is hard to predict without testing (and probably not relevant anyway), but it will definitely look better (because any interpolation, dithering, antialiasing, etc. happens after compositing, instead of before—unless you're going for that 8-bit look, of course, in which case it will destroy the look…). You can do this by compositing everything to an off-screen surface of 1334x800 (or, better, scaling everything up by a constant factor), then transforming that surface for display. (Note that the transform methods include an optional DestSurface argument. You can use this to directly transform from the offscreen surface to the display's surface.)
But let's assume you want to do it the way you asked.
You can do this when loading the sprites. For example:
def rescale(surf, scale):
new_width, new_height = surf.get_width() * scale, surf.get_height() * scale
return pygame.transform.smoothscale(surf, (new_width, new_height))
class ScaledSprite(pygame.sprite.Sprite):
def __init__(self, path, scale):
pygame.sprite.Sprite.__init__(self)
self.image = rescale(pygame.image.load(path), scale)
self.rect = self.image.get_rect()
And the same for the backgrounds.
from this SO question, you can get the size of the monitor with
infoObject = pygame.display.Info()
which gets the height and width of the screen as infoObject.current_w and infoObject.current_h
You can then use these values to scale everything appropriately.
I'm new to Pyglet (and stackoverflow) and cannot seem to find out how to resize images.
'pipe.png' is the image that I am trying to adjust the size of.
With this code, the image is not fully shown because the window size is too small.
I would like to adjust the size of the image so that it fits inside of the window.
The current size of 'pipe.png' is 100x576.
import pyglet
window = pyglet.window.Window()
pyglet.resource.path = ["C:\\"]
pipe = pyglet.resource.image('pipe.png')
pyglet.resource.reindex()
#window.event
def on_draw():
window.clear()
pipe.blit(0, 0)
pyglet.app.run()
EDIT:
I ended up finding out the answer here:
http://pyglet.org/doc-current/programming_guide/image.html#simple-image-blitting
The solution is:
imageWidth = 100
imageHeight = 100
imageName.width = imageWidth
imageName.height = imageHeight
This would adjust to image size to display as 100x100
Came across of this oldie, so for whoever lone ranger that ends up here juast as I did. Changing .width and .height won't do much in many cases (or at all these days?).
In order to successfully change a image resolution, you need to modify it's .scale attribute.
Here's a snippet of code that I use to resize a image:
from pyglet.gl import *
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
image = pyglet.image.load('test.png')
height, width = 800, 600 # Desired resolution
# the min() and max() mumbo jumbo is to honor the smallest requested resolution.
# this is because the smallest resolution given is the limit of say
# the window-size that the image will fit in, there for we can't honor
# the largest resolution or else the image will pop outside of the region.
image.scale = min(image.height, height)/max(image.height, height)), max(min(width, image.width)/max(width, image.width)
# Usually not needed, and should not be tampered with,
# but for a various bugs when using sprite-inheritance on a user-defined
# class, these values will need to be updated manually:
image.width = width
image.height = height
image.texture.width = width
image.texture.height = height
I'm new to pyglet. I'd like to change a pixel from black to white at each on_draw iteration. So after 1000 iterations, there should be exactly 1000 white pixels in the window. However, I'd like to avoid calling 1000 draw operations in on_draw for that. So I'd like to create an image, do an RGB putpixel on the image, and blit the image to the screen. How can I do that? The pyglet documentation, the examples and the source code aren't too helpful on this.
Since no one gave a really good answer to this.
I'll place one here:
import pyglet
from random import randint
width, height = 500, 500
window = pyglet.window.Window(width=width, height=height)
image = pyglet.image.SolidColorImagePattern((255,255,255,255)).create_image(width, height)
data = image.get_image_data().get_data('RGB', width*3)
new_image = b''
for i in range(0, len(data), 3):
pixel = bytes([randint(0,255)]) + bytes([randint(0,255)]) + bytes([randint(0,255)])
new_image += pixel
image.set_data('RGB', width*3, new_image)
#window.event
def on_draw():
window.clear()
image.blit(0, 0)
pyglet.app.run()
Essentially, what this does is it creates a white image, that in itself can be drawn in the window. But seeing as we want to do putpixel, i've modified every pixel in the white image as a demo.
Can be used in junction with:
https://pythonhosted.org/pyglet/api/pyglet.image.ImageData-class.html#get_region
Which can be used to optemize the image manipulation further.
This is too late to help you, but there are ways to do this. For example, blit_into, which modifies a loaded image:
import pyglet
window = pyglet.window.Window(600, 600)
background = pyglet.resource.image('my600x600blackbackground.bmp')
pix = pyglet.resource.image('singlewhitepixel.bmp').get_image_data()
def update(dt):
background.blit_into(pix, x, y, 0) #specify x and y however you want
#window.event
def on_draw():
window.clear()
background.blit(0,0)
pyglet.clock.schedule(update, 1.0/30) #30 frames per second
pyglet.app.run()
It seems there is no easy way to do this in pyglet. So I've given up on using pyglet.