文章目录
- 1、需求
- 2、实现
- 2-1 贴图、切分
- 2-2 GUI
- 3、运行效果
- 4、代码
1、需求
- 把一个图像切分成 1x3 或者 3x3
- 切分出来的图像比例希望都是 1:1 正方形
- 如果图像尺寸满足 切分条件,自动填充一些“白边”然后继续切分
- 如果填充了白边的话,希望能够调整原图像在画布上的位置(居中、对齐左边等)
- 都到这了,或许可以给原图像再加一个边距,这样如果刚好够切分图像整体也会多一层“白边”
2、实现
2-1 贴图、切分
秉持着怎么方便怎么来的原则,就用一下
Pillow
库。
1、打开图像获取尺寸,计算画布大小
Image.open
Image.size
2、创建新画布,并将目标贴进去
Image.new
Image.paste
3、对贴好图的画布进行切分
Image.crop
Image.save
2-2 GUI
界面不是很复杂,也不需要很复杂,那就用
tkinter
吧
1、图片路径、输出路径
tkinter.filedialog
tkinter.Label
tkinter.Entry
tkinter.Button
2、切分模式、对齐模式
tkinter.Label
tkinter.Button
3、背景颜色
tkinter.Label
tkinter.colorchooser.askcolor
tkinter.Button
4、内边距
tkinter.Label
tkinter.Scale
3、运行效果
分析结束,走你
4、代码
from typing import Union
from PIL import Image
from os.path import exists, split as path_split
from os import makedirs
class ImgAlign:
START = 0
CENTER = 1
END = 2
MIDDLE = (CENTER, CENTER)
LEFT_CENTER = (START, CENTER)
RIGHT_CENTER = (END, CENTER)
LEFT_TOP = (START, START)
CENTER_TOP = (CENTER, START)
RIGHT_TOP = (END, START)
LEFT_BOTTOM = (START, END)
CENTER_BOTTOM = (CENTER, END)
RIGHT_BOTTOM = (END, END)
ALIGNS = [
LEFT_TOP, CENTER_TOP, RIGHT_TOP,
LEFT_CENTER, MIDDLE, RIGHT_CENTER,
LEFT_BOTTOM, CENTER_BOTTOM, RIGHT_BOTTOM
]
def __getitem__(self, item: int):
return self.ALIGNS[item]
class ImgSpliter:
ONELINE_MODE = 1
THREELINE_MODE = 0
WHITE = '#FFF'
BLACK = '#000'
PADDING = Union[int,
list[int, int], tuple[int, int],
list[int, int, int, int], tuple[int, int, int, int]]
def __init__(self):
self.id = 0
@classmethod
def split_it(cls, img_path: str, out_dir='./', save_origin=False, mode=ONELINE_MODE,
bg=WHITE, padding: PADDING = (0, 0), align=ImgAlign.MIDDLE):
"""
切分图像
:param img_path: 图像路径
:param out_dir: 切分后图像保存文件夹
:param mode: 切分模式:一行还是三行
:param bg: 画布背景颜色。Image.new 里的color配置
:param padding: 画布内边距(相当于原图像外边距)。可以是 n(上下左右都是n);(上下,左右) ;(上,下,下,左,右)
:param align: 对齐方式。 ImgAlign 里的”枚举“
:return:
"""
_padding = (0, 0, 0, 0)
if isinstance(padding, int):
_padding = (padding, padding, padding, padding)
elif isinstance(padding, (tuple, list)):
if len(padding) == 2:
_padding = (padding[0], padding[0], padding[1], padding[1])
elif len(padding) == 4:
_padding = padding
pass
else:
raise ValueError("padding 数组长度应为2或者4")
else:
raise ValueError("padding 数组长度应为2或者4")
im = Image.open(img_path)
img_name = '.'.join(path_split(img_path)[-1].split('.')[:-1])
_out_dir = out_dir + f'/{img_name}'
img_format = im.format
width, height = im.size
width += _padding[2] + _padding[3]
height += _padding[0] + _padding[1]
if not exists(_out_dir):
makedirs(_out_dir)
if mode == cls.ONELINE_MODE:
# 1、宽小于等于三倍高。总长三倍高
if width <= height*3:
bk_size = (height*3, height)
# 2、宽大于三倍高。总长等于宽,总高等于三分之一长。
else:
fix_width = width % 3
_width = width + (3-fix_width if fix_width else 0)
bk_size = (_width, _width // 3)
paste_start_x = 0 # START
if align[0] == ImgAlign.CENTER:
paste_start_x = (bk_size[0]-width)//2
elif align[0] == ImgAlign.END:
paste_start_x = bk_size[0]-width
paste_start_y = 0 # START
if align[1] == ImgAlign.CENTER:
paste_start_y = (bk_size[1]-height)//2
elif align[1] == ImgAlign.END:
paste_start_y = bk_size[1] - height
bk = Image.new('RGB', bk_size, bg)
bk.paste(im, (paste_start_x+_padding[2], paste_start_y+_padding[0]))
if save_origin:
tail = 1
origin_out_path = f'{_out_dir}/{img_name}_wrap.{img_format}'
while exists(origin_out_path):
origin_out_path = f'{_out_dir}/{img_name}_wrap-{tail}.{img_format}'
tail += 1
bk.save(origin_out_path)
im.close()
for i in range(3):
curr_img = bk.crop((
i*bk_size[1],
0,
(i+1) * bk_size[1],
bk_size[1]
))
tail = 1
out_path = f'{_out_dir}/{img_name}_{i+1}.{img_format}'
while exists(out_path):
out_path = f'{_out_dir}/{img_name}_{i+1}-{tail}.{img_format}'
tail += 1
curr_img.save(out_path)
curr_img.close()
yield i+1, out_path
bk.close()
elif mode == cls.THREELINE_MODE:
_canvas_size = max(width, height)
fix_size = 3 - _canvas_size % 3 if _canvas_size % 3 else 0
canvas_size = _canvas_size + fix_size
per_size = canvas_size // 3
paste_start_x = 0 # START
if align[0] == ImgAlign.CENTER:
paste_start_x = (canvas_size-width)//2
elif align[0] == ImgAlign.END:
paste_start_x = canvas_size-width
paste_start_y = 0 # START
if align[1] == ImgAlign.CENTER:
paste_start_y = (canvas_size-height)//2
elif align[1] == ImgAlign.END:
paste_start_y = canvas_size - height
bk = Image.new('RGB', (canvas_size, canvas_size), bg)
bk.paste(im, (paste_start_x+_padding[2], paste_start_y+_padding[0]))
if save_origin:
tail = 1
origin_out_path = f'{_out_dir}/{img_name}_wrap.{img_format}'
while exists(origin_out_path):
origin_out_path = f'{_out_dir}/{img_name}_wrap-{tail}.{img_format}'
tail += 1
bk.save(origin_out_path)
im.close()
for row in range(3):
for col in range(3):
x_start = col * per_size
y_start = row * per_size
curr_img = bk.crop((
x_start, y_start,
x_start + per_size, y_start + per_size
))
tail = 1
out_path = f'{_out_dir}/{img_name}_{row + 1}{col + 1}.{img_format}'
while exists(out_path):
out_path = f'{_out_dir}/{img_name}_{row + 1}{col + 1}-{tail}.{img_format}'
tail += 1
curr_img.save(out_path)
curr_img.close()
yield row*3+col+1, out_path
bk.close()