Why is Pyglet adding random pixels to my window width/height?
Question:
Im trying to make a simple gif cropping programme using pyglet. It works perfectly on the first gif that gets loaded by the programme, in that the window is the exact size of the gif and the rectangle being used as the cropping shape draws precisely where the mouse clicks/drags/releases. As soon as I switch to the next or previous gif the window resize gets run twice, adding 16 pixels to the width and 39 to the height in the second round, which creates a black border on the top and right. When switching gifs im printing some of the width/height values to try to understand the problem, below is an example from pressing the right key once:
Window Resized to 363 by 284
363 363
284 284
Window Resized to 379 by 323
363 379
284 323
After this happens creating a rectangle shape doesnt happen precisely where the mouse clicks anymore (its offset somewhat). If I then try to resize the window manually by clicking and dragging the edges it ‘snaps back’ into place and removes the additional pixels + allows me to draw rectangles correctly. Ive been tearing my hair out trying to fix this to no avail. Ive included a couple screenshots and the code im using below.
First Gif
Second gif
import os
import pyglet
from pyglet import shapes
from datetime import datetime
from PIL import Image
# create a list of gif files in current folder
files = []
n = 0
for file in os.listdir():
if file[-4:] == ".gif":
files.append(file)
gif = pyglet.image.load_animation(files[n])
sprite = pyglet.sprite.Sprite(gif)
# create window as wide as gif
window = pyglet.window.Window(width = sprite.width, height = sprite.height, caption="My Pyglet Window", resizable=True)
#create a rectangle to crop with
rec = shapes.Rectangle(0, 0, 0, 0, color = (255,255,255,96))
@window.event
def on_draw():
window.clear()
sprite.draw()
rec.draw()
@window.event
def on_mouse_press(x, y, button, modifiers):
global rec
# dont do anything if inside rectabgle
if x >= rec.x and (x - rec.x) < rec.width and y > rec.y and (y - rec.y) < rec.height:
pass
# otherwise set the start point for a new rectangle
else:
rec = shapes.Rectangle(x, y, 0, 0, color = (255,255,255,96))
@window.event
def on_mouse_release(x, y, button, modifiers):
# if needed, convert the rectagle so that the origin is bottom left
if rec.width <0:
rec.x = rec.x - abs(rec.width)
rec.width = abs(rec.width)
if rec.height <0:
rec.y = rec.y - abs(rec.height)
rec.height = abs(rec.height)
@window.event
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
global rec
# If inside current rectangle, move it with the drag, moves the origin but maintains the size
if x >= rec.x and (x - rec.x) < rec.width and y > rec.y and (y - rec.y) < rec.height:
rec = shapes.Rectangle(rec.x + dx, rec.y + dy, rec.width, rec.height, color = (255,255,255,96))
return
# otherwise increase the rectangle
rec = shapes.Rectangle(rec.x, rec.y, x-rec.x, y-rec.y, color = (255,255,255,96))
# Do things when various keys pressed: next gif, previous gif, crop gif
@window.event
def on_key_press(symbol, modifier):
global files
global n
global sprite
global window
global rec
global sprite
# key "LEFT" get pressed go forward 1 gif
if symbol == pyglet.window.key.LEFT:
# check not trying to go outside list
if n - 1 >= 0:
n -= 1
gif = pyglet.image.load_animation(files[n])
sprite = pyglet.sprite.Sprite(gif)
window.set_size(width = sprite.width, height = sprite.height)
rec = shapes.Rectangle(0, 0, 0, 0, color = (255,255,255,96))
else:
print("Start of list")
# key "RIGHT" get pressed go back 1 gif
if symbol == pyglet.window.key.RIGHT:
# check not trying to go outside list
if n + 1 < len(files):
n += 1
gif = pyglet.image.load_animation(files[n])
sprite = pyglet.sprite.Sprite(gif)
window.set_size(width = sprite.width, height = sprite.height)
rec = shapes.Rectangle(0, 0, 0, 0, color = (255,255,255,96))
else:
print("End of List")
@window.event
def on_resize(width, height):
global sprite
print(f"Window Resized to {width} by {height}")
print(window.width, width)
print(window.height, height)
pyglet.app.run()
Answers:
Recommended Window sizes are received directly from the OS. For instance you can request 10000x10000x but it’s up the OS to return what dimensions it wants to give you. This also may include window borders, and titlebars.
That being said a resize can mess with the projection matrix.
Try this:
window = pyglet.window.Window()
def on_resize(w, h):
pyglet.gl.glViewport(0, 0, w, h)
window.projection = pyglet.math.Mat4.orthogonal_projection(0, w, 0, h, -255, 255)
window.on_resize = on_resize
Then call your window changes.
EDIT: After looking, there may be a bug in the built in on_resize
event, using the one above fixes the issue.
Im trying to make a simple gif cropping programme using pyglet. It works perfectly on the first gif that gets loaded by the programme, in that the window is the exact size of the gif and the rectangle being used as the cropping shape draws precisely where the mouse clicks/drags/releases. As soon as I switch to the next or previous gif the window resize gets run twice, adding 16 pixels to the width and 39 to the height in the second round, which creates a black border on the top and right. When switching gifs im printing some of the width/height values to try to understand the problem, below is an example from pressing the right key once:
Window Resized to 363 by 284
363 363
284 284
Window Resized to 379 by 323
363 379
284 323
After this happens creating a rectangle shape doesnt happen precisely where the mouse clicks anymore (its offset somewhat). If I then try to resize the window manually by clicking and dragging the edges it ‘snaps back’ into place and removes the additional pixels + allows me to draw rectangles correctly. Ive been tearing my hair out trying to fix this to no avail. Ive included a couple screenshots and the code im using below.
First Gif
Second gif
import os
import pyglet
from pyglet import shapes
from datetime import datetime
from PIL import Image
# create a list of gif files in current folder
files = []
n = 0
for file in os.listdir():
if file[-4:] == ".gif":
files.append(file)
gif = pyglet.image.load_animation(files[n])
sprite = pyglet.sprite.Sprite(gif)
# create window as wide as gif
window = pyglet.window.Window(width = sprite.width, height = sprite.height, caption="My Pyglet Window", resizable=True)
#create a rectangle to crop with
rec = shapes.Rectangle(0, 0, 0, 0, color = (255,255,255,96))
@window.event
def on_draw():
window.clear()
sprite.draw()
rec.draw()
@window.event
def on_mouse_press(x, y, button, modifiers):
global rec
# dont do anything if inside rectabgle
if x >= rec.x and (x - rec.x) < rec.width and y > rec.y and (y - rec.y) < rec.height:
pass
# otherwise set the start point for a new rectangle
else:
rec = shapes.Rectangle(x, y, 0, 0, color = (255,255,255,96))
@window.event
def on_mouse_release(x, y, button, modifiers):
# if needed, convert the rectagle so that the origin is bottom left
if rec.width <0:
rec.x = rec.x - abs(rec.width)
rec.width = abs(rec.width)
if rec.height <0:
rec.y = rec.y - abs(rec.height)
rec.height = abs(rec.height)
@window.event
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
global rec
# If inside current rectangle, move it with the drag, moves the origin but maintains the size
if x >= rec.x and (x - rec.x) < rec.width and y > rec.y and (y - rec.y) < rec.height:
rec = shapes.Rectangle(rec.x + dx, rec.y + dy, rec.width, rec.height, color = (255,255,255,96))
return
# otherwise increase the rectangle
rec = shapes.Rectangle(rec.x, rec.y, x-rec.x, y-rec.y, color = (255,255,255,96))
# Do things when various keys pressed: next gif, previous gif, crop gif
@window.event
def on_key_press(symbol, modifier):
global files
global n
global sprite
global window
global rec
global sprite
# key "LEFT" get pressed go forward 1 gif
if symbol == pyglet.window.key.LEFT:
# check not trying to go outside list
if n - 1 >= 0:
n -= 1
gif = pyglet.image.load_animation(files[n])
sprite = pyglet.sprite.Sprite(gif)
window.set_size(width = sprite.width, height = sprite.height)
rec = shapes.Rectangle(0, 0, 0, 0, color = (255,255,255,96))
else:
print("Start of list")
# key "RIGHT" get pressed go back 1 gif
if symbol == pyglet.window.key.RIGHT:
# check not trying to go outside list
if n + 1 < len(files):
n += 1
gif = pyglet.image.load_animation(files[n])
sprite = pyglet.sprite.Sprite(gif)
window.set_size(width = sprite.width, height = sprite.height)
rec = shapes.Rectangle(0, 0, 0, 0, color = (255,255,255,96))
else:
print("End of List")
@window.event
def on_resize(width, height):
global sprite
print(f"Window Resized to {width} by {height}")
print(window.width, width)
print(window.height, height)
pyglet.app.run()
Recommended Window sizes are received directly from the OS. For instance you can request 10000x10000x but it’s up the OS to return what dimensions it wants to give you. This also may include window borders, and titlebars.
That being said a resize can mess with the projection matrix.
Try this:
window = pyglet.window.Window()
def on_resize(w, h):
pyglet.gl.glViewport(0, 0, w, h)
window.projection = pyglet.math.Mat4.orthogonal_projection(0, w, 0, h, -255, 255)
window.on_resize = on_resize
Then call your window changes.
EDIT: After looking, there may be a bug in the built in on_resize
event, using the one above fixes the issue.