英文:
Why is Pyglet adding random pixels to my window width/height?
问题
我正在尝试使用pyglet制作一个简单的gif裁剪程序。在程序加载的第一个gif上,它完美地工作,窗口的大小与gif的精确大小相同,并且用作裁剪形状的矩形在鼠标点击/拖动/释放的位置精确绘制。但一旦我切换到下一个或前一个gif,窗口调整大小操作会运行两次,第二轮会将宽度增加16像素,高度增加39像素,从而在顶部和右侧创建黑色边框。切换gif时,我正在打印一些宽度/高度值,以尝试理解问题,以下是按一次右箭头键的示例:
窗口大小调整为363 x 284
363 363
284 284
窗口大小调整为379 x 323
363 379
284 323
在发生这种情况后,矩形形状不再精确地出现在鼠标单击的位置(存在某种偏移)。然后,如果我尝试手动调整窗口大小,通过单击和拖动边缘,它会“回弹”回原位,并删除额外的像素,使我能够正确地绘制矩形。我已经试图解决这个问题,但一直无法成功。下面是我使用的一些代码以及一些屏幕截图。
第一个GIF
第二个GIF
import os
import pyglet
from pyglet import shapes
from datetime import datetime
from PIL import Image
# 在当前文件夹中创建一个gif文件列表
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)
# 创建与gif宽度相同的窗口
window = pyglet.window.Window(width=sprite.width, height=sprite.height, caption="My Pyglet Window", resizable=True)
# 创建一个用于裁剪的矩形
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
# 如果在矩形内部,则不执行任何操作
if x >= rec.x and (x - rec.x) < rec.width and y >= rec.y and (y - rec.y) < rec.height:
pass
# 否则设置新矩形的起始点
else:
rec = shapes.Rectangle(x, y, 0, 0, color=(255, 255, 255, 96))
@window.event
def on_mouse_release(x, y, button, modifiers):
# 如果需要,将矩形转换为以左下角为原点
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 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
# 否则增加矩形的大小
rec = shapes.Rectangle(rec.x, rec.y, x - rec.x, y - rec.y, color=(255, 255, 255, 96))
# 当按下各种键时执行不同操作:下一个gif,上一个gif,裁剪gif
@window.event
def on_key_press(symbol, modifier):
global files
global n
global sprite
global window
global rec
global sprite
# 按下“左箭头”键前进1个gif
if symbol == pyglet.window.key.LEFT:
# 检查不要超出列表范围
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("列表的开头")
# 按下“右箭头”键后退1个gif
if symbol == pyglet.window.key.RIGHT:
# 检查不要超出列表范围
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("列表的末尾")
@window.event
def on_resize(width, height):
global sprite
print(f"窗口大小调整为{width} x {height}")
print(window.width, width)
print(window.height, height)
pyglet.app.run()
希望这能帮助你解决你遇到的问题。
英文:
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()
答案1
得分: 0
推荐的窗口尺寸直接从操作系统中获取。例如,你可以请求10000x10000的尺寸,但最终的尺寸由操作系统决定,这可能包括窗口边框和标题栏。
话虽如此,调整窗口大小可能会影响投影矩阵。
尝试以下代码:
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
然后调用你的窗口变化。
编辑:经过检查,内置的on_resize
事件可能存在bug,使用上述代码可以解决这个问题。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论