python excel图片批量拼接导出

一、使用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   # 处理所有工作表
    )
相关推荐
踏着七彩祥云的小丑6 小时前
pytest——Mark标记
开发语言·python·pytest
小李子呢02117 小时前
前端八股CSS(2)---动画的实现方式
前端·javascript
不爱吃炸鸡柳7 小时前
Python入门第一课:零基础认识Python + 环境搭建 + 基础语法精讲
开发语言·python
Dxy12393102168 小时前
Python基于BERT的上下文纠错详解
开发语言·python·bert
GreenTea8 小时前
从 Claw-Code 看 AI 驱动的大型项目开发:2 人 + 10 个自治 Agent 如何产出 48K 行 Rust 代码
前端·人工智能·后端
渣渣xiong9 小时前
从零开始:前端转型AI agent直到就业第五天-第十一天
前端·人工智能
布局呆星9 小时前
Vue3 | 组件通信学习小结
前端·vue.js
C澒9 小时前
IntelliPro 企业级产研协作平台:前端智能生产模块设计与落地
前端·ai编程
SiYuanFeng9 小时前
Colab复现 NanoChat:从 Tokenizer(CPU)、Base Train(CPU) 到 SFT(GPU) 的完整踩坑实录
python·colab