稍等片刻,正在加载中...

pillow相关实战操作

一. pillow

Python图像处理库。

1. 文档

2. 安装

pip install pillow

二. 实战操作

1. 图片中实现文字书写超过宽度自动换行

from PIL import Image, ImageDraw, ImageFont


class ImgText:
    font = ImageFont.truetype("宋体.ttf", 24)

    def __init__(self, text):
        # 预设宽度 可以修改成你需要的图片宽度
        self.width = 100
        # 文本
        self.text = text
        # 段落 , 行数, 行高
        self.duanluo, self.note_height, self.line_height = self.split_text()

    def get_duanluo(self, text):
        txt = Image.new('RGBA', (100, 100), (255, 255, 255, 0))
        draw = ImageDraw.Draw(txt)
        # 所有文字的段落
        duanluo = ""
        # 宽度总和
        sum_width = 0
        # 几行
        line_count = 1
        # 行高
        line_height = 0
        for char in text:
            width, height = draw.textsize(char, ImgText.font)
            sum_width += width
            if sum_width > self.width:  # 超过预设宽度就修改段落 以及当前行数
                line_count += 1
                sum_width = 0
                duanluo += '\n'
            duanluo += char
            line_height = max(height, line_height)
        if not duanluo.endswith('\n'):
            duanluo += '\n'
        return duanluo, line_height, line_count

    def split_text(self):
        # 按规定宽度分组
        max_line_height, total_lines = 0, 0
        allText = []
        for text in self.text.split('\n'):
            duanluo, line_height, line_count = self.get_duanluo(text)
            max_line_height = max(line_height, max_line_height)
            total_lines += line_count
            allText.append((duanluo, line_count))
        line_height = max_line_height
        total_height = total_lines * line_height
        return allText, total_height, line_height

    def draw_text(self):
        """
        绘图以及文字
        :return:
        """
        note_img = Image.open("demo.png").convert("RGBA")
        draw = ImageDraw.Draw(note_img)
        # 左上角开始
        x, y = 0, 0
        for duanluo, line_count in self.duanluo:
            draw.text((x, y), duanluo, fill=(255, 0, 0), font=ImgText.font)
            y += self.line_height * line_count
        note_img.save("result.png")


if __name__ == '__main__':
    n = ImgText(
        "一切皆往事经过这里" * 5)
    n.draw_text()

测试用的图片:

注意事项:

  • 有一些字体文件是不能够书写中文的。

2. 图片上写文字并旋转文字

from PIL import Image, ImageDraw, ImageFont

def draw_rotated_text(image, font, text, angle, x, y):
    txt = Image.new(image.mode, font.getsize(text))
    d = ImageDraw.Draw(txt)
    d.text((0, 0), text, font=font, fill=(255, 0, 0))
    txt = txt.rotate(angle, expand=1)
    image.paste(txt, (int(x - txt.width/2), int(y - txt.height/2)), txt)

def image_text():
    image = Image.open('bg.png').convert("RGBA")
    font = ImageFont.truetype('demo.ttf', 50)
    draw_rotated_text(image, font, "zero", 0, image.width/2, image.height/2)
    draw_rotated_text(image, font, "ninety", 90, image.width/2, image.height/2)
    draw_rotated_text(image, font, "onetwenty", 120, image.width/2, image.height/2)
    image.show()

if __name__ == '__main__':
    image_text()

3. 实现图片中某个区域的高斯模糊

from PIL import Image, ImageFilter


class MyGaussianBlur(ImageFilter.Filter):
    name = "GaussianBlur"

    def __init__(self, radius=2, bounds=None):
        """
        bounds裁剪的矩形,作为一个(left,up,right,below)的元组。
        left:与左边界的距离
        up:与上边界的距离
        right:还是与左边界的距离
        below:还是与上边界的距离
        :param radius:
        :param bounds:
        """
        self.radius = radius
        self.bounds = bounds

    def filter(self, image):
        if self.bounds:
            clips = image.crop(self.bounds).gaussian_blur(self.radius)
            image.paste(clips, self.bounds)
            return image
        else:
            return image.gaussian_blur(self.radius)


def main():
    image = Image.open('demo.jpg')
    print(image.size)  # (1024, 1024)
    bounds = (16, 945, 415, 1000)  # 高斯模糊的区域
    radius = 10  # 高斯模糊的值
    image = image.filter(MyGaussianBlur(radius=radius, bounds=bounds))
    # image.show()  # 查看生成的图片效果
    image.save("demo2.png")  # 保存为demo2.png


if __name__ == '__main__':
    main()

4. 透明水印放置在背景图上方

import numpy as np
from PIL import Image
import uuid


def blend_image(fore_image, background):
    """
    :param fore_image: 水印图片
    :param background: 背景图片
    :return:
    """
    # 读入图片
    background = Image.open(background).convert('RGB')

    h = Image.new('RGBA', background.size, color=(0, 0, 0, 0))

    # 加载图片水印
    mark = Image.open(fore_image)
    box = (223, 956, 259, 980)  # 水印放置的位置
    region = mark.resize((box[2] - box[0], box[3] - box[1]))
    h.paste(region, box)

    fore_image = h.resize(background.size)

    # 图片加权合成
    scope_map = np.array(fore_image)[:, :, -1] / 255
    scope_map = scope_map[:, :, np.newaxis]
    scope_map = np.repeat(scope_map, repeats=3, axis=2)
    res_image = np.multiply(scope_map, np.array(fore_image)[:, :, :3]) + np.multiply((1 - scope_map),
                                                                                     np.array(background))
    # output_path = str(uuid.uuid1()) + '.png'
    # 保存图片
    res_image = Image.fromarray(np.uint8(res_image))
    res_image.show()
    # res_image.save(output_path)
    # return output_path


if __name__ == '__main__':
    blend_image('mark2.png', 'demo2.png')

注意事项

  • 如果遇到背景图片是白色的话,水印位置会变成黑色的。

5. 给图片添加图片水印

from PIL import Image

def main():
    # 加载背景图
    background = Image.open('demo1.jpg').convert('RGBA')
    # 加载图片水印
    mark = Image.open('mark.png')
    box = (16, 945, 415, 1000)
    region = mark.resize((box[2] - box[0], box[3] - box[1]))
    background.paste(region, box)
    background.show()


if __name__ == '__main__':
    main()

解释box = (16, 945, 415, 1000)中的值:这里是使用了两个坐标点。长方形的形状。第一个点是左上角的坐标(16, 945)。第二个点是右下角的坐标(415, 1000)。这两个点确定之后就可以构成一个矩形了。上面的程序我是把整张图片水印放贴在背景图上的。我采用的demo1.png的尺寸是:1024*1024mark.png是:282*40

实现后的效果如下所示:
image

posted @ 2021-01-06 09:24  一切皆往事  阅读(403)  评论(0)    收藏  举报