家里领导给安排了活儿。需求是这样的,她们需要将现有的office文档中的图片上加一行字,加的字是一串编码,这串编码可以从word上直接获取。她们每次都是手动加,几十张图片下来也比较费时,看可不可以自动加。
这个没有做过,瞬间来了兴趣。
首先选择Python做,而不是java,Python做起来比较方便。
初步想法是,逐行遍历word文档,当遇到符合的字符串就保存下来,如果遇到图片就将字符串加到图片上,然后继续向下遍历。
1. 基础库的安装通过pip安装依赖库:
.\pip3.9.exe install python-docx -i https://pypi.mirrors.ustc.edu.cn/simple/
.\pip.exe install pillow -i https://pypi.mirrors.ustc.edu.cn/simple/
2. 整体结构
通过docx编辑word,每个word就是一个 Document对象,每一行看作是一个paragraph。遍历word文档,当遍历到的一行是text的时候,就通过正则取编码并保存,如果是图片,就处理图片,在图片上增加编码,然后用新图片替换旧图片。用新的图片替换旧图片没有找到具体方法,只好曲线救国,删除旧图片再添加新图片。
3. 主处理方法def process(path):
#读取文档
doc = Document(path)
#获取文档所有内容
allPara = doc.paragraphs
lines = len(allPara)
#保存编码
curr_No = ''
#保存
min_width = 6010276
#遍历每段
for i in range(lines):
curr_para = allPara[i]
#本段不是图像
if not is_image(curr_para):
#取出本段文本内容
curr_text = curr_para.text
print('第' + str(i) + '行的内容是:' + curr_text)
#正则匹配,获取需要的字符串,并保存
re_result = re.search('S/O\s+No\.\s*\S*', curr_text)
if re_result is not None:
curr_No = re_result.group()
#本段是图像
else:
#获取本段所有图像列表
image_list = get_all_picture(doc, curr_para)
#将编码加到图像上,编码都相同
image_list_after_change = add_no_to_all_image(image_list, curr_No)
p = curr_para._element
size = len(image_list_after_change)
#添加新段落
curr_run = curr_para.insert_paragraph_before().add_run()
#对于每行图像,先删除,再添加
for j in range(size):
curr_width = image_list[j].width
if min_width > curr_width:
min_width = curr_width
#这块没搞明白宽度的计算,干脆都取最小宽度
curr_run.add_picture(BytesIO(image_list_after_change[j].blob), width=min_width)
#如果一行有多张图片,中间加一个空格
if j < size - 1:
curr_run.add_text(' ')
#curr_para.insert_paragraph_before().add_run().add_picture(BytesIO(new_image.blob), width=image.width)
#删除本段
p.getparent().remove(p)
#保存结果
doc.save('D:\test\test2_result.docx')
4. 判断是否为图像
def is_image(paragraph: Paragraph):
img = paragraph._element.xpath('.//pic:pic')
if not img:
return False
else:
return True
5. 获取本段所有图像
def get_all_picture(document: Document, paragraph: Paragraph):
#获取所有图像
all_img = paragraph._element.xpath('.//pic:pic')
if not all_img:
return
size = len(all_img)
allimage = []
#获取单个图像,并加入到list,最后返回
for i in range(size):
img: CT_Picture = all_img[i]
embed = img.xpath('.//a:blip/@r:embed')[0]
related_part: ImagePart = document.part.related_parts[embed]
image: Image = related_part.image
#print("image" + str(i) + ':' + str(image.width) + '-' + str(image.px_width) + '-' + str(image.horz_dpi))
allimage.append(image)
return allimage
6. 将编码加到图像上
def add_no_to_all_image(image_list, new_text):
size = len(image_list)
result_image_list = []
for i in range(size):
image = image_list[i]
#获取图片内容
blob = image.blob
#转换为PIL库的image
img_pil = PIL.Image.open(BytesIO(blob))
draw = ImageDraw.Draw(img_pil)
#获取字体,Windows系统中字体文件路径是固定的,后边的32是大小
font = ImageFont.truetype("C:\Windows\Fonts\SIMLI.TTF", 32)
#通过字体获取要加载图片上的字的大小
text_width, text_height = font.getsize(new_text)
#计算要放在图片上的字的位置,水平居中,垂直靠下
position = ((img_pil.width - text_width) / 2, (img_pil.height/2 + (img_pil.height/2 - text_height-20)))
#在图片上写字
draw.text(position, new_text, font=font, fill='yellow')
#将结果写到bytesIO
io_array = BytesIO()
img_pil.save(io_array, 'png')
#将图像结果保存到docx的image格式
result_image_list.append(docx.image.image.Image.from_blob(io_array.getvalue()))
return result_image_list
7. 最后是main函数
# -*- coding: UTF-8 -*-
import PIL.Image
import docx.image.image
from docx import Document
from docx.shared import Inches
from docx.text.paragraph import Paragraph
from docx import shared
import os
import re
from docx.image.image import Image
from docx.parts.image import ImagePart
from docx.oxml.shape import CT_Picture
import numpy as np
from PIL import Image
from PIL import ImageFont, ImageDraw
from io import BytesIO
import cv2
if __name__ == '__main__':
word_path = 'D:\test\test2.docx'
process(word_path)
8. 程序遗留问题
处理完之后,发现新word比之前大很多,可以先压缩图片再保存(没有实现),也可以通过“另存为”解决
1)将文档打开后,点击另存为,点击工具->压缩图片
2) 选择web,点击确定,最后保存
9. 致谢做这个,在网上查了很多资料,以下几篇文档帮助很大
1)图片提取: python-docx刨析之提取图片_JovenGeek的博客-CSDN博客
2)Python自动化修改word实例 - 简书
3)图片增加文字: Python在图片上添加文字_修炼之路的博客-CSDN博客_python在图片上添加文字
资源链接:用Python实现在word文档的图片上加一行字-Python文档类资源-CSDN下载
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)