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
First Gif

Second 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()
Asked By: HJOEUser

||

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.

Answered By: Charlie
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.