Python Pyglet, new sprites in batch - python

Python, pyglet
I want to add sprites to my window after it was drawn.
i try to use batch, becouse i want to to have lot of sprites.
my simple testing code is:
import pyglet
import random
from pyglet.window import key, mouse
from pyglet import image
from PIL import Image, ImageDraw, ImageFont
#function return pyglet image 10x10px triangle, random color. Instead of loading a file, work fine
def pyimg():
background = Image.new('RGBA', (10,10), (255,255,255,0) )
img = Image.new('RGBA', (10,10), (0,0,0,0) )
draw = ImageDraw.Draw(img)
draw.polygon([(0,0), (0,10), (10,0)], fill=(random.randint(0,255),random.randint(0,255),random.randint(0,255)))
im= Image.alpha_composite(background, img)
return pyglet.image.ImageData(im.width, im.height, 'RGBA', im.tobytes(), pitch=-im.width * 4)
screenWidth=1280
window = pyglet.window.Window(screenWidth, 720, resizable=True)
batch=pyglet.graphics.Batch()
sprites=[]
sprites.append(pyglet.sprite.Sprite(pyimg(), x=50, y=50, batch=batch))
sprites.append(pyglet.sprite.Sprite(pyimg(), x=150, y=50, batch=batch))
i=30
#window.event
def on_draw():
window.clear()
batch.draw()
#window.event
def on_key_press(symbol, modifiers):
global i
if symbol == key.RETURN:
print("Return key pressed")
sprites.append(pyglet.sprite.Sprite(pyimg(), x=150+i, y=50))
i+=15
pyglet.app.run()
App displays two sprites, and should add one more after enter key pressed. How to update display?

This line: sprites.append(pyglet.sprite.Sprite(pyimg(), x=150+i, y=50)) you aren't specifying the batch to add sprites into.
It needs to be sprites.append(pyglet.sprite.Sprite(pyimg(), x=150+i, y=50, batch=batch))

Related

Pyglet render into texture

I'm writing a drawing program using pyglet, and I want to be able to have the image being created as separate from the window's buffer (for instance, the image could be larger than the window, or may want to draw to this image at a different rate than the main window is being re-drawn). I want to be able to draw into this off-screen image, then display it in the window, but pyglet doesn't allow drawing to anything else than a window. Is there any simple way I can do this?
I've tried creating a second hidden pyglet window, but this gets rendered at the same rate as the main window which I definitely don't want.
The closest I found was Pyglet draw text into texture, but the code there isn't complete, and also no longer works as the opengl version used by pyglet has moved on.
The following code works for me, perhaps someone else can improve on my answer:
import pyglet
from pyglet.gl import *
from ctypes import byref
W, H = 800, 600
image = pyglet.image.create(W, H)
texture = image.get_texture()
window = pyglet.window.Window(width=W, height=H)
fbo_id = gl.GLuint(0)
glGenFramebuffers(1, byref(fbo_id))
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
glBindTexture(GL_TEXTURE_2D, texture.id)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0)
rect1 = pyglet.shapes.Rectangle(0, 0, W, H, (255, 0, 0) )
rect2 = pyglet.shapes.Rectangle(W//4, H//4, W//2, H//2, (0, 0, 255) )
label = pyglet.text.Label("Hello World", font_name="Times New Roman", font_size=36,
x=W//2, y=H//2, anchor_x="center", anchor_y="center")
rect1.draw()
rect2.draw()
label.draw()
#window.event
def on_mouse_drag(x, y, dx, dy, xxx, modifiers):
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
line = pyglet.shapes.Line(x-dx, y-dy, x, y, 3, (0, 255, 255))
line.draw()
#window.event
def on_draw():
glBindFramebuffer(GL_FRAMEBUFFER, 0)
window.clear()
texture.blit(0, 0)
pyglet.app.run()

Python Pyglet Problem (cords of the sprite)

(I am not english. Hope you understand.)
Hi, I'm trying to move my "start_button" sprite to x = 150, but it'll duplicate it.
Here's the code:
import pyglet
window = pyglet.window.Window()
window.clear()
#ON_TEXT
def ontext(txt):
start_button.x = 150
#INTERVAL
def interval(int):
print("Running")
pyglet.clock.schedule_interval(interval, 1/30)
#SPRITES
def paint():
start_button.draw()
start_button_pic = pyglet.image.load("start_button.png")
start_button = pyglet.sprite.Sprite(start_button_pic)
#PUSH_HANDLERS
window.push_handlers(
on_text=ontext,
on_draw=paint,
)
pyglet.app.run()
print("Done")
Thanks for answers!
Andrew
You need to clear the window, before drawing the sprite:
def paint():
window.clear()
start_button.draw()
The clear method clears the color and depth buffer (see pyglet.window). Actually, the sprite is not duplicated, but the sprite drawn in the previous frames is still there because the color buffer was never cleared.

Add lable, textbox and button to tkinter canvas

How to add a label, textbox and button to a program in which an image is display using tkinter canvas. In this program, an image is displayed to user. Lines are drawn over image on mouse click at different position. I want to add a textbox and a button, so that user can enter name for the object drawn using mouse clicks. For example, Enter label: textboxforinputname__Button to enter.
from Tkinter import *
import Image, ImageTk, ImageDraw
import numpy as np
coord=[] # for saving coord of each click position
Dict_Polygon={} # Dictionary for saving polygon
list_of_points=[]
flag=True
label=0
def draw_lines(event):
mouse_xy = (event.x, event.y)
func_Draw_lines(mouse_xy)
def func_Draw_lines(mouse_xy):
center_x, center_y = mouse_xy
if canvas.old_coords:
x1, y1 = canvas.old_coords
canvas.create_line(center_x, center_y, x1, y1)
# add clicked positions to list
if flag==True:
list_of_points.append(mouse_xy)
canvas.old_coords = center_x, center_y
# Main function
if __name__ == '__main__':
root = Tk()
# Input image
img = Image.open("test.jpg")
# Draw canvas for iput image to pop up image for clicks
filename = ImageTk.PhotoImage(img)
canvas = Canvas(root,height=img.size[0],width=img.size[0])
canvas.image = filename
canvas.create_image(0,0,anchor='nw',image=filename)
canvas.pack()
canvas.old_coords = None
# bind function to canvas to generate event
canvas.bind("<Button 3>", draw_lines)
root.mainloop()

Image import issue with pygame

So this program is supposed to just put a sprite on screen. But the image is not importing right. I made sure the image has no background, but in the program, part of the background turns black while the other half stays transparent. Its really weird.
heres my code:
from Tkinter import *
import pygame
from livewires import games
#Creating screen window
games.init(screen_width = 700, screen_height = 650, fps = 50)
#creating background image for the screen
screen_background = games.load_image('resized_stars background.png', transparent = False)
games.screen.background = screen_background
#Creating a sprite
spaceship_image = games.load_image('8-bit_Spaceship.png')
spaceship = games.Sprite(image = spaceship_image, x=350, y=235)
games.screen.add(spaceship)
#main loop at the end of the program just as in tkinter
games.screen.mainloop()
Why will it not show up on screen properly?
Here's what I use, and it works just fine:
First, create the screen:
screen = pygame.display.set_mode((screen width, screen height))
Then:
spaceship = pygame.image.load("direct it to the image")
An example of directing it to the image would be "C:/PythonFolder/spaceship.png"
I see you just put the name of the file.
Then, when you're ready to blit (append) it to the screen, use
screen.blit(spaceship, (x location, y location))
Then update it:
pygame.display.update()
or:
pygame.display.flip()

How can I convert canvas content to an image?

from Tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
root.mainloop()
I want to convert canvas content to a bitmap or other image, and then do other operations, such as rotating or scaling the image, or changing its coordinates.
Bitmaps can improve efficiency to show if I am no longer drawing.
What should I do?
You can either generate a postscript document (to feed into some other tool: ImageMagick, Ghostscript, etc):
from Tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
root.mainloop()
cv.update()
cv.postscript(file="file_name.ps", colormode='color')
root.mainloop()
or draw the same image in parallel on PIL and on Tkinter's canvas (see: Saving a Tkinter Canvas Drawing (Python)). For example (inspired by the same article):
from Tkinter import *
import Image, ImageDraw
width = 400
height = 300
center = height//2
white = (255, 255, 255)
green = (0,128,0)
root = Tk()
# Tkinter create a canvas to draw on
cv = Canvas(root, width=width, height=height, bg='white')
cv.pack()
# PIL create an empty image and draw object to draw on
# memory only, not visible
image1 = Image.new("RGB", (width, height), white)
draw = ImageDraw.Draw(image1)
# do the Tkinter canvas drawings (visible)
cv.create_line([0, center, width, center], fill='green')
# do the PIL image/draw (in memory) drawings
draw.line([0, center, width, center], green)
# PIL image can be saved as .png .jpg .gif or .bmp file (among others)
filename = "my_drawing.jpg"
image1.save(filename)
root.mainloop()
I have found a great way of doing this which is really helpful. For it, you need the PIL module. Here is the code:
from PIL import ImageGrab
def getter(widget):
x=root.winfo_rootx()+widget.winfo_x()
y=root.winfo_rooty()+widget.winfo_y()
x1=x+widget.winfo_width()
y1=y+widget.winfo_height()
ImageGrab.grab().crop((x,y,x1,y1)).save("file path here")
What this does is you pass a widget name into the function. The command root.winfo_rootx() and the root.winfo_rooty() get the pixel position of the top left of the overall root window.
Then, the widget.winfo_x() and widget.winfo_y() are added to, basically just get the pixel coordinate of the top left hand pixel of the widget which you want to capture (at pixels (x,y) of your screen).
I then find the (x1,y1) which is the bottom left pixel of the widget. The ImageGrab.grab() makes a printscreen, and I then crop it to only get the bit containing the widget. Although not perfect, and won't make the best possible image, this is a great tool for just getting a image of any widget and saving it.
If you have any questions, post a comment! Hope this helped!
Use Pillow to convert from Postscript to PNG
from PIL import Image
def save_as_png(canvas,fileName):
# save postscipt image
canvas.postscript(file = fileName + '.eps')
# use PIL to convert to PNG
img = Image.open(fileName + '.eps')
img.save(fileName + '.png', 'png')
Maybe you can try to use widget_winfo_id to get the HWND of the canvas.
import win32gui
from PIL import ImageGrab
HWND = canvas.winfo_id() # get the handle of the canvas
rect = win32gui.GetWindowRect(HWND) # get the coordinate of the canvas
im = ImageGrab.grab(rect) # get image of the current location
A better way for #B.Jenkins's answer that doesn't need a reference to the root object:
from PIL import ImageGrab
def save_widget_as_image(widget, file_name):
ImageGrab.grab(bbox=(
widget.winfo_rootx(),
widget.winfo_rooty(),
widget.winfo_rootx() + widget.winfo_width(),
widget.winfo_rooty() + widget.winfo_height()
)).save(file_name)
On my system had serious issues with ghostscript and the ImageGrab in general. Solution draw on PIL Image, save as a file, load file on PhotoImage, which is used to create new TKinter Canvas.
canvas = Canvas(win, width=IMG_W, height=IMG_H)
img = PILImg.new("RGB", (IMG_W, IMG_H), "#000")
draw = ImageDraw.Draw(img)
draw.rectangle([x,y,w,h], fill=color, outline=border)
img.save("stock-chart.png")
copyImg = PhotoImage(file="stock-chart.png")
canvas.create_image(IMG_W_2, IMG_H_2, image=copyImg)

Categories