python-pptx
python-pptx copied to clipboard
Can't change text without changing format and got exception when getting color
Versions: Python: 3.10.8 python-pptx: 0.6.21 PowerPoint: (Office 2013 and Microsoft 365)
I'm facing a bug.
When I just replace the text of a text_frame
it'll change the format of the text also.
font-size, font-color, bolt, underline, etc.
import pptx
prs = pptx.Presentation("test2.pptx")
slide = prs.slides[0]
shp = slide.shapes
print(shp[1].text_frame.text)
shp[1].text_frame.text = "new text"
print(shp[1].text_frame.text)
prs.save("test3.pptx")
How the input and output looks like: Unbenannt_2023_05_02
The two files as reference: test2.pptx test3.pptx
My idea was to get the color, format, etc. and apply after changing, but I got an exception:
Traceback (most recent call last):
File "D:\Python\sandbox\pptx-editor.py", line 12, in <module>
print(shp[1].text_frame.paragraphs[0].font.color.rgb)
File "D:\Python\sandbox\venv\lib\site-packages\pptx\dml\color.py", line 61, in rgb
return self._color.rgb
File "D:\Python\sandbox\venv\lib\site-packages\pptx\dml\color.py", line 171, in rgb
raise AttributeError(tmpl % self.__class__.__name__)
AttributeError: no .rgb property on color type '_NoneColor'
With this added to the code on top:
print(shp[1].text_frame.paragraphs[0].font.color.rgb)
here's a way to do this:
import pptx
prs = pptx.Presentation("test2.pptx")
for slide in prs.slides:
for shape in slide.shapes:
text_frame = slide.text_frame
for paragraph in text_frame.paragraphs:
for run in paragraph.runs:
run.text = "Your text"
This should work. It makes sure that formatting is kept. PS: There are several more conditions that you can add for group shapes formatting etc.. like
if shape.shape_type == MSO_SHAPE_TYPE.GROUP:
recursively_search(shape.shapes)
also you may need additional checks like: shape.has_text_frame
Use the petpptx package, this is an updated fork of python-pptx
python -m pip install petpptx
Saved previous font style
font_style= text_frame.paragraphs[0].runs[0].font
text_frame.clear()
run = text_frame.paragraphs[0].add_run()
run.font = font_style
run.text = "Hello World"
Copied font
font_style= text_frame.paragraphs[0].runs[0].font
text_frame.paragraphs[0].runs[1].font = deepcopy(font_style)