图像九宫格切分1x3、3x3 Python

文章目录

  • 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、运行效果

分析结束,走你
图像九宫格切分1x3、3x3 Python_第1张图片
图像九宫格切分1x3、3x3 Python_第2张图片
图像九宫格切分1x3、3x3 Python_第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()

你可能感兴趣的:(python,tkinter,pillow,九宫格,图像切分)