|
@@ -0,0 +1,278 @@
|
|
|
+# -*- codeing = utf-8 -*-
|
|
|
+# @Time : 2024/5/20 18:44
|
|
|
+# @Author : Clown
|
|
|
+# @File : demo_数据表截图.py
|
|
|
+# @Software : PyCharm
|
|
|
+import os.path
|
|
|
+import uuid
|
|
|
+from io import BytesIO
|
|
|
+from typing import Union
|
|
|
+
|
|
|
+import xlwings as xw
|
|
|
+from PIL import ImageGrab,ImageOps
|
|
|
+from spire.xls import *
|
|
|
+
|
|
|
+from openpyxl import load_workbook
|
|
|
+from PIL import Image
|
|
|
+from PIL import ImageDraw
|
|
|
+from PIL import ImageFont
|
|
|
+import tempfile
|
|
|
+from wcwidth import wcswidth
|
|
|
+
|
|
|
+# 以下仅使用于安装了Microsoft的设备上
|
|
|
+def excel_grab(excel_path, sheet_name: Union[str, int] = 0, cell_area=None, pic_path=None, visible=False, saved=True):
|
|
|
+ """
|
|
|
+ Excel指定区域截图
|
|
|
+ :param excel_path: Excel文件路径
|
|
|
+ :param sheet_name: 工作表名称或索引,0即第一张工作表
|
|
|
+ :param cell_area: 截图区域,默认None。'A2:N17', 不指定时获取有内容的区域截图
|
|
|
+ :param pic_path: 截图文件路径,png格式
|
|
|
+ :param visible: 截图时是否打开显示Excel
|
|
|
+ :param saved: 是否将截图保存到本地
|
|
|
+ :return: png路径 或 图片的bytes
|
|
|
+ """
|
|
|
+ app = xw.App(visible=visible, add_book=False)
|
|
|
+ wb = app.books.open(excel_path)
|
|
|
+ if isinstance(sheet_name, str):
|
|
|
+ sheet = wb.sheets(sheet_name)
|
|
|
+ else:
|
|
|
+ sheet = wb.sheets[sheet_name]
|
|
|
+ if cell_area:
|
|
|
+ pic_area = sheet[cell_area]
|
|
|
+ else:
|
|
|
+ pic_area = sheet.used_range # 获取有内容的range
|
|
|
+ pic_area.autofit() #自适应调整列宽和行高
|
|
|
+ # Borders(11) 内部垂直边线。
|
|
|
+ pic_area.api.Borders(11).LineStyle = 1
|
|
|
+ pic_area.api.Borders(11).Weight = 3
|
|
|
+
|
|
|
+ # Borders(12) 内部水平边线。
|
|
|
+ pic_area.api.Borders(12).LineStyle = 1
|
|
|
+ pic_area.api.Borders(12).Weight = 3
|
|
|
+ try:
|
|
|
+ pic_area.api.CopyPicture() # 复制图片区域
|
|
|
+ sheet.api.Paste()
|
|
|
+ pic = sheet.pictures[0] # 当前图片
|
|
|
+ pic.api.Copy()
|
|
|
+ pic.delete() # 删除sheet上的图片
|
|
|
+ except Exception as e:
|
|
|
+ return f'区域【{cell_area}】截图失败,错误:{e}'
|
|
|
+ finally:
|
|
|
+ wb.close()
|
|
|
+ app.quit()
|
|
|
+
|
|
|
+ try:
|
|
|
+ img = ImageGrab.grabclipboard() # 获取剪贴板的图片数据
|
|
|
+ img = ImageOps.expand(img, border = 10, fill = 'white') #背景改成白色
|
|
|
+ except Exception as e:
|
|
|
+ return f'区域【{cell_area}】从剪贴板获取截图失败,错误:{e}'
|
|
|
+ if saved:
|
|
|
+ if not pic_path:
|
|
|
+ pic_path = f'{os.path.splitext(excel_path)[0]}_{uuid.uuid4().hex[:10]}.png'
|
|
|
+ print(pic_path)
|
|
|
+ img.save(pic_path)
|
|
|
+ else:
|
|
|
+ f = BytesIO()
|
|
|
+ img.save(f, 'png')
|
|
|
+ img_data = f.getvalue()
|
|
|
+ f.close()
|
|
|
+ return pic_path if saved else img_data
|
|
|
+
|
|
|
+def excel_to_pic(excel_path):
|
|
|
+ import pandas as pd
|
|
|
+ import matplotlib.pyplot as plt
|
|
|
+ from pandas.plotting import table
|
|
|
+ from PIL import Image
|
|
|
+ from io import BytesIO
|
|
|
+
|
|
|
+ from pylab import mpl
|
|
|
+
|
|
|
+ mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 指定默认字体:解决plot不能显示中文问题
|
|
|
+ mpl.rcParams['axes.unicode_minus'] = False
|
|
|
+
|
|
|
+ xls = pd.ExcelFile(excel_path)
|
|
|
+ j = 0
|
|
|
+ for sheet_name in xls.sheet_names:
|
|
|
+ # 读取工作表数据
|
|
|
+ df = pd.read_excel(xls, sheet_name = sheet_name)
|
|
|
+ # 将缺失值转为空字符串,避免表格中出现NaN
|
|
|
+ df = df.applymap(lambda x: str(x) if pd.notna(x) else '')
|
|
|
+ # 创建一个样式对象
|
|
|
+
|
|
|
+ print("正在处理 %s 表格" % sheet_name)
|
|
|
+ j = j + 1
|
|
|
+
|
|
|
+ if df.shape[0] > 150: # 假设以100行作为一个分割点
|
|
|
+
|
|
|
+ df_split = [df[i:i + 150] for i in range(0, df.shape[0], 150)]
|
|
|
+
|
|
|
+ for i, data in enumerate(df_split):
|
|
|
+ fig = plt.figure(figsize = (9, 26), dpi = 200)
|
|
|
+ ax = fig.add_subplot(111, frame_on = False)
|
|
|
+
|
|
|
+ # 隐藏x轴 y轴
|
|
|
+ ax.xaxis.set_visible(False) # hide the x axis
|
|
|
+ ax.yaxis.set_visible(False) # hide the y axis
|
|
|
+
|
|
|
+ fig.tight_layout()
|
|
|
+ # 如果数据是图片,则保存为图片,否则执行表格处理
|
|
|
+ if isinstance(data.iloc[0, 0], Image.Image): # 检查数据是否为图片
|
|
|
+ img = data.iloc[:, 0].apply(lambda x: x.tobytes()) # 将图片转换为字节流
|
|
|
+ img_buffer = BytesIO()
|
|
|
+ img_buffer.write(img.values.tobytes()) # 将字节流转为BytesIO对象
|
|
|
+ img = Image.open(img_buffer) # 将BytesIO对象转为图片
|
|
|
+ img.save( str(j) + '_' + str(i) + '!' + sheet_name + '.png') # 保存图片
|
|
|
+ else:
|
|
|
+
|
|
|
+ ax.table(cellText = data.values, colLabels = data.columns, cellLoc = 'center', loc = 'center')
|
|
|
+ ax.set_title(sheet_name, fontsize = 12, loc = 'left')
|
|
|
+ # ax.text(0, 1, sheet_name, ha='left', va='center', fontsize=12, transform=ax.transAxes)
|
|
|
+ plt.savefig( str(j) + '_' + str(i) + '!' + sheet_name + '.jpg')
|
|
|
+ plt.close(fig)
|
|
|
+ print("已完成 %s 表格处理" % sheet_name)
|
|
|
+ elif df.shape[0] > 50:
|
|
|
+ if isinstance(df.iloc[0, 0], Image.Image): # 检查数据是否为图片
|
|
|
+ img = df.iloc[:, 0].apply(lambda x: x.tobytes()) # 将图片转换为字节流
|
|
|
+ img_buffer = BytesIO()
|
|
|
+ img_buffer.write(img.values.tobytes()) # 将字节流转为BytesIO对象
|
|
|
+ img = Image.open(img_buffer) # 将BytesIO对象转为图片
|
|
|
+ img.save(str(j) + '!' + sheet_name + '.png') # 保存图片
|
|
|
+ else:
|
|
|
+
|
|
|
+ fig = plt.figure(figsize = (9, 10), dpi = 500)
|
|
|
+ ax = fig.add_subplot(111, frame_on = False)
|
|
|
+ ax.set_title(sheet_name, fontsize = 12, loc = 'left')
|
|
|
+ # ax.text(0, 0.8, sheet_name, ha='left', va='center', fontsize=12, transform=ax.transAxes)
|
|
|
+ table1 = ax.table(cellText = df.values, colLabels = df.columns, cellLoc = 'center', loc = 'center')
|
|
|
+ table1.auto_set_font_size(True) # 禁用自动设置字体大小
|
|
|
+ table1.set_fontsize(14) # 设置字体大小为12
|
|
|
+ ax.xaxis.set_visible(False) # hide the x axis
|
|
|
+ ax.yaxis.set_visible(False) # hide the y axis
|
|
|
+ fig.tight_layout()
|
|
|
+ plt.savefig( str(j) + '!' + sheet_name + '.jpg')
|
|
|
+ plt.close(fig)
|
|
|
+ print("已完成 %s 表格处理" % sheet_name)
|
|
|
+
|
|
|
+
|
|
|
+ else:
|
|
|
+ if isinstance(df.iloc[0, 0], Image.Image): # 检查数据是否为图片
|
|
|
+ img = df.iloc[:, 0].apply(lambda x: x.tobytes()) # 将图片转换为字节流
|
|
|
+ img_buffer = BytesIO()
|
|
|
+ img_buffer.write(img.values.tobytes()) # 将字节流转为BytesIO对象
|
|
|
+ img = Image.open(img_buffer) # 将BytesIO对象转为图片
|
|
|
+ img.save( str(j) + '!' + sheet_name + '.png') # 保存图片
|
|
|
+ else:
|
|
|
+
|
|
|
+ fig = plt.figure(figsize = (9, 6), dpi = 500)
|
|
|
+ ax = fig.add_subplot(111, frame_on = False)
|
|
|
+ ax.set_title(sheet_name, fontsize = 12, loc = 'left')
|
|
|
+ # 设置标题在x,y轴上位置,字体
|
|
|
+ # ax.text(0, 0.8, sheet_name, ha='left', va='center', fontsize=12, transform=ax.transAxes)
|
|
|
+ table1 = ax.table(cellText = df.values, colLabels = df.columns, cellLoc = 'center', loc = 'center')
|
|
|
+ table1.auto_set_font_size(True) # 禁用自动设置字体大小
|
|
|
+ table1.set_fontsize(14) # 设置字体大小为12
|
|
|
+
|
|
|
+ ax.xaxis.set_visible(False) # hide the x axis
|
|
|
+ ax.yaxis.set_visible(False) # hide the y axis
|
|
|
+
|
|
|
+ # fig.tight_layout()
|
|
|
+ plt.savefig( str(j) + '!' + sheet_name + '.jpg')
|
|
|
+ plt.close(fig)
|
|
|
+ print("已完成 %s 表格处理" % sheet_name)
|
|
|
+
|
|
|
+def excel_to_img(excel_path):
|
|
|
+
|
|
|
+
|
|
|
+ # 创建Workbook对象
|
|
|
+ workbook = Workbook()
|
|
|
+
|
|
|
+ # 载入Excel文件
|
|
|
+ workbook.LoadFromFile(excel_path)
|
|
|
+
|
|
|
+ # 获取工作表
|
|
|
+ sheet = workbook.Worksheets.get_Item(0)
|
|
|
+
|
|
|
+ # 移除页边距
|
|
|
+ pageSetup = sheet.PageSetup
|
|
|
+ pageSetup.TopMargin = 0
|
|
|
+ pageSetup.BottomMargin = 0
|
|
|
+ pageSetup.LeftMargin = 0
|
|
|
+ pageSetup.RightMargin = 0
|
|
|
+
|
|
|
+ # 将工作表转换为图片
|
|
|
+ image = sheet.ToImage(sheet.FirstRow, sheet.FirstColumn, sheet.LastRow, sheet.LastColumn)
|
|
|
+
|
|
|
+ # 保存图片
|
|
|
+ image.Save("工作表转图片.png")
|
|
|
+
|
|
|
+ workbook.Dispose()
|
|
|
+
|
|
|
+def excel_to_img_linux(excel_path):
|
|
|
+ # 加载Excel文件
|
|
|
+ wb = load_workbook(excel_path)
|
|
|
+ sheet = wb.active
|
|
|
+
|
|
|
+ # 单元格的行高和列宽
|
|
|
+ row_height = 20
|
|
|
+ column_width = 10
|
|
|
+
|
|
|
+ # 扫描表格尺寸
|
|
|
+ row_size = {}
|
|
|
+ for i in range(sheet.max_column):
|
|
|
+ row_size[str(i)] = 0
|
|
|
+ print(row_size)
|
|
|
+ for row in sheet.iter_rows(min_row = 1, min_col = 1, max_col = sheet.max_column, max_row = sheet.max_row):
|
|
|
+ n = 0
|
|
|
+ for cell in row:
|
|
|
+ text = str(cell.value) if cell.value is not None else ''
|
|
|
+ if row_size[str(n)] <= wcswidth(text):
|
|
|
+ row_size[str(n)] = wcswidth(text)
|
|
|
+ n += 1
|
|
|
+ print(row_size)
|
|
|
+ img_width = 0
|
|
|
+ for key, v in row_size.items():
|
|
|
+ img_width = img_width + v
|
|
|
+ print(img_width)
|
|
|
+
|
|
|
+ if 1 == 1:
|
|
|
+ # 创建一个图像,大小根据单元格大小进行调整
|
|
|
+ img_width = column_width * img_width
|
|
|
+ img_height = row_height * (sheet.max_row + 1)
|
|
|
+ img = Image.new('RGB', (img_width, img_height), color = 'white')
|
|
|
+
|
|
|
+ # 设置字体
|
|
|
+ font = ImageFont.truetype('E:/chrome下载文件/simsun.ttc', 16)
|
|
|
+ draw = ImageDraw.Draw(img)
|
|
|
+
|
|
|
+ # 绘制网路线
|
|
|
+ grid_color = (128, 128, 128)
|
|
|
+ for row_line_y in range(sheet.max_row + 1):
|
|
|
+ draw.line([(0, row_height * row_line_y), (img_width, row_height * row_line_y)], fill = grid_color) # 画横线
|
|
|
+
|
|
|
+ img_width = 0
|
|
|
+ for key, v in row_size.items():
|
|
|
+ draw.line([(img_width, 0), (img_width, row_height * sheet.max_row)], fill = grid_color) # 画纵线
|
|
|
+ img_width = img_width + (v * column_width)
|
|
|
+
|
|
|
+ # 绘制单元格内容
|
|
|
+ for row in sheet.iter_rows(min_row = 1, min_col = 1, max_col = sheet.max_column, max_row = sheet.max_row):
|
|
|
+ n = 0
|
|
|
+ m = 4
|
|
|
+ for cell in row:
|
|
|
+ text = str(cell.value) if cell.value is not None else ''
|
|
|
+ draw.text((m, row_height * (cell.row - 1) + 2), text, font = font, fill = (0, 0, 0))
|
|
|
+ m = m + (column_width * row_size[str(n)])
|
|
|
+ n += 1
|
|
|
+
|
|
|
+ # 保存图片
|
|
|
+ img.save('output.png')
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ excel_path = r'C:\Users\ClownHe\Desktop\店务通数据\2024-05-11至2024-05-17发货单(supplier_split).xlsx'
|
|
|
+ # excel_grab(excel_path)
|
|
|
+ # 使用函数
|
|
|
+ output_path = 'output_image.png' # 输出图片的路径
|
|
|
+ # excel_to_pic(excel_path)
|
|
|
+ # excel_to_img(excel_path)
|
|
|
+ excel_to_img_linux(excel_path)
|