用python在excel画画

在B站看到一个人在excel画人像,秀的一手好技术,但是作为半个程序猿有点忍不了,所以有了这个小脚本。
主要实现功能很简单,读取图片,把像素转化成excel的表格底色,保存到excel。

难点几个:

  1. excel列宽,行高调整。这里使用下面的语法来调整行高列宽,至于为什么是这两个特定值,手动调整看到行高列宽的默认值还不是一样的,这样才能保证一个单元格是正方形,而不是长方形。
ws.column_dimensions[_get_column_letter(x)].width = 3 / 15
ws.row_dimensions[y].height = 6 * 3 / 16
  1. 图片转化为RGB像素信息的矩阵。使用下面语句获得图片RGB信息矩阵pix
img = Image.open(picture)
pix = img.load()
print(pix[0,0])
> (122,121,201)
  1. RGB的像素填充excel的单元格。这个方法来填充单元格颜色,在openpyxl的颜色格式是CC99FF,所有手动转下RGB的格式。
    我感觉这里应该是有有相应的方法的,这里直接网上找了个写好的,没找对应的包。
fill_1 = PatternFill("solid", fgColor=_color(pix[x - 1, y - 1]))
self.ws[cell_name].fill = fill_1
  1. 其他的步骤就是循环了,最终的代码逻辑稍微梳理下,就有了这个脚本。
    但是实际的效率非常低,一个1080*1080的图要2分钟多才能完成。
    本来想找找优化方案,但是看了一圈没找到好的思路,这里算是留个坑把。
import openpyxl
from openpyxl.styles import PatternFill
from PIL import Image
from openpyxl.utils.cell import _get_column_letter
from datetime import datetime


class draw_on_excel():
    def __init__(self):
        self.wb = openpyxl.Workbook()
        pass

    def init_sheet(self, sheet_name='picture', size=(100, 100)):
        print('{}: Draw begin'.format(datetime.now()))
        # 调整用到的列和行的宽度高度
        ws = self.wb.create_sheet(sheet_name, index=0)
        for x in range(1, size[1] + 1):
            ws.column_dimensions[_get_column_letter(x)].width = 3 / 15
        for y in range(1, size[0] + 1):
            ws.row_dimensions[y].height = 6 * 3 / 16
        self.ws = ws

    def draw_from(self, picture=''):
        self.picture = picture
        # 加载图片,读取大小
        img = Image.open(picture)
        pix = img.load()

        def _color(value):
            digit = list(map(str, range(10))) + list("ABCDEF")
            if isinstance(value, tuple):
                string = ''
                for i in value:
                    a1 = i // 16
                    a2 = i % 16
                    string += digit[a1] + digit[a2]
                return string
            elif isinstance(value, str):
                a1 = digit.index(value[1]) * 16 + digit.index(value[2])
                a2 = digit.index(value[3]) * 16 + digit.index(value[4])
                a3 = digit.index(value[5]) * 16 + digit.index(value[6])
                return (a1, a2, a3)

        # 初始化excel对应的行列
        self.init_sheet(picture, img.size)

        # draw picture
        for x in range(1, img.size[0] + 1):
            for y in range(1, img.size[1] + 1):
                cell_name = '{}{}'.format(_get_column_letter(x), y)
                fill_1 = PatternFill("solid", fgColor=_color(pix[x - 1, y - 1]))
                self.ws[cell_name].fill = fill_1

    def save_to(self, out_put=''):
        self.wb.save(out_put)
        print('{}: picture "{}" saved in "{}".'.format(datetime.now(), self.picture, out_put))


if __name__ == '__main__':
    die = draw_on_excel()
    die.draw_from('20200530194555.jpg')
    die.save_to('picture.xlsx')

> 2020-05-30 20:53:37.457255: Draw begin
2020-05-30 20:55:39.862170: picture "20200530194555.jpg" saved in "picture.xlsx".

你可能感兴趣的:(python)