Created
February 18, 2017 22:02
-
-
Save Zulko/e072d78dd5dbd2458f34d2166265e081 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
An alternative text clip for Moviepy, relying on Gizeh instead of ImageMagick | |
Advantages: | |
- Super fast (20x faster) | |
- no need to install imagemagick | |
- full-vector graphic, no aliasing problems | |
- Easier font names | |
Disadvantages: | |
- Requires Cairo installed | |
- Doesnt support kerning (=letters spacing) | |
""" | |
try: | |
import gizeh as gz | |
GIZEH_AVAILABLE = True | |
except ImportError: | |
GIZEH_AVAILABLE = False | |
import numpy as np | |
from moviepy.editor import ImageClip | |
def autocrop(np_img): | |
"""Return the numpy image without empty margins.""" | |
if len(np_img.shape) == 3: | |
if np_img.shape[2] == 4: | |
thresholded_img = np_img[:,:,3] # use the mask | |
else: | |
thresholded_img = np_img.max(axis=2) # black margins | |
zone_x = thresholded_img.max(axis=0).nonzero()[0] | |
xmin, xmax = zone_x[0], zone_x[-1] | |
zone_y = thresholded_img.max(axis=1).nonzero()[0] | |
ymin, ymax = zone_y[0], zone_y[-1] | |
return np_img[ymin:ymax+1, xmin:xmax+1] | |
def text_clip(text, font_family, align='left', | |
font_weight='normal', font_slant='normal', | |
font_height = 70, font_width = None, | |
interline= None, fill_color=(0,0,0), | |
stroke_color=(0, 0, 0), stroke_width=2, | |
bg_color=None): | |
"""Return an ImageClip displaying a text. | |
Parameters | |
---------- | |
text | |
Any text, possibly multiline | |
font_family | |
For instance 'Impact', 'Courier', whatever is installed | |
on your machine. | |
align | |
Text alignment, either 'left', 'center', or 'right'. | |
font_weight | |
Either 'normal' or 'bold'. | |
font_slant | |
Either 'normal' or 'oblique'. | |
font_height | |
Eight of the font in pixels. | |
font_width | |
Maximal width of a character. This is only used to | |
create a surface large enough for the text. By | |
default it is equal to font_height. Increase this value | |
if your text appears cropped horizontally. | |
interline | |
number of pixels between two lines. By default it will be | |
stroke_width | |
Width of the letters' stroke in pixels. | |
stroke_color | |
For instance (0,0,0) for black stroke or (255,255,255) | |
for white. | |
fill_color=(0,0,0), | |
For instance (0,0,0) for black letters or (255,255,255) | |
for white. | |
bg_color | |
The background color in RGB or RGBA, e.g. (255,100,230) | |
(255,100,230, 128) for semi-transparent. If left to none, | |
the background is fully transparent | |
""" | |
if not GIZEH_AVAILABLE: | |
raise ImportError("`text_clip` requires Gizeh installed.") | |
stroke_color = np.array(stroke_color)/255.0 | |
fill_color = np.array(fill_color)/255.0 | |
if bg_color is not None: | |
np.array(bg_color)/255.0 | |
if font_width is None: | |
font_width = font_height | |
if interline is None: | |
interline = 0.3 * font_height | |
line_height = font_height + interline | |
lines = text.splitlines() | |
max_line = max(len(l) for l in lines) | |
W = int(max_line * font_width + 2 * stroke_width) | |
H = int(len(lines) * line_height + 2 * stroke_width) | |
surface = gz.Surface(width=W, height=H, bg_color=bg_color) | |
xpoint = { | |
'center': W/2, | |
'left': stroke_width + 1, | |
'right': W - stroke_width - 1 | |
}[align] | |
for i, line in enumerate(lines): | |
ypoint = (i+1) * line_height | |
text_element = gz.text(line, fontfamily=font_family, fontsize=font_height, | |
h_align=align, v_align='top', | |
xy=[xpoint, ypoint], fontslant=font_slant, | |
stroke=stroke_color, stroke_width=stroke_width, | |
fill=fill_color) | |
text_element.draw(surface) | |
cropped_img = autocrop(surface.get_npimage(transparent=True)) | |
return ImageClip(cropped_img) | |
# Example | |
clip = text_clip("This is\na multiline\ntext.", font_family="impact", | |
fill_color=(100,155,255)) | |
clip.ipython_display() |
Thanks, I believe there are plans to replace ImageMagick textclips by this new approach in MoviePy 2.0
thanks dude.
I have a small problem but i can't Identify what's wrong.
I Keep getting that extra space .
here's the code :
text_clip("Hello world",
font_height=30,
bg_color=(255,255,255),
font_family="Ubuntu")
I tried to remove the autocrop
function, and i got the same result.
tried to play with it before deleting it, but I got a random results ( I have no experience in numpy )
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great stuff, works perfectly! Thanks!