百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

#005 Python实现批量 Word to PNG图片

ztj100 2024-11-27 23:33 20 浏览 0 评论

有个网友在WordtoPDF的文章中留言说有没有WORDTOPNG。

有需求,必须安排,业务场景做出来再聊聊。

一、思路

第一种:用WORD TO PDF的库(win32com.client)来实现

查资料发现这个库的SaveAs方法里面的WdSaveFormat 没有图片格式。

参考微软的官方说明:

https://learn.microsoft.com/zh-cn/office/vba/api/word.wdsaveformat

这个方法应该是行不通了。


第二种:百度出来Aspose这家商业的py库可以

立刻安排:Demo都跑成功了,结果图片上有这家的水印。

裤子都脱了,给我安排这个,就这?


第三种:曲线救国

STEP1:DOC先转PDF

SETP2:PDF转PNG

看起来可行


二、实现和讲解

先贴代码,再来讲解注意事项:

Bash
# -*- coding: utf-8 -*-
"""
    @Author  : Nick
    @Time    : 2023/9/7
    @Comment : #005 doc to pdf to png
"""

from datetime import datetime
from pathlib import Path
import fitz  #pip install PyMuPDF
import cv2 # pip3 install opencv-python -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
import numpy as np
import os
from shutil import copyfile
import win32com.client #pip install pywin32


def is_blank(line):
    """
    判断本行是否空白行
    """
    for pixel in line:
        if not all(n == 255 for n in pixel):
            return False
    return True

def get_blank_block(img, begin_row, end_row, need_height):
    """
    获取高度大于等于输入值的整块空白区域
    """
    if (img is None) or (begin_row < 0) or (end_row < begin_row) or (need_height <= 0):
        return False, 0, 0
    if (end_row - begin_row) < need_height:
        return False, 0, 0
    start_row = -1
    found = False
    found_height = 0
    for row in range(begin_row, end_row):
        line = img[row, :]
        if not is_blank(line):
            # 非空白,则判断高度是否符合
            if found_height >= need_height:
                break
            start_row = -1
            found_height = 0
            continue
        # 是空白行
        if start_row < 0:
            start_row = row
        found_height += 1
    if found_height >= need_height:
        found = True
    return found, start_row, found_height

def shrink_img(img, blank_height=50, reserve_height=20):
    """
    将图片中过长的空白背景截取删除:对于图片中整行都是白色,且超过一定高度的,仅保留指定高度区域,其余删除。
    """
    # 读取原始图片宽高
    height, width = img.shape[:2]
    found = True
    img_stack = None
    begin_row = 0
    while found:
        found, begin_blank_row, found_height = get_blank_block(img, begin_row, height, blank_height)
        if found:
            # 找到空白区域,将搜索起始行到空白起始行之间的图像加入stack,跳过空白区域,继续搜索
            img2 = img[begin_row: begin_blank_row + reserve_height, :]
            begin_row = begin_blank_row + found_height
        else:
            # 没找到空白区域,将搜索起始行到结束行的图像加入stack
            img2 = img[begin_row:height, :]
        if img_stack is None:
            img_stack = np.vstack((img2,))
        else:
            img_stack = np.vstack((img_stack, img2))
    if img_stack is None:
        img_stack = img
    return img_stack

def pdf_2_png(pdf_name,png_name=None):
    print(pdf_name)
    pdf_path = Path(pdf_name).parent
    doc = fitz.open(pdf_name)
    img_stack = None
    temp = 0
    # 每页pdf生产一个临时图片
    for pg in range(doc.page_count):
        page = doc[pg]
        temp += 1
        rotate = int(0)
        # 每个尺寸的缩放系数为2,这将为我们生成分辨率提高四倍的图像。
        zoom_x = 2.0
        zoom_y = 2.0
        trans = fitz.Matrix(zoom_x, zoom_y).prerotate(rotate)
        pixmap = page.get_pixmap(matrix=trans, alpha=False)
        # 生成临时png文件路径
        pic_name = str(pdf_path.joinpath('_temp_{}.png'.format(temp)).absolute())
        pixmap.save(pic_name)
        # pm_img = cv2.imread(pic_name) # 此方式不支持中文目录,改用下方方法
        pm_img = cv2.imdecode(np.fromfile(pic_name, dtype=np.uint8), cv2.IMREAD_COLOR + cv2.IMREAD_IGNORE_ORIENTATION)
    
        pm_img = cv2.resize(pm_img, (1191, 1684))
        # 删除临时图片文件
        Path(pic_name).unlink(True)
        # 拼长图
        if img_stack is None:
            img_stack = np.vstack((pm_img,))
        else:
            img_stack = np.vstack((img_stack, pm_img))
    # 删除长图中的空白区域
    thin_img = shrink_img(img_stack, 100, 20)

    output_file = png_name if png_name is not None else str(pdf_path.joinpath(Path(pdf_name).stem + ".png").absolute())
    # cv2.imwrite(str(tmp_img_name.absolute()), thin_img) # 不支持中文目录
    # 采用下述方法保存到带中文的目录
    cv2.imencode('.png', thin_img)[1].tofile(output_file)

def shrink_file(img_file,target_file):
    pm_img = cv2.imread(img_file)
    im = shrink_img(pm_img, 120, 20)
    cv2.imwrite(target_file, im)


# Word文件转换为PDF
def doc_to_pdf(word_path, pdf_path):
    try:
        # 创建Word应用程序对象
        word_app = win32com.client.Dispatch('Word.Application')
        # 打开Word文档
        doc = word_app.Documents.Open(word_path)
        # 保存为PDF
        doc.SaveAs(pdf_path, FileFormat=17)
        # 关闭文档和应用程序
        doc.Close()
        word_app.Quit()
        print(f'成功转换:{word_path} -> {pdf_path}')
        return True
    except Exception as e:
        print(f'转换失败:{word_path},错误信息:{str(e)}')
        return False

# 批量转换Word文件夹下的所有文档
def batch_doc_to_pdf_to_png(word_folder, pdf_folder):
    # 检查PDF保存目录是否存在,若不存在则创建
    if not os.path.exists(pdf_folder):
        os.makedirs(pdf_folder)

    # 遍历Word文件夹下的所有文件
    for filename in os.listdir(word_folder):
        if filename.endswith('.doc') or filename.endswith('.docx'):
            
            word_path = os.path.join(word_folder, filename)
            pdf_path = os.path.join(pdf_folder, f'{os.path.splitext(filename)[0]}.pdf')
            print("STEP1:正在处理DOC_TO_PDF:")
            print("DOC:" + word_path)
            print("PDF:" + pdf_path)
            doc_to_pdf(word_path, pdf_path)
            print("STEP2:正在处理PDF_TO_PNG:")
            pdf_2_png(pdf_path)
            print("PDF:" + pdf_path + "转PNG完成")

if __name__ == '__main__':
# 调用批量转换函数进行转换
    folder_path = os.path.dirname(os.path.abspath(__file__)) #py所在的文件夹

    batch_doc_to_pdf_to_png(folder_path, folder_path)

注意事项:

1.要按照代码上的备注安装好依赖库。不常用的,我都写了备注。

2.把这个代发贴到py文件以后,把文件和WORD文档放在一个目录下,双击执行就可以。

3.注意:PDF合并成一张长图的时候,需要的时间较长,需要耐性等待一会。


三、执行效果

执行过程:

效果:

部分功能参考了网友的代码:

https://blog.csdn.net/trivialboy/article/details/130380086

相关推荐

前端案例·程序员的浪漫:流星雨背景

如果文章对你有收获,还请不要吝啬【点赞收藏评论】三连哦,你的鼓励将是我成长助力之一!谢谢!(1)方式1:简单版本【1】先看实现效果...

UI样式iPod classic的HTML本地音乐播放器框架

PS:音量可以鼠标点击按住在音量图标边的轮盘上下拖拽滑动音量大小中心按钮可以更改播放器为白色...

JavaScript 强制回流问题及优化方案

JavaScript代码在运行过程中可能会强制触发浏览器的回流(Reflow)...

Ai 编辑器 Cursor 零基础教程:推箱子小游戏实战演练

最近Ai火的同时,Ai编辑器Cursor同样火了一把。今天我们就白漂一下Cursor,使用免费版本搞一个零基础教程...

19年前司机被沉尸水库!凶手落网,竟已是身家千万的大老板

]|\[sS])*"|'(?:[^\']|\[sS])*'|[^)}]+)s*)/g,l=window.testenv_reshost||window.__moon_host||"res.wx.qq...

全民健身网络热度调查“居家健身”成为第一网络热词

]|\[sS])*"|'(?:[^\']|\[sS])*'|[^)}]+)s*)/g,l=window.testenv_reshost||window.__moon_host||"res.wx.qq...

取代JavaScript库的10个现代Web API及详细实施代码

为什么浏览器内置的API你还在用某个臃肿的Javascript库呢?用内置的API有什么好处呢?Web平台经历了巨大演进,引入了强大的原生API,不再需要臃肿的JavaScript库。现代浏览器现已支...

前端文件下载的N种姿势:从简单到高级

文件下载是web开发里一个非常常见的功能,无论是下载用户生成的数据、图片、文档还是应用程序包。前端开发者有多种方式来实现这一需求,每种方式都有其适用场景和优缺点。介绍下几种比较常用的文件下载方法。...

JavaScript 性能优化方法(js前端性能优化)

JavaScript性能优化方法减少DOM操作频繁的DOM操作会导致浏览器重绘和回流,影响性能。使用文档片段(DocumentFragment)或虚拟DOM技术减少直接操作。...

DOM节点的创建、插入、删除、查找、替换

在前端开发中,js与html联系最紧密的莫过于对DOM的操作了,本文为大家分享一些DOM节点的基本操作。一、创建DOM节点使用的命令是varoDiv=document.createElement...

前端里的拖拖拽拽(拖拽式前端框架)

最近在项目中使用了react-dnd,一个基于HTML5的拖拽库,“拖拽能力”丰富了前端的交互方式,基于拖拽能力,会扩展各种各样的拖拽反馈效果,因此有必要学习了解,最好的学习方式就是实操!...

大模型实战:Flask+H5三件套实现大模型基础聊天界面

本文使用Flask和H5三件套(HTML+JS+CSS)实现大模型聊天应用的基本方式话不多说,先贴上实现效果:流式输出:思考输出:聊天界面模型设置:模型设置会话切换:前言大模型的聊天应用从功能...

SSE前端(sse前端数据)

<!DOCTYPEhtml><htmllang="zh-CN"><head>...

课堂点名总尴尬?试试 DeepSeek,或能实现点名自由!(附教程)

2025年2月26日"你有没有经历过这样的场景?老师拿着花名册扫视全班:'今天我们来点名...'那一刻心跳加速,默念:'别点我!'但现在,我要...

我会在每个项目中复制这10个JS代码片段

你是否也有这种感觉:在搭建新项目时,你会想:"这个函数我是不是已经写过了...在某个地方?"是的——我也是。所以在开发了数十个React、Node和全栈应用后,我不再重复造轮子。我创建...

取消回复欢迎 发表评论: