Python根据字体的大小获取字符串像素长度并以表格的形式在图片中显示

在Python中常用的两个图像处理库,一个opencv,一个是PIL。其中,opencv是不支持中文显示的,所以只能显示英文。详细实现如下代码:

# -*- coding: utf-8 -*-#
# Author:      weiz
# Date:        2020/1/13 下午6:26
# Name:        testFont.py
# Description: 让文字信息以表格的形式在图片中显示
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import cv2

def is_chinese(uchar):
    """
    判断一个unicode是否是汉字
    :param uchar:
    :return:
    """
    if uchar >= u'\u4e00' and uchar<=u'\u9fa5':
        return True
    else:
        return False


def fitImageSize_pil(img, fontsize, font_w, font_h, row, longestChn, gap):
    """
    适配图片大小
    :param img:
    :param fontsize:
    :param font_w:
    :param font_h:
    :param row:
    :param longestChn:
    :param gap:
    :return:
    """
    img_h, img_w = img.shape[:2]

    h_rate = (font_h * row) / img_h
    w_rate = font_w / img_w

    while (max(h_rate, w_rate) <= 0.7) or (max(h_rate, w_rate) >= 0.9):
        if max(h_rate, w_rate) <= 0.7:
            fontsize = fontsize + 1
            font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
            font_w, font_h = font.getsize(longestChn)
            font_w = font_w + 2 * gap
            font_h = font_h + 2 * gap
            h_rate = (font_h * row) / img_h
            w_rate = font_w / img_w
        if max(h_rate, w_rate) >= 0.9:
            fontsize = fontsize - 1
            font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
            font_w, font_h = font.getsize(longestChn)
            font_w = font_w + 2 * gap
            font_h = font_h + 2 * gap
            h_rate = (font_h * row) / img_h
            w_rate = font_w / img_w

    font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
    return font, font_w, font_h


def showChn4table_pil(img, chnList, fontsize=None, gap=None, start_x=None, start_y=None):
    """
    以表格的形式在图片的居中(默认是居中)显示中文或者英文字符
    :param img:
    :param chnList:
    :param fontsize:
    :param gap:表格和字体之间的距离
    :param start_x:
    :param start_y:
    :return:
    """
    row = len(chnList)
    if gap == None:
        gap = 2
    if fontsize == None:
        fontsize = 20
    longestChn = ""
    longestChn_count = 0
    # 涉及到中文汉字,一个汉字占两个字节。但是len()函数只计算字符串的个数,而显示涉及到像素
    for chnStr in chnList:
        count = 0
        for chn in chnStr:
            if is_chinese(chn):
                count += 1
        count = (len(chnStr) - count) + count * 2
        if count > longestChn_count:
            longestChn = chnStr
            longestChn_count = count
    img_h, img_w = img.shape[:2]

    pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(pil_img)
    # 如果是在Linux系统下运行,可能需要把simhei.ttf字体放到当前运行脚本同路径下
    font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
    font_w, font_h = font.getsize(longestChn)
    font_w = font_w + 2 * gap
    font_h = font_h + 2 * gap

    font, font_w, font_h = fitImageSize_pil(img, fontsize, font_w, font_h, row, longestChn, gap)

    # 修改start_x和start_y就可以在图片的任意位置显示
    if start_x == None:
        start_x = (img_w - font_w) // 2
    if start_y == None:
        start_y = (img_h - font_h * row) // 2
    end_x = start_x + font_w
    end_y = start_y + font_h * row

    for i, chnStr in enumerate(chnList):
        line_spacing = i * font_h
        draw.text((start_x+gap, start_y+line_spacing+gap), chnStr, (0, 0, 0), font)
        draw.line((start_x, start_y+line_spacing, end_x, start_y+line_spacing), 'red')

    draw.line((start_x, end_y, end_x, end_y), 'red')
    draw.line((start_x, start_y, start_x, end_y), 'red')
    draw.line((end_x, start_y, end_x, end_y), 'red')

    img = cv2.cvtColor(np.asarray(pil_img), cv2.COLOR_RGB2BGR)
    return img


def showEng4table_cv(img, engList, fontScale=None, gap=None, start_x=None, start_y=None):
    """
    以表格的形式在图片的居中(默认是居中)显示英文字符(opencv不支持中文)
    :param img:
    :param engList:
    :param fontScale:
    :param gap:表格和字体之间的距离
    :param start_x:
    :param start_y:
    :return:
    """
    row = len(engList)
    if gap == None:
        gap = 2
    if fontScale == None:
        fontScale = 1
    longestEng = ""
    for engStr in engList:
        if len(engStr) > len(longestEng):
            longestEng = engStr
    img_h, img_w = img.shape[:2]

    (font_w, font_h), baseline = cv2.getTextSize(longestEng, cv2.FONT_HERSHEY_TRIPLEX, fontScale, 1)
    font_h = font_h + baseline + 2 * gap
    font_w = font_w + 2 * gap


    if start_x == None:
        start_x = (img_w - font_w) // 2
    if start_y == None:
        start_y = (img_h - (font_h * row)) // 2
    end_x = start_x + font_w
    end_y = start_y + font_h * row

    for i, engStr in enumerate(engList):
        line_spacing = i * font_h
        cv2.rectangle(img, (start_x, start_y+line_spacing), (end_x, start_y+line_spacing+font_h), (0, 0, 0))
        cv2.putText(img, engStr, (start_x+gap, start_y+line_spacing+font_h-baseline-gap), cv2.FONT_HERSHEY_TRIPLEX, fontScale, (0, 0, 0), 1)

    return img


if __name__ == "__main__":
    img = np.ones([600, 1000, 3], dtype=np.uint8) * 188

    chnList = ['没有,不是,别乱说!', '产品型号|CCF| 符合标推| GB7251.3', '额定工作电压:220V/380V  额定工作电流', '额定绝缘电压:400V额定工作频率:50HZ', '出厂编号|| 出厂日期||年| |月', '河 南 西 西弗  电 气 有 限 公 司', 'abcdetfghidjkkdjddekdjieiij']
    img_pil = showChn4table_pil(img, chnList, 20, 5)
    cv2.imshow("img_pil", img_pil)

    engList = ["How old are you?", "How are you!", "How are you!", "Of course the longest string is me!", "How are you!", "How are you!", "hello,world!", "No, no, don't talk nonsense!"]
    img_cv = showEng4table_cv(img, engList, 0.8, 5)
    cv2.imshow("img_cv", img_cv)

    cv2.waitKey()

效果图片:

使用PIL
使用opencv
发布了82 篇原创文章 · 获赞 126 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_31112205/article/details/103972831
今日推荐