批量压缩word中的图片
一、问题
实验报告中包含了大量的图片,不压缩的情况下占用了非常大的空间,本学期一共收了7次实验报告,总计约2.6GB,这对于我的硬盘来说是一个不小的负担,所以需要对文档中的所有图片进行一次压缩。
二、原理
在office2007以前,word文档基本可以认为是一个二进制文件(doc后缀),是没有办法采用正常的方式进行编辑的,所以如果当我们用ms office写的doc文件用wps或其他开源的office工具打开后,大概率是会出现排版的问题的,这是对协议实现不完善的后果。
在office2007时,微软提出了新的基于xml的文件格式(docx后缀),通过使用xml对文件内容进行管理,然后将所有的xml文件、图片文件、视频文件等内容打包压缩为zip格式,然后将后缀名改为docx,即完成了word文件的创建。可以看出docx的改动是比doc要简单的,我这里采用的原理就是这样。
三、开干
1. 更改文件名
不巧的是,实验报告很多同学的学号和姓名之间加了空格,这在后续进行命令处理文件时,出现了问题,所以,这里先把文件名改一遍,如果有空格,则删除空格。
import os
# 创建一个列表,存放文件名
files = []
# 获取当前工作目录
path = os.getcwd()
def main():
# 获取当前文件中所有文件名,如果结尾是doc
# 则添加到files列表中,待处理
for file in os.listdir(path):
if file.endswith("doc"):
files.append(file)
rename()
def rename():
# 遍历列表,如果文件名中出现了空格
# 则:
# 重命名该文件
# 删除列表中的带空格的文件名
# 添加更改后不带空格的文件名
for file in files:
if " " in file:
filepath = path+"\\"+file
os.rename(filepath, filepath.replace(" ", ""))
files.remove(file)
files.append(file.replace(" ", ""))
2. 更改文件格式
不巧的是,这次实验报告所有同学都是采用doc格式创建的,这里强势吐槽一下各位同学的计算机知识,虽然是计算机相关专业的。所以我们需要将doc转成docx。
这里查一句,如果是手动打开该文件,然后另存为docx文件,那么文件中的图片也是可以被压缩的,如果用python另存为,则不会被压缩,看来还是有问题的。要不也不会有下边压缩文件的操作了。
这里我们使用了python win32com库,安装win32com库可以 pip install pywin32
。代码如下:
from win32com import client as wc #导入模块
def convertDoc2Docx():
word = wc.Dispatch("Word.Application") # 打开word应用程序
for file in files:
print("convert:"+file)
filepath = path+"\\"+file
#打开word文件
doc = word.Documents.Open(filepath)
# 说是将文件名转为docx,实际上保存时后缀直接改成了zip
# 所以目标文件名称后缀改一下
filename = filepath.replace("doc", "zip")
#另存为后缀为".docx"的文件,其中参数12指docx文件
doc.SaveAs(filename, 12)
#关闭原来word文件
doc.Close()
word.Quit()
3. 解压docx文件
经过上述第二步以后,所有的doc文件已经被转换成了docx,这里使用了python自带的zipfile模块进行解压缩
import zipfile
def unzipDocx():
for file in files:
print("unzip:"+file)
# 拼凑文件夹路径
dirpath = path+"\\"+file.split(".")[0]
# 拼凑文件名,zip格式结尾
zippath = path+"\\"+file.replace("doc", "zip")
# 创建目录,每个文件都有自己专属的目录,用以存放解压后的所有文件
os.mkdir(dirpath)
# 创建zipfile对象
zp = zipfile.ZipFile(zippath, "r")
# 解压缩
zp.extractall(path=dirpath)
# 关闭
zp.close()
# 删除zip文件
os.remove(zippath)
4、更改图片大小
直接上代码
import cv2
import numpy as np
import shutil
import subprocess
def resizeImage():
for file in files:
print("resize:"+file)
# 拼凑图片文件所在的目录:“解压后的文件路径\word\media”
# 也就是说所有的图片文件都是在media文件夹中
imagepath = "\\".join([path, file.split(".")[0],"word", "media"])
# 创建两个列表,保存两种不同的文件类型名称
jpegfiles = []
pngfiles = []
# 区分两种文件名
for tempfile in os.listdir(imagepath):
if tempfile.endswith("jpeg"):
jpegfiles.append(tempfile)
elif tempfile.endswith("png"):
pngfiles.append(tempfile)
# 压缩jpeg文件
for jpegfile in jpegfiles:
print("resize:"+jpegfile)
# 拼凑完整的待处理文件路径
filepath = imagepath + "\\" + jpegfile
# 这里需要注意,opencv好像是无法识别中文路径
# 所以这里使用numpy模块先读取文件内容
# 然后转换成opencv能够识别的图像信息
img = cv2.imdecode(np.fromfile(filepath, dtype=np.uint8), -1)
# os.rename(filepath, filepath+".bak")
# 同样由于中文路径问题,所以这里先将文件缩小后保存到“D:\\temp\\”这个目录中
# 然后使用shutil剪切到原来的media路径中
tempfile = "D:\\temp\\" + jpegfile
cv2.imwrite(tempfile,img,[cv2.IMWRITE_JPEG_QUALITY,30])
shutil.move(tempfile, filepath)
# png文件使用的是另一种处理方式
# 最开始找了个工具pngquant,想着总得用上呀
# 其实png用opencv也是可以处理的
for pngfile in pngfiles:
print("resize:"+pngfile)
filepath = imagepath + "\\" + pngfile
# 先将需要转换的文件移动到“D:\\temp\\”
# 如果直接在当前文件夹更改的话,文件名会被改掉,然后还得改回来
tempfile = "D:\\temp\\" + pngfile
shutil.move(filepath, tempfile)
# 拼凑命令,使用subprocess进行运行,也就是执行cmd命令
# 这里需要注意的是,先下载pngquant,然后,解压,然后添加环境变量
cmd = "pngquant --quality=10-20 {} --output D:\\temp\\temp.png".format(tempfile)
subprocess.run(cmd)
# 将更改后的文件移动到原来的文件夹
shutil.move("D:\\temp\\temp.png", filepath)
os.remove(tempfile)
5、 重新压缩
文件处理完后,显然是要重新压缩成为docx文件的,这里需要注意的是,压缩时,我们压缩的时文件夹中的内容,不是文件夹,如图:
def zipDocx():
for file in files:
print("zip:"+file)
zipfile = path+"\\"+file.replace("doc", "zip")
dirpath = path+"\\"+file.split(".")[0]
# 压缩使用的时7z命令,当然也是需要添加到环境变量的
# 其实也可以用zipfile进行压缩,但是我不知道哪里错了,总之没弄出来
# 其实解压也可以用7z
cmd ="7z a {} {}\\*".format(zipfile, dirpath)
subprocess.run(cmd)
# 重命名zip文件为docx
dstfile = zipfile.replace("zip", "docx")
os.rename(zipfile, dstfile)