python-pptx icon indicating copy to clipboard operation
python-pptx copied to clipboard

Can't change text without changing format and got exception when getting color

Open TenchiMuyo1984 opened this issue 1 year ago • 2 comments

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)

TenchiMuyo1984 avatar May 02 '23 19:05 TenchiMuyo1984

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

AM-ash-OR-AM-I avatar Jun 05 '23 09:06 AM-ash-OR-AM-I

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)

sedrew avatar Jun 06 '23 12:06 sedrew