一、使用openpyxl库导出,用某一列命名,把同一行的图片全部拼接在一起
- 原文件是xls另存为xlsx文件,执行的时候报错。文件损坏,重新建一个xlsx文件,把数据复制过去
python
#!/usr/bin/env python
#-*- coding: utf-8 -*-
# vim:fenc=utf-8
# @author tlwlmy
# @version 2026-01-31
import os
import io
from openpyxl import load_workbook
from openpyxl.drawing.image import Image
import re
from PIL import Image as PILImage
from PIL import ImageOps
def merge_images_vertical(image_paths, output_folder, filename):
"""
纵向拼接多张图片(上下排列)
:param image_paths: 图片路径列表(如 ["1.png", "2.png"])
:param output_folder: 保存目录
:param filename: 图片名字
"""
# 1. 打开所有图片并存储
images = []
for open_images in image_paths:
img = PILImage.open(io.BytesIO(open_images._data()))
images.append(img)
if not images:
print("无有效图片可拼接!")
return
# 2. 计算拼接后总尺寸:宽度取最大的图片宽度,高度累加所有图片高度
max_width = max(img.width for img in images)
total_height = sum(img.height for img in images)
# 3. 创建空白画布(背景白色)
merged_img = PILImage.new("RGB", (max_width, total_height), color="white")
# 4. 逐张粘贴图片
current_y = 0 # 记录当前粘贴的y坐标
for img in images:
# 若图片宽度小于最大宽度,居中粘贴(可选,也可左对齐)
offset_x = (max_width - img.width) // 2
merged_img.paste(img, (offset_x, current_y))
current_y += img.height # 更新y坐标
# 保存图片
filepath = os.path.join(output_folder, filename)
# 5. 保存拼接后的图片
merged_img.save(filepath)
print(f"纵向拼接完成!保存至:{filepath}")
def export_images_by_column_openpyxl(excel_path, name_column='A', output_folder="named_images", image_columns=None, sheet_name=None):
"""
根据指定列的单元格内容为图片命名
参数:
- excel_path: Excel文件路径
- name_column: 用于命名的列字母(如 'A', 'B', 'C')
- output_folder: 输出文件夹
- sheet_name: 指定工作表名称,None表示所有工作表
"""
# 创建输出文件夹
os.makedirs(output_folder, exist_ok=True)
# 加载工作簿
wb = load_workbook(excel_path)
# 确定要处理的工作表
if sheet_name:
sheets = [wb[sheet_name]]
else:
sheets = wb.worksheets
image_count = 0
for ws in sheets:
print(f"\n正在处理工作表: {ws.title}")
# 获取所有图片
images = ws._images
# images_dict
images_dict = {}
for img in images:
image_count += 1
# 获取图片的锚点位置
# openpyxl中,图片位置信息在anchor属性中
if hasattr(img, 'anchor'):
# 获取图片左上角所在的单元格
# 不同版本的openpyxl可能有所不同
try:
# 方法1:尝试获取from属性
if hasattr(img.anchor, '_from'):
col_idx = img.anchor._from.col # 列索引(1开始)
row_idx = img.anchor._from.row + 1 # 行索引(1开始)
print(col_idx, row_idx)
# 方法2:尝试直接获取属性
elif hasattr(img, 'left') and hasattr(img, 'top'):
# 通过坐标计算最近单元格
col_idx = int(img.left // 64) + 1 # 近似计算
row_idx = int(img.top // 20) + 1 # 近似计算
else:
print(f" 图片{image_count}: 无法获取位置信息,使用默认名称")
col_idx = row_idx = None
except:
col_idx = row_idx = None
if col_idx and row_idx:
# 确定命名列的位置
# 假设图片与命名单元格在同一行
try:
# 获取命名列的单元格值
name_cell = f"{name_column}{row_idx}"
print('name_cell', name_cell)
name_value = ws[name_cell].value
if name_value:
# 清理文件名(移除非法字符)
clean_name = clean_filename(str(name_value))
filename = f"{clean_name}.png"
else:
filename = f"图片{image_count}.png"
except:
filename = f"图片{image_count}.png"
else:
filename = f"图片{image_count}.png"
else:
filename = f"图片{image_count}.png"
print('col', col_idx, row_idx)
# 筛选第几列的图片
if image_columns is not None:
if col_idx not in image_columns:
print('continue')
continue
# 查询图片是否是多张
if filename not in images_dict.keys():
images_dict[filename] = [img]
else:
images_dict[filename].append(img)
for filename in images_dict.keys():
# 拼接图片
merge_images_vertical(images_dict[filename], output_folder, filename)
print(f"\n{'='*50}")
print(f"处理完成!")
print(f"总图片数: ", len(images_dict.keys()))
print(f"保存位置: {os.path.abspath(output_folder)}")
def clean_filename(filename):
"""清理文件名,移除非法字符"""
# 移除非法字符
illegal_chars = r'[<>:"/\\|?*]'
filename = re.sub(illegal_chars, '', filename)
# 限制长度
if len(filename) > 100:
filename = filename[:100]
# 移除首尾空格
filename = filename.strip()
# 如果清空后为空,使用默认名称
if not filename:
filename = "未命名"
return filename
# 使用示例
if __name__ == "__main__":
excel_file = "123.xlsx"
# 示例1:使用A列的内容命名
export_images_by_column_openpyxl(
excel_path=excel_file,
name_column='D', # 使用B列命名
output_folder="image",
image_columns=[9, 10],
sheet_name=None # 处理所有工作表
)