如何从 powerpoint (python-pptx) 访问图像
How can I access images from powerpoint (python-pptx)
我很难尝试使用 python-pptx 库 access/save 图像。因此,如果图像的形状类型为 PICTURE
(即 shape.shape_type == MSO_SHAPE_TYPE.PICTURE
),我可以使用 'blob' 属性轻松 access/save 图像。这是代码:
import argparse
import os
from PIL import Image
import pptx
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx import Presentation
from mdutils.mdutils import MdUtils
from mdutils import Html
def main():
parser = argparse.ArgumentParser()
parser.add_argument('ppt_name', type=str, help='add the name of the PowerPoint file(NOTE: the folder must be in the same directory as the prorgram file')
args = parser.parse_args()
pptx_name = args.ppt_name
pptx_name_formatted = pptx_name.split('.')[0]
prs = Presentation(pptx_name)
path = '{}_converted'.format(pptx_name_formatted)
if not os.path.exists(path):
os.mkdir(path)
images_folder = '{}_images'.format(pptx_name_formatted)
images_path = os.path.join(path, images_folder)
if not os.path.exists(images_path):
os.mkdir(images_path)
ppt_dict = {} #Keys: slide numbers, values: slide content
texts = []
slide_count = 0
picture_count = 0
for slide in prs.slides:
texts = []
slide_count += 1
for shape in slide.shapes:
if shape.has_text_frame:
if '\n' in shape.text:
splitted = shape.text.split('\n')
for word in splitted:
if word != '':
texts.append(word)
elif shape.text == '':
continue
else:
texts.append(shape.text)
elif shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
with open('{}/image{}_slide{}.png'.format(images_path, picture_count, slide_count), 'wb') as f:
f.write(shape.image.blob)
picture_count += 1
ppt_dict[slide_count] = texts
ppt_content = ''
for k,v in ppt_dict.items():
ppt_content = ppt_content + ' - Slide number {}\n'.format(k)
for a in v:
ppt_content = ppt_content + '\t - {}\n'.format(a)
mdFile = MdUtils(file_name='{}/{}'.format(path,path)) #second argument isn't path, it just shares the path name.
mdFile.write(ppt_content)
mdFile.create_md_file()
if __name__ == "__main__":
main()
问题是当图片是形状类型'auto shape'时,我试了很多方法都没有用。当我执行 运行 时,我知道形状的以下代码是图片:
if shape.shape_type == MSO_SHAPE_TYPE.AUTO_SHAPE:
print(shape.auto_shape_type)
print(shape.fill.type)
#indented because it's in a for loop
它为 shape.auto_shape_type
输出 RECTANGLE
和 PICTURE
对于 shape.fill.type
但我现在想要的是保存图片(可能通过写入图像的二进制图像字节流)。有人可以帮忙吗?
图像(部分,有斑点)的“link”在填充定义中。使用它你可以得到图像。
用shape.fill._xPr.xml
打印出XML周围的填充定义。这将使您了解需要导航到的内容。很有可能它看起来像 "rId9"
和一些特定的其他数字,其中“9”占位符在该示例中。可能在 "blipfill"
附近。该图像用作形状的“填充”,所以这就是这里发生的事情。
然后使用 slide._part
之类的东西获取幻灯片部分,并使用其 .related_parts
“dict”使用 relationship-id[= 查找图像“填充”部分38=](类似“rId9”的字符串)。
image_part = slide._part.related_parts["rId9"]
ImagePart
实现在这里:
https://github.com/scanny/python-pptx/blob/master/pptx/parts/image.py#L21
它提供了对图像的访问权限以及有关图像的大量详细信息。
您必须使用 lxml
调用来检索类似“rId9”的字符串,大致类似于:
rIds = shape.fill._xPr.xpath(".//@embed")
rId = rIds[0]
您需要对 XPath 进行一些研究,以根据您在前面的步骤中打印出的 XML 计算出正确的表达式。 XPath 上有很多内容,包括这里的 SO,这是一个入门资源:http://www.rpbourret.com/xml/XPathIn5.htm
如果您无法解决,post 您打印出来的 XML 我们可以帮助您进行下一步。
这是我的方法,感谢 scanny。
for slide in prs.slides:
slide_count += 1
slide_parts = list(slide._part.related_parts.keys())
for part in slide_parts:
image_part = slide._part.related_parts[part]
if type(image_part) == pptx.parts.image.ImagePart or pptx.opc.package.Part:
file_startswith = image_part.blob[0:1]
if file_startswith == b'\x89' or file_startswith == b'\xff' or file_startswith == b'\x47':
with open('{}/image{}_slide{}.png'.format(images_path, picture_count, slide_count), 'wb') as f:
f.write(image_part.blob)
picture_count += 1
存在用于检查 PNG、JPEG 或 GIF 的 if 条件,因为 pptx.opc.package.Part
并不总是图像。
实际上,我想既然我正在检查 image_part.blob
的开头,我认为我不需要包括说 if type(image_part) == pptx.parts.image.ImagePart or pptx.opc.package.Part:
但只要它正常工作...
我很难尝试使用 python-pptx 库 access/save 图像。因此,如果图像的形状类型为 PICTURE
(即 shape.shape_type == MSO_SHAPE_TYPE.PICTURE
),我可以使用 'blob' 属性轻松 access/save 图像。这是代码:
import argparse
import os
from PIL import Image
import pptx
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx import Presentation
from mdutils.mdutils import MdUtils
from mdutils import Html
def main():
parser = argparse.ArgumentParser()
parser.add_argument('ppt_name', type=str, help='add the name of the PowerPoint file(NOTE: the folder must be in the same directory as the prorgram file')
args = parser.parse_args()
pptx_name = args.ppt_name
pptx_name_formatted = pptx_name.split('.')[0]
prs = Presentation(pptx_name)
path = '{}_converted'.format(pptx_name_formatted)
if not os.path.exists(path):
os.mkdir(path)
images_folder = '{}_images'.format(pptx_name_formatted)
images_path = os.path.join(path, images_folder)
if not os.path.exists(images_path):
os.mkdir(images_path)
ppt_dict = {} #Keys: slide numbers, values: slide content
texts = []
slide_count = 0
picture_count = 0
for slide in prs.slides:
texts = []
slide_count += 1
for shape in slide.shapes:
if shape.has_text_frame:
if '\n' in shape.text:
splitted = shape.text.split('\n')
for word in splitted:
if word != '':
texts.append(word)
elif shape.text == '':
continue
else:
texts.append(shape.text)
elif shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
with open('{}/image{}_slide{}.png'.format(images_path, picture_count, slide_count), 'wb') as f:
f.write(shape.image.blob)
picture_count += 1
ppt_dict[slide_count] = texts
ppt_content = ''
for k,v in ppt_dict.items():
ppt_content = ppt_content + ' - Slide number {}\n'.format(k)
for a in v:
ppt_content = ppt_content + '\t - {}\n'.format(a)
mdFile = MdUtils(file_name='{}/{}'.format(path,path)) #second argument isn't path, it just shares the path name.
mdFile.write(ppt_content)
mdFile.create_md_file()
if __name__ == "__main__":
main()
问题是当图片是形状类型'auto shape'时,我试了很多方法都没有用。当我执行 运行 时,我知道形状的以下代码是图片:
if shape.shape_type == MSO_SHAPE_TYPE.AUTO_SHAPE:
print(shape.auto_shape_type)
print(shape.fill.type)
#indented because it's in a for loop
它为 shape.auto_shape_type
RECTANGLE
和 PICTURE
对于 shape.fill.type
但我现在想要的是保存图片(可能通过写入图像的二进制图像字节流)。有人可以帮忙吗?
图像(部分,有斑点)的“link”在填充定义中。使用它你可以得到图像。
用shape.fill._xPr.xml
打印出XML周围的填充定义。这将使您了解需要导航到的内容。很有可能它看起来像 "rId9"
和一些特定的其他数字,其中“9”占位符在该示例中。可能在 "blipfill"
附近。该图像用作形状的“填充”,所以这就是这里发生的事情。
然后使用 slide._part
之类的东西获取幻灯片部分,并使用其 .related_parts
“dict”使用 relationship-id[= 查找图像“填充”部分38=](类似“rId9”的字符串)。
image_part = slide._part.related_parts["rId9"]
ImagePart
实现在这里:
https://github.com/scanny/python-pptx/blob/master/pptx/parts/image.py#L21
它提供了对图像的访问权限以及有关图像的大量详细信息。
您必须使用 lxml
调用来检索类似“rId9”的字符串,大致类似于:
rIds = shape.fill._xPr.xpath(".//@embed")
rId = rIds[0]
您需要对 XPath 进行一些研究,以根据您在前面的步骤中打印出的 XML 计算出正确的表达式。 XPath 上有很多内容,包括这里的 SO,这是一个入门资源:http://www.rpbourret.com/xml/XPathIn5.htm
如果您无法解决,post 您打印出来的 XML 我们可以帮助您进行下一步。
这是我的方法,感谢 scanny。
for slide in prs.slides:
slide_count += 1
slide_parts = list(slide._part.related_parts.keys())
for part in slide_parts:
image_part = slide._part.related_parts[part]
if type(image_part) == pptx.parts.image.ImagePart or pptx.opc.package.Part:
file_startswith = image_part.blob[0:1]
if file_startswith == b'\x89' or file_startswith == b'\xff' or file_startswith == b'\x47':
with open('{}/image{}_slide{}.png'.format(images_path, picture_count, slide_count), 'wb') as f:
f.write(image_part.blob)
picture_count += 1
存在用于检查 PNG、JPEG 或 GIF 的 if 条件,因为 pptx.opc.package.Part
并不总是图像。
实际上,我想既然我正在检查 image_part.blob
的开头,我认为我不需要包括说 if type(image_part) == pptx.parts.image.ImagePart or pptx.opc.package.Part:
但只要它正常工作...