Zulko / gizeh

Simple Vector Graphics for Python
Other
702 stars 70 forks source link

issue with gizeh text_clip #54

Closed vloe closed 1 year ago

vloe commented 2 years ago

I'm using gizeh and moviepy to add text on videoclip. I use your code to create a text clip. There is an annoying issue with inconsistency in the space between the text lines. Where sometimes the space will be too large between two lines. It happens every now and then, and I don't understand why.

Here the code I'm using (your code):

def autocrop(np_img):
    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 = 100, font_width = None,
              interline= None, fill_color=(0,0,0),
              stroke_color=(0, 0, 0), stroke_width=2,
              bg_color=None):
    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)

This is how I create the text clip:

texts["text0"] = textwrap.fill(texts["text0"], 46)
clip = text_clip(texts["text0"], font_family="Verdana", align='left',
                     font_weight='normal', font_slant='normal',
                     font_height=33, font_width=None,
                     interline=None, fill_color=(255, 255, 255),
                     stroke_color=(255, 255, 255), stroke_width=0, bg_color=None)

Here is an example of the space between the textlines being to large: image

Here is another one: image

Here is a normal example where everything is fine, no problems: image

another one where everything is fine, no problems: image

The same code is used on every text clip, and there is no "section" used in any of the texts, just compound text. It looks like it happens to any text, regardless how many lines there are. Please help me out! Thanks :-)

vloe commented 2 years ago

can anyone help me out? @Zulko, @ivuk, @eriknw, @festinuz