2021-07-30 21:21:51 +08:00
|
|
|
|
from configs.path_config import IMAGE_PATH, TTF_PATH
|
|
|
|
|
|
from PIL import Image, ImageFile, ImageDraw, ImageFont
|
|
|
|
|
|
from imagehash import ImageHash
|
|
|
|
|
|
from io import BytesIO
|
|
|
|
|
|
from matplotlib import pyplot as plt
|
2021-08-17 23:17:08 +08:00
|
|
|
|
from typing import Tuple, Optional, Union
|
2021-07-30 21:21:51 +08:00
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
import cv2
|
|
|
|
|
|
import base64
|
|
|
|
|
|
import imagehash
|
2021-09-09 17:14:33 +08:00
|
|
|
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
|
|
|
|
|
Image.MAX_IMAGE_PIXELS = None
|
2021-07-30 21:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def compare_image_with_hash(
|
|
|
|
|
|
image_file1: str, image_file2: str, max_dif: int = 1.5
|
|
|
|
|
|
) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
比较两张图片的hash值是否相同
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param image_file1: 图片文件路径
|
|
|
|
|
|
:param image_file2: 图片文件路径
|
|
|
|
|
|
:param max_dif: 允许最大hash差值, 越小越精确,最小为0
|
|
|
|
|
|
"""
|
|
|
|
|
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
|
|
|
|
|
hash_1 = get_img_hash(image_file1)
|
|
|
|
|
|
hash_2 = get_img_hash(image_file2)
|
|
|
|
|
|
dif = hash_1 - hash_2
|
|
|
|
|
|
if dif < 0:
|
|
|
|
|
|
dif = -dif
|
|
|
|
|
|
if dif <= max_dif:
|
|
|
|
|
|
return True
|
|
|
|
|
|
else:
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_img_hash(image_file: str) -> ImageHash:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
获取图片的hash值
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param image_file: 图片文件路径
|
|
|
|
|
|
"""
|
|
|
|
|
|
with open(image_file, "rb") as fp:
|
|
|
|
|
|
hash_value = imagehash.average_hash(Image.open(fp))
|
|
|
|
|
|
return hash_value
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-09-05 02:21:38 +08:00
|
|
|
|
def compressed_image(
|
|
|
|
|
|
in_file: Union[str, Path], out_file: Union[str, Path] = None, ratio: float = 0.9
|
|
|
|
|
|
):
|
2021-07-30 21:21:51 +08:00
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
压缩图片
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param in_file: 被压缩的文件路径
|
|
|
|
|
|
:param out_file: 压缩后输出的文件路径
|
|
|
|
|
|
:param ratio: 压缩率,宽高 * 压缩率
|
|
|
|
|
|
"""
|
2021-08-17 23:17:08 +08:00
|
|
|
|
in_file = Path(IMAGE_PATH) / in_file if isinstance(in_file, str) else in_file
|
|
|
|
|
|
if out_file:
|
2021-09-05 02:21:38 +08:00
|
|
|
|
out_file = (
|
|
|
|
|
|
Path(IMAGE_PATH) / out_file if isinstance(out_file, str) else out_file
|
|
|
|
|
|
)
|
2021-08-17 23:17:08 +08:00
|
|
|
|
else:
|
|
|
|
|
|
out_file = in_file
|
2021-07-30 21:21:51 +08:00
|
|
|
|
h, w, d = cv2.imread(str(in_file.absolute())).shape
|
2021-09-05 02:21:38 +08:00
|
|
|
|
img = cv2.resize(
|
|
|
|
|
|
cv2.imread(str(in_file.absolute())), (int(w * ratio), int(h * ratio))
|
|
|
|
|
|
)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
cv2.imwrite(str(out_file.absolute()), img)
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-09-05 02:21:38 +08:00
|
|
|
|
def alpha2white_pil(pic: Image) -> Image:
|
2021-07-30 21:21:51 +08:00
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
将图片透明背景转化为白色
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param pic: 通过PIL打开的图片文件
|
|
|
|
|
|
"""
|
|
|
|
|
|
img = pic.convert("RGBA")
|
|
|
|
|
|
width, height = img.size
|
|
|
|
|
|
for yh in range(height):
|
|
|
|
|
|
for xw in range(width):
|
|
|
|
|
|
dot = (xw, yh)
|
|
|
|
|
|
color_d = img.getpixel(dot)
|
|
|
|
|
|
if color_d[3] == 0:
|
|
|
|
|
|
color_d = (255, 255, 255, 255)
|
|
|
|
|
|
img.putpixel(dot, color_d)
|
|
|
|
|
|
return img
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pic2b64(pic: Image) -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
PIL图片转base64
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param pic: 通过PIL打开的图片文件
|
|
|
|
|
|
"""
|
|
|
|
|
|
buf = BytesIO()
|
|
|
|
|
|
pic.save(buf, format="PNG")
|
|
|
|
|
|
base64_str = base64.b64encode(buf.getvalue()).decode()
|
|
|
|
|
|
return "base64://" + base64_str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fig2b64(plt_: plt) -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
matplotlib图片转base64
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param plt_: matplotlib生成的图片
|
|
|
|
|
|
"""
|
|
|
|
|
|
buf = BytesIO()
|
|
|
|
|
|
plt_.savefig(buf, format="PNG", dpi=100)
|
|
|
|
|
|
base64_str = base64.b64encode(buf.getvalue()).decode()
|
|
|
|
|
|
return "base64://" + base64_str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_valid(file: str) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
判断图片是否损坏
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param file: 图片文件路径
|
|
|
|
|
|
"""
|
|
|
|
|
|
valid = True
|
|
|
|
|
|
try:
|
|
|
|
|
|
Image.open(file).load()
|
|
|
|
|
|
except OSError:
|
|
|
|
|
|
valid = False
|
|
|
|
|
|
return valid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CreateImg:
|
|
|
|
|
|
"""
|
|
|
|
|
|
快捷生成图片与操作图片的工具类
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
|
self,
|
2021-09-05 02:21:38 +08:00
|
|
|
|
w: int,
|
|
|
|
|
|
h: int,
|
|
|
|
|
|
paste_image_width: int = 0,
|
|
|
|
|
|
paste_image_height: int = 0,
|
|
|
|
|
|
color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = "white",
|
|
|
|
|
|
image_mode: str = "RGBA",
|
|
|
|
|
|
font_size: int = 10,
|
|
|
|
|
|
background: Union[Optional[str], BytesIO] = None,
|
|
|
|
|
|
ttf: str = "yz.ttf",
|
|
|
|
|
|
ratio: float = 1,
|
|
|
|
|
|
is_alpha: bool = False,
|
|
|
|
|
|
plain_text: Optional[str] = None,
|
|
|
|
|
|
font_color: Optional[Tuple[int, int, int]] = None,
|
2021-07-30 21:21:51 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param w: 自定义图片的宽度,w=0时为图片原本宽度
|
|
|
|
|
|
:param h: 自定义图片的高度,h=0时为图片原本高度
|
|
|
|
|
|
:param paste_image_width: 当图片做为背景图时,设置贴图的宽度,用于贴图自动换行
|
|
|
|
|
|
:param paste_image_height: 当图片做为背景图时,设置贴图的高度,用于贴图自动换行
|
|
|
|
|
|
:param color: 生成图片的颜色
|
2021-09-05 02:21:38 +08:00
|
|
|
|
:param image_mode: 图片的类型
|
2021-07-30 21:21:51 +08:00
|
|
|
|
:param font_size: 文字大小
|
|
|
|
|
|
:param background: 打开图片的路径
|
|
|
|
|
|
:param ttf: 字体,默认在 resource/ttf/ 路径下
|
|
|
|
|
|
:param ratio: 倍率压缩
|
2021-09-05 02:21:38 +08:00
|
|
|
|
:param is_alpha: 是否背景透明
|
|
|
|
|
|
:param plain_text: 纯文字文本
|
2021-07-30 21:21:51 +08:00
|
|
|
|
"""
|
|
|
|
|
|
self.w = int(w)
|
|
|
|
|
|
self.h = int(h)
|
|
|
|
|
|
self.paste_image_width = int(paste_image_width)
|
|
|
|
|
|
self.paste_image_height = int(paste_image_height)
|
|
|
|
|
|
self.current_w = 0
|
|
|
|
|
|
self.current_h = 0
|
2021-09-05 02:21:38 +08:00
|
|
|
|
self.font = ImageFont.truetype(TTF_PATH + ttf, int(font_size))
|
2021-07-30 21:21:51 +08:00
|
|
|
|
if not background:
|
2021-09-05 02:21:38 +08:00
|
|
|
|
if plain_text:
|
|
|
|
|
|
ttf_w, ttf_h = self.getsize(plain_text)
|
|
|
|
|
|
self.w = self.w if self.w > ttf_w else ttf_w
|
|
|
|
|
|
self.h = self.h if self.h > ttf_h else ttf_h
|
|
|
|
|
|
self.markImg = Image.new(image_mode, (self.w, self.h), color)
|
|
|
|
|
|
self.markImg.convert(image_mode)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
else:
|
|
|
|
|
|
if not w and not h:
|
|
|
|
|
|
self.markImg = Image.open(background)
|
|
|
|
|
|
w, h = self.markImg.size
|
|
|
|
|
|
if ratio and ratio > 0 and ratio != 1:
|
|
|
|
|
|
self.w = int(ratio * w)
|
|
|
|
|
|
self.h = int(ratio * h)
|
|
|
|
|
|
self.markImg = self.markImg.resize(
|
|
|
|
|
|
(self.w, self.h), Image.ANTIALIAS
|
|
|
|
|
|
)
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.w = w
|
|
|
|
|
|
self.h = h
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.markImg = Image.open(background).resize(
|
|
|
|
|
|
(self.w, self.h), Image.ANTIALIAS
|
|
|
|
|
|
)
|
2021-09-05 02:21:38 +08:00
|
|
|
|
if is_alpha:
|
|
|
|
|
|
array = self.markImg.load()
|
|
|
|
|
|
for i in range(w):
|
|
|
|
|
|
for j in range(h):
|
|
|
|
|
|
pos = array[i, j]
|
|
|
|
|
|
is_edit = (sum([1 for x in pos[0:3] if x > 240]) == 3)
|
|
|
|
|
|
if is_edit:
|
|
|
|
|
|
array[i, j] = (255, 255, 255, 0)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
self.draw = ImageDraw.Draw(self.markImg)
|
|
|
|
|
|
self.size = self.w, self.h
|
2021-09-05 02:21:38 +08:00
|
|
|
|
if plain_text:
|
|
|
|
|
|
fill = font_color if font_color else (0, 0, 0)
|
|
|
|
|
|
self.text((0, 0), plain_text, fill)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
def paste(
|
|
|
|
|
|
self,
|
|
|
|
|
|
img: "CreateImg" or Image,
|
|
|
|
|
|
pos: Tuple[int, int] = None,
|
|
|
|
|
|
alpha: bool = False,
|
2021-09-05 02:21:38 +08:00
|
|
|
|
center_type: Optional[str] = None,
|
2021-07-30 21:21:51 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
贴图
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param img: 已打开的图片文件,可以为 CreateImg 或 Image
|
|
|
|
|
|
:param pos: 贴图位置(左上角)
|
|
|
|
|
|
:param alpha: 图片背景是否为透明
|
2021-09-05 02:21:38 +08:00
|
|
|
|
:param center_type: 居中类型,可能的值 center: 完全居中,by_width: 水平居中,by_height: 垂直居中
|
2021-07-30 21:21:51 +08:00
|
|
|
|
"""
|
2021-09-05 02:21:38 +08:00
|
|
|
|
if center_type:
|
|
|
|
|
|
if center_type not in ["center", "by_height", "by_width"]:
|
|
|
|
|
|
raise ValueError(
|
|
|
|
|
|
"center_type must be 'center', 'by_width' or 'by_height'"
|
|
|
|
|
|
)
|
|
|
|
|
|
width, height = 0, 0
|
|
|
|
|
|
if not pos:
|
|
|
|
|
|
pos = (0, 0)
|
|
|
|
|
|
if center_type == "center":
|
|
|
|
|
|
width = int((self.w - img.w) / 2)
|
|
|
|
|
|
height = int((self.h - img.h) / 2)
|
|
|
|
|
|
elif center_type == "by_width":
|
|
|
|
|
|
width = int((self.w - img.w) / 2)
|
|
|
|
|
|
height = pos[1]
|
|
|
|
|
|
elif center_type == "by_height":
|
|
|
|
|
|
width = pos[0]
|
|
|
|
|
|
height = int((self.h - img.h) / 2)
|
|
|
|
|
|
pos = (width, height)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
if isinstance(img, CreateImg):
|
|
|
|
|
|
img = img.markImg
|
|
|
|
|
|
if self.current_w == self.w:
|
|
|
|
|
|
self.current_w = 0
|
|
|
|
|
|
self.current_h += self.paste_image_height
|
|
|
|
|
|
if not pos:
|
|
|
|
|
|
pos = (self.current_w, self.current_h)
|
|
|
|
|
|
if alpha:
|
|
|
|
|
|
try:
|
|
|
|
|
|
self.markImg.paste(img, pos, img)
|
|
|
|
|
|
except ValueError:
|
|
|
|
|
|
img = img.convert("RGBA")
|
|
|
|
|
|
self.markImg.paste(img, pos, img)
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.markImg.paste(img, pos)
|
|
|
|
|
|
self.current_w += self.paste_image_width
|
|
|
|
|
|
|
|
|
|
|
|
def getsize(self, msg: str) -> Tuple[int, int]:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
获取文字在该图片 font_size 下所需要的空间
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param msg: 文字内容
|
|
|
|
|
|
"""
|
2021-09-05 02:21:38 +08:00
|
|
|
|
return self.font.getsize(msg)
|
|
|
|
|
|
|
|
|
|
|
|
def point(self, pos: Tuple[int, int], fill: Optional[Tuple[int, int, int]] = None):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
绘制多个或单独的像素
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param pos: 坐标
|
|
|
|
|
|
:param fill: 填错颜色
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.draw.point(pos, fill=fill)
|
|
|
|
|
|
|
|
|
|
|
|
def ellipse(
|
|
|
|
|
|
self,
|
|
|
|
|
|
pos: Tuple[int, int, int, int],
|
|
|
|
|
|
fill: Optional[Tuple[int, int, int]] = None,
|
|
|
|
|
|
outline: Optional[Tuple[int, int, int]] = None,
|
|
|
|
|
|
width: int = 1,
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
绘制圆
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param pos: 坐标范围
|
|
|
|
|
|
:param fill: 填充颜色
|
|
|
|
|
|
:param outline: 描线颜色
|
|
|
|
|
|
:param width: 描线宽度
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.draw.ellipse(pos, fill, outline, width)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
def text(
|
2021-09-05 02:21:38 +08:00
|
|
|
|
self, pos: Tuple[int, int], text: str, fill: Tuple[int, int, int] = (0, 0, 0), center_type: Optional[str] = None
|
2021-07-30 21:21:51 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
在图片上添加文字
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param pos: 文字位置
|
|
|
|
|
|
:param text: 文字内容
|
|
|
|
|
|
:param fill: 文字颜色
|
2021-09-05 02:21:38 +08:00
|
|
|
|
:param center_type: 居中类型,可能的值 center: 完全居中,by_width: 水平居中,by_height: 垂直居中
|
2021-07-30 21:21:51 +08:00
|
|
|
|
"""
|
2021-09-05 02:21:38 +08:00
|
|
|
|
if center_type:
|
|
|
|
|
|
if center_type not in ["center", "by_height", "by_width"]:
|
|
|
|
|
|
raise ValueError(
|
|
|
|
|
|
"center_type must be 'center', 'by_width' or 'by_height'"
|
|
|
|
|
|
)
|
|
|
|
|
|
w, h = self.w, self.h
|
|
|
|
|
|
ttf_w, ttf_h = self.getsize(text)
|
|
|
|
|
|
if center_type == 'center':
|
|
|
|
|
|
w = int((w - ttf_w) / 2)
|
|
|
|
|
|
h = int((h - ttf_h) / 2)
|
|
|
|
|
|
elif center_type == 'by_width':
|
|
|
|
|
|
w = int((w - ttf_w) / 2)
|
|
|
|
|
|
elif center_type == 'by_height':
|
|
|
|
|
|
h = int((h - ttf_h) / 2)
|
|
|
|
|
|
pos = (w, h)
|
|
|
|
|
|
self.draw.text(pos, text, fill=fill, font=self.font)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
def save(self, path: str):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
保存图片
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param path: 图片路径
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.markImg.save(path)
|
|
|
|
|
|
|
|
|
|
|
|
def show(self):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
显示图片
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.markImg.show(self.markImg)
|
|
|
|
|
|
|
|
|
|
|
|
def resize(self, ratio: float = 0, w: int = 0, h: int = 0):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
压缩图片
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param ratio: 压缩倍率
|
|
|
|
|
|
:param w: 压缩图片宽度至 w
|
|
|
|
|
|
:param h: 压缩图片高度至 h
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not w and not h and not ratio:
|
|
|
|
|
|
raise Exception("缺少参数...")
|
|
|
|
|
|
if not w and not h and ratio:
|
|
|
|
|
|
w = int(self.w * ratio)
|
|
|
|
|
|
h = int(self.h * ratio)
|
|
|
|
|
|
self.markImg = self.markImg.resize((w, h), Image.ANTIALIAS)
|
|
|
|
|
|
self.w, self.h = self.markImg.size
|
|
|
|
|
|
self.size = self.w, self.h
|
|
|
|
|
|
self.draw = ImageDraw.Draw(self.markImg)
|
|
|
|
|
|
|
|
|
|
|
|
def crop(self, box: Tuple[int, int, int, int]):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
裁剪图片
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param box: 左上角坐标,右下角坐标 (left, upper, right, lower)
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.markImg = self.markImg.crop(box)
|
|
|
|
|
|
self.w, self.h = self.markImg.size
|
|
|
|
|
|
self.size = self.w, self.h
|
|
|
|
|
|
self.draw = ImageDraw.Draw(self.markImg)
|
|
|
|
|
|
|
|
|
|
|
|
def check_font_size(self, word: str) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
检查文本所需宽度是否大于图片宽度
|
2021-08-04 15:19:45 +08:00
|
|
|
|
参数:
|
|
|
|
|
|
:param word: 文本内容
|
2021-07-30 21:21:51 +08:00
|
|
|
|
"""
|
2021-09-05 02:21:38 +08:00
|
|
|
|
return self.font.getsize(word)[0] > self.w
|
2021-07-30 21:21:51 +08:00
|
|
|
|
|
2021-09-05 02:21:38 +08:00
|
|
|
|
def transparent(self, alpha_ratio: float = 1, n: int = 0):
|
2021-07-30 21:21:51 +08:00
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
图片透明化
|
|
|
|
|
|
参数:
|
2021-09-05 02:21:38 +08:00
|
|
|
|
:param alpha_ratio: 透明化程度
|
2021-07-30 21:21:51 +08:00
|
|
|
|
:param n: 透明化大小内边距
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.markImg = self.markImg.convert("RGBA")
|
|
|
|
|
|
x, y = self.markImg.size
|
|
|
|
|
|
for i in range(n, x - n):
|
|
|
|
|
|
for k in range(n, y - n):
|
|
|
|
|
|
color = self.markImg.getpixel((i, k))
|
2021-09-05 02:21:38 +08:00
|
|
|
|
color = color[:-1] + (int(100 * alpha_ratio),)
|
2021-07-30 21:21:51 +08:00
|
|
|
|
self.markImg.putpixel((i, k), color)
|
|
|
|
|
|
|
|
|
|
|
|
def pic2bs4(self) -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
CreateImg 转 base64
|
|
|
|
|
|
"""
|
|
|
|
|
|
buf = BytesIO()
|
|
|
|
|
|
self.markImg.save(buf, format="PNG")
|
|
|
|
|
|
base64_str = base64.b64encode(buf.getvalue()).decode()
|
|
|
|
|
|
return base64_str
|
|
|
|
|
|
|
|
|
|
|
|
def convert(self, type_: str):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
修改图片类型
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param type_: 类型
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.markImg = self.markImg.convert(type_)
|
|
|
|
|
|
|
|
|
|
|
|
def rectangle(
|
|
|
|
|
|
self,
|
|
|
|
|
|
xy: Tuple[int, int, int, int],
|
|
|
|
|
|
fill: Optional[Tuple[int, int, int]] = None,
|
|
|
|
|
|
outline: str = None,
|
|
|
|
|
|
width: int = 1,
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
画框
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param xy: 坐标
|
|
|
|
|
|
:param fill: 填充颜色
|
|
|
|
|
|
:param outline: 轮廓颜色
|
|
|
|
|
|
:param width: 线宽
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.draw.rectangle(xy, fill, outline, width)
|
|
|
|
|
|
|
|
|
|
|
|
def line(
|
|
|
|
|
|
self,
|
|
|
|
|
|
xy: Tuple[int, int, int, int],
|
|
|
|
|
|
fill: Optional[Tuple[int, int, int]] = None,
|
|
|
|
|
|
width: int = 1,
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
画线
|
|
|
|
|
|
参数:
|
|
|
|
|
|
:param xy: 坐标
|
|
|
|
|
|
:param fill: 填充
|
|
|
|
|
|
:param width: 线宽
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.draw.line(xy, fill, width)
|
|
|
|
|
|
|
|
|
|
|
|
def circle(self):
|
|
|
|
|
|
"""
|
|
|
|
|
|
说明:
|
|
|
|
|
|
将 CreateImg 图片变为圆形
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.convert("RGBA")
|
|
|
|
|
|
r2 = min(self.w, self.h)
|
|
|
|
|
|
if self.w != self.h:
|
|
|
|
|
|
self.resize(w=r2, h=r2)
|
|
|
|
|
|
r3 = int(r2 / 2)
|
|
|
|
|
|
imb = Image.new("RGBA", (r3 * 2, r3 * 2), (255, 255, 255, 0))
|
|
|
|
|
|
pim_a = self.markImg.load() # 像素的访问对象
|
|
|
|
|
|
pim_b = imb.load()
|
|
|
|
|
|
r = float(r2 / 2)
|
|
|
|
|
|
for i in range(r2):
|
|
|
|
|
|
for j in range(r2):
|
|
|
|
|
|
lx = abs(i - r) # 到圆心距离的横坐标
|
|
|
|
|
|
ly = abs(j - r) # 到圆心距离的纵坐标
|
|
|
|
|
|
l = (pow(lx, 2) + pow(ly, 2)) ** 0.5 # 三角函数 半径
|
|
|
|
|
|
if l < r3:
|
|
|
|
|
|
pim_b[i - (r - r3), j - (r - r3)] = pim_a[i, j]
|
|
|
|
|
|
self.markImg = imb
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
def getchannel(self, itype):
|
|
|
|
|
|
self.markImg = self.markImg.getchannel(itype)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
pass
|