Related
I am writing a program that puts captions on the screen and I am using PIL because it has high-quality text that is way better than the default moviepy text. I currently can put the text on a black screen, I tried using a fully transparent image as a sort of hack but that didn't work. So if anyone knows how to put PIL text on an image, or up the quality of the default moviepy text, let me know, please. Here is my basic code to put white text on a black background:
import numpy as np
from moviepy.editor import *
from PIL import Image, ImageFont, ImageDraw
SIZE = (1280, 720)
DURATION = 2
FPS = 1
TEXT = "I am having a hard time"
FONT_SIZE = 100
TEXT_COLOR_HEX = "#ffffff"
FONT = "Amiri-Bold"
def create_PIL():
img = Image.new("RGB", size=SIZE)
#draw = ImageDraw.Draw(img)
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(f"../Fonts/UniNeue-Trial-Bold.ttf", size=FONT_SIZE)
draw.text((100, 100), TEXT, font=font, fill=TEXT_COLOR_HEX)
img = np.array(img)
return VideoClip(lambda t: img, duration=DURATION).set_fps(FPS)
final = concatenate_videoclips(
[create_PIL()]
)
final.write_videofile('./test.mp4')
I am trying to put this text onto a video, and I need to have custom start and duration times but all this does it put it on a black screen, which is what I expected but not what I want.
How can I add text on top of an image (i.e NOT INSIDE the image)?
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
img = Image.open("SAMPLE-IN.png")
draw = ImageDraw.Draw(img)
# font = ImageFont.truetype(<font-file>, <font-size>)
font = ImageFont.truetype("FONTS/arial.ttf", 36)
# draw.text((x, y),"Sample Text",(r,g,b))
draw.text((0,0),"Sample Text",(0,255,255),font=font)
img.save('sample-out.jpg')
You should create an image that is bigger than the original one, paste the first one and the text onto it, like this:
from PIL import Image, ImageFont, ImageDraw, ImageOps
img = Image.open("SAMPLE-IN.png")
img = ImageOps.expand(img, border=10, fill=(255,255,255))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("FONTS/arial.ttf", 36)
draw.text((0,0),"Sample Text",(0,255,255),font=font)
img.save('sample-out.jpg')
I receive a jpg sequence from network and wish to draw it on screen.
I want to use turtle to draw it but now I only know turtle accept gif as background image but not jpg.
#!/usr/bin/env python
import turtle
image = "demo.gif"
screen = turtle.Screen()
screen.addshape(image)
turtle.shape(image)
turtle.mainloop()
How can I draw jpg from byte array to turtle? Or any other better framework to show video sequence?
opencv can do it perfect!
#!/usr/bin/env python
import cv2
import numpy as np
import time
def openfile(filename):
fd = open("test.jpg","rb")
frame = fd.read()
frame = np.array(bytearray(frame))
fd.close()
frame = cv2.imdecode(frame, 1)
return frame
def openfile2(filename):
frame = cv2.imread(filename)
return frame
frame = openfile("test.jpg")
title = "jpeg"
cv2.namedWindow(title,cv2.WINDOW_AUTOSIZE);
cv2.imshow(title,frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
I'm working with Python 2.7.3 and PIL/Pillow and want to create text (with opacity) on an alpha_channel background saved as png. Here is my code which doesn't do exactly, what I was hoping:
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from PIL import ImageEnhance
width=854
height=480
opacity=0.8
text='copyright'
filename = 'result.png'
black = (0,0,0)
white = (255,255,255)
font = ImageFont.truetype('verdana.ttf',15)
wm = Image.new('RGBA',(width,height),white)
im = Image.new('L',(width,height),0)
draw = ImageDraw.Draw(wm)
w,h = draw.textsize(text, font)
draw.text(((width-w)/2,(height-h)/2),text,white,font)
en = ImageEnhance.Brightness(wm)
#en.putalpha(mask)
mask = en.enhance(1-opacity)
im.paste(wm,(25,25),mask)
im.save(filename)
Result:
The following code is what I'm looking for, but the background fully transparent/alpha_channel:
import PIL
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
width = 854
height = 480
black = (0,0,0)
text = "copyright"
white = (255,255,255)
font = ImageFont.truetype("Arial.ttf",40)
img = Image.new("RGBA", (width,height),white)
draw = ImageDraw.Draw(img)
w, h = draw.textsize(text, font)
draw.text(((width-w)/2,(height-h)/2),text,black,font=font)
draw = ImageDraw.Draw(img)
#img.putalpha
img.save("result.png")
#img.show
Result:
The problem is that wm has the same color as the text, so you won't see anything if you draw the text onto it. Change the color of wm to transparent, like I did below (and remove the commas after initializing of width, height and opacity):
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from PIL import ImageEnhance
width=854
height=480
opacity=0.8
text='copyright'
filename = 'result.png'
black = (0,0,0)
white = (255,255,255)
transparent = (0,0,0,0)
font = ImageFont.truetype('verdana.ttf',15)
wm = Image.new('RGBA',(width,height),transparent)
im = Image.new('RGBA',(width,height),transparent) # Change this line too.
draw = ImageDraw.Draw(wm)
w,h = draw.textsize(text, font)
draw.text(((width-w)/2,(height-h)/2),text,white,font)
en = ImageEnhance.Brightness(wm)
#en.putalpha(mask)
mask = en.enhance(1-opacity)
im.paste(wm,(25,25),mask)
im.save(filename)
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)