I want to replace the text in a textbox in Powerpoint with Python-pptx.
Everything I found online didn't work for me and the documentation isn't that helpful for me.
So I have a Textbox with the Text:
$$Name 1$$
$$Name 2$$
and I want to change the $$Name1 $$ to Tom.
How can I achieve that?
A TextFrame object defined in python-pptx helps in manipulating contents of a textbox. You can do something like:
from python-pptx import Presentation
"""open file"""
prs = Presentaion('pptfile.pptx')
"""get to the required slide"""
slide = prs.slides[0]
"""Find required text box"""
for shape in slide.shapes:
if not shape.has_text_frame:
continue
text_frame = shape.text_frame
if "Name 1" == text_frame.text:
text_frame.text = "Tom"
"""save the file"""
prs.save("pptfile.pptx")
Try this:
import pptx
input_pptx = "Input File Path"
prs = pptx.Presentation((input_pptx))
testString = "$$Name1 $$"
replaceString = 'Tom'
title_slide_layout = prs.slide_layouts[0]
slide = prs.slides.add_slide(title_slide_layout)
for slide in prs.slides:
for shape in slide.shapes:
if shape.has_text_frame:
if(shape.text.find(testString))!=-1:
shape.text = shape.text.replace(testString, replaceString)
if not shape.has_table:
continue
prs.save('C:/test.pptx')
Ok thank you. I just found out, that my PowerPoint example was totaly messed up. No everything works fine with a new PowerPoint blanked
In order to keep original formatting, we need to replace the text at the run level.
from pptx import Presentation
ppt = Presentation(file_path_of_pptx)
search_str = '$$Name1$$'
replace_str = 'Tom'
for slide in ppt.slides:
for shape in slide.shapes:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
print(run.text)
if(run.text.find(search_str))!=-1:
run.text = run.text.replace(search_str, replace_str)
ppt.save(file_path_of_new_pptx)
Since PowerPoint splits the text of a paragraph into seemingly random runs (and on top each run carries its own - possibly different - character formatting) you can not just look for the text in every run, because the text may actually be distributed over a couple of runs and in each of those you'll only find part of the text you are looking for.
Doing it at the paragraph level is possible, but you'll lose all character formatting of that paragraph, which might screw up your presentation quite a bit.
Using the text on paragraph level, doing the replacement and assigning that result to the paragraph's first run while removing the other runs from the paragraph is better, but will change the character formatting of all runs to that of the first one, again screwing around in places, where it shouldn't.
Therefore I wrote a rather comprehensive script that can be installed with
python -m pip install python-pptx-text-replacer
and that creates a command python-pptx-text-replacer that you can use to do those replacements from the command line, or you can use the class TextReplacer in that package in your own Python scripts. It is able to change text in tables, charts and wherever else some text might appear, while preserving any character formatting specified for that text.
Read the README.md at https://github.com/fschaeck/python-pptx-text-replacer for more detailed information on usage. And open an issue there if you got any problems with the code!
Also see my answer at python-pptx - How to replace keyword across multiple runs? for an example of how the script deals with character formatting...
Related
how to make an input appear at the bottom of the terminal/console?
with
import Console
a = Console.getconsole()
a.text(0,-1,'YOU CAN PRINT TEXT IN THE BOTTOM ROW OF CONSOLE')
you can print text in the bottom of the console, but you can't input. how can you make an input at the bottom of the console?
Click to see image
More detailed picture
Im getting answers that are not what im searching exactly for but i understand them. Other option for me it would be have 2 consoles and whain i imput something in console1 smething happens to console2.
Functions or libraries are not available to fulfill the desired output then there is always a way to achieve the result by logic.
print('abc')
a="\n"*10
x= input(a+'Enter here :')
print(x)
The console (or terminal) in python works in a way that it goes to the next available line. However, you can use the get_terminal_size() method to do complete the task.
What one could do is add many blank lines like this:
import os
# Get the size of the terminal
size = os.get_terminal_size()
print('number of rows', size.lines)
a="\n"*(size.lines - 2)
name= input(a+'what is your name?')
print('hello', name)
which would look like this:
I'm trying to copy texts from the word document into a PowerPoint text box using Python. I want all the texts in the word document in the exact same formatting into one PowerPoint text box. The problem here is some of the paragraphs are in bold and some are not. I'm not sure if this is even possible. Please see below how the word doc looks like:-
Word Doc
And this is how it should look like in the ppt (In one text box)
PowerPoint
I'm using python docx and pptx library but I'm not expert in them. Please help!
Edit:
some of the things I've tried so far:-
I found one code to copy texts with styles but it is for word to word.
def get_para_data(output_doc_name, paragraph):
"""
Write the run to the new file and then set its font, bold, alignment, color etc. data.
"""
output_para = output_doc_name.add_paragraph()
for run in paragraph.runs:
output_run = output_para.add_run(run.text)
# Run's bold data
output_run.bold = run.bold
# Run's italic data
output_run.italic = run.italic
# Run's underline data
output_run.underline = run.underline
# Run's color data
output_run.font.color.rgb = run.font.color.rgb
# Run's font data
output_run.style.name = run.style.name
# Paragraph's alignment data
output_para.paragraph_format.alignment = paragraph.paragraph_format.alignment
input_doc = Document('InputDoc.docx')
output_doc = Document()
# Call the function
get_para_data(output_doc, input_doc.paragraphs[3])
# Save the new file
output_doc.save('OutputDoc.docx')
Please let me know how to do this from word to PowerPoint.
I wanted change the all fonts in about 100 powerpoint files, without opening the files. There are several shape types in each slide and each might have a different font. I used python-pptx package and wrote the following code to change the fonts of all texts in a powerpoint presentation. Although it does not give any error, it does not work, and the fonts in the file are still whatever they were, for example Arial. I also added print(shape.text) to make sure that it has found all texts, and it seems that there is no issue there. Is it a bug? Or am I missing anything?
prs = Presentation('f10.pptx')
for i, slide in enumerate(prs.slides):
for shape in slide.shapes:
print (shape.has_text_frame)
if shape.has_text_frame:
print(shape.text)
for p in shape.text_frame.paragraphs:
for r in p.runs:
print(r.font.name)
r.font.name = 'Tahoma'
print(r.font.name)
prs.save('f10_tahoma.pptx')
Besides, it seems that the package does not work for utf-8 characters. I added a text-box on the last slide by adding:
text_frame = shape.text_frame
text_frame.clear() # not necessary for newly-created shape
p = text_frame.paragraphs[0]
run = p.add_run()
run.text = 'سلام '
font = run.font
font.name = 'Andalus'
font.size = Pt(18)
before saving the file to add a textbox with utf-8 characters. It adds it there, and when I check the font it shows that it is set to Andalus, but actually it is not Andalus.
With Aspose.Slides for Python via .NET, you can easily change all fonts for all texts in your presentations. The following code example shows you how to do this:
import aspose.slides as slides
with slides.Presentation('example.pptx') as presentation:
for slide in presentation.slides:
for shape in slide.shapes:
if isinstance(shape, slides.AutoShape):
for paragraph in shape.text_frame.paragraphs:
for portion in paragraph.portions:
portion.portion_format.latin_font = slides.FontData('Tahoma')
You can also evaluate Aspose.Slides Cloud SDK for Python for presentation manipulating. This REST-based API allows you to make 150 free API calls per month for API learning and presentation processing.
Aspose Slides Online Viewer can be used to view presentations without PowerPoint installed.
I work at Aspose.
What language is the text of the file? Run.font properties work fine for UTF-8, but there is a separate font for cursive scripts like Arabic. Access to that secondary font is not implemented in python-pptx unfortunately, but that could explain at least part of the behavior you're seeing.
For roman character text (like that we're using here), there are a couple things to check.
The font in question needs to be installed on the machine PowerPoint is running on when the document is opened. Otherwise PowerPoint will substitute a font.
The font (typeface) name used in the XML will not always exactly match what appears in the PowerPoint drop-down selection box. You need to give that name to python-pptx in the exact form it should appear in the XML. You may need to make an example file that works by hand, perhaps containing a single slide with a single textbox for simplicity, and then inspect the XML of that file to find the "spelling" used for that typeface by PowerPoint.
You could do that with code like this:
prs = Presentation("example.pptx")
shape = prs.slides[0].shapes[0]
print(shape._element.xml)
You should be able to locate the typeface name somewhere in an element like <p:rPr> or <p:defRPr>.
Just starting to try to use python-pptx, and have fallen at the first. Linux Mint 20.1, python 3.85, LibreOffice 6.4.
This is basically the 'Hello World' from the documentation.
from pptx import Presentation
from pptx.util import Inches, Pt
prs = Presentation()
blank_slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(blank_slide_layout)
left = top = width = height = Inches(1)
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
print('before text ', txBox.left, txBox.top, txBox.width, txBox.height)
tf.text = "This is a long line of text inside a textbox"
print('after text ', txBox.left, txBox.top, txBox.width, txBox.height)
prs.save('test.pptx')
The text is more than a single line for the textbox. Printing out its bounds before and after text insertion shows that as far as python-pptx is concerned, the textbox width hasn't changed.
When the resulting presentation is viewed in LibreOffice, instead of wrapping the text within its boundaries, the textbox has expanded symmetrically around the mid point, pushing the start of the text off the lefthand edge of the page.
I was hoping the LibreOffice was only incompatible with powerpoint for rare edge cases, but text in text boxes is the meat and bread of presentations.
When I upload it to google slides, the text wraps within the left and right text box boundaries, but spills out of the bottom edge. The textbox shows up as 1" x 1" in the right place.
If I use onedrive.live.com, the text is left justified in the box and spills out of the righthand side without wrapping, and the textbox is shown as being 1" x 1" in the right place.
If I use onlinedocumentviewer.com, the display is the same as onedrive, though I can't get to see the text box.
Unfortunately I can't test the behaviour on a native powerpoint installation.
Maybe there's an autosize or fixed flag, which left unset leaves each viewer defaulting it in its own idiosyncratic way? How do we control text boxes / frames when targetting LibreOffice?
I possibly have a workaround to break up my text into single lines and use one per text box, but I'd rather understand the whether it can be done the proper way.
After some floundering around in the docs, I stumbled across the text_frame .word_wrap property. Setting to True gets the text to wrap in LibreOffice. While I was there, setting text_frame.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE reduces font size to get it all to fit in the box.
Is there a list of properties like .word_wrap in one place anywhere?
It seems this issue was brought up and requested back in 2015 but I cannot find any updates on it. I'm trying to copy an entire slide (including its text and images) from another presentation into my working presentation by doing something like the following:
prs = Presentation('CurrentPresentation.pptx')
prs1 = Presentation('OtherPresentation.pptx')
# Wanted_Slide = prs1.slides[0]
New_Slide = prs.slides.add_slide(prs1.slide_layout[0])
But all this does is add a totally blank slide (with the wanted slide's background) with slide layout 0, which totally makes sense. I know that's not the right way to do it. I tried the below and it did add a slide, but it was just a duplicate one of what was already in the prs presentation (I guess I found a way to duplicate a slide already in the presentation inadvertently):
def Add_Slide(self):
xml_slides = prs.slides._sldIdLst
xml_slides1 = prs1.slides._sldIdLst
slides = list(xml_slides)
slides1 = list(xml_slides1)
xml_slides.append(slides1[0])
The above code is a manipulation of a slide delete method I found online.
Or does anyone have any sort of recommendation on how to completely copy a slide and all of its contents over to a working presentation?
I apologize if no developments have been made and this post is a rehash. Thank you in advance.
There's an issue in the library's repo that has some code to do this, but it's rough, it doesn't work for all cases.
from pptx.parts.chart import ChartPart
from pptx.parts.embeddedpackage import EmbeddedXlsxPart
from pptx import Presentation
import copy
def _get_blank_slide_layout(pres):
layout_items_count = [len(layout.placeholders) for layout in pres.slide_layouts]
min_items = min(layout_items_count)
blank_layout_id = layout_items_count.index(min_items)
return pres.slide_layouts[blank_layout_id]
def move_slide(pres1, pres, index):
"""Duplicate the slide with the given index in pres1 and "moves" it into pres.
Adds slide to the end of the presentation"""
source = pres1.slides[index]
blank_slide_layout = _get_blank_slide_layout(pres)
dest = pres.slides.add_slide(blank_slide_layout)
for shape in source.shapes:
newel = copy.deepcopy(shape.element)
dest.shapes._spTree.insert_element_before(newel, 'p:extLst')
for key, value in source.part.rels.items():
# Make sure we don't copy a notesSlide relation as that won't exist
if "notesSlide" not in value.reltype:
target = value._target
# if the relationship was a chart, we need to duplicate the embedded chart part and xlsx
if "chart" in value.reltype:
partname = target.package.next_partname(
ChartPart.partname_template)
xlsx_blob = target.chart_workbook.xlsx_part.blob
target = ChartPart(partname, target.content_type,
copy.deepcopy(target._element), package=target.package)
target.chart_workbook.xlsx_part = EmbeddedXlsxPart.new(
xlsx_blob, target.package)
dest.part.rels.add_relationship(value.reltype, target,value.rId)
This function is an alteration of what is on the github comments at the location cited above. It works well for me, haven't tested it with charts or anything. It's slightly altered from what was posted on the site, because there was the rough example noted by the original answer, and there was a more thorough answer for duplicating within a presentation. Figured I'd post since it took me a while to get this all put together.
This solution has mainly worked with one exception. After copying the slide over to the destination presentation when I open the destination presentation I get the following warning:
PowerPoint couldn't read some content in xxx.pptx and removed it. Please check your presentation to see if the rest of it looks ok.
The rest of the presentation does look fine and after saving and reopening the warning goes away. Do you know of a way to make it so this warning doesn't appear or if there is a way to resolve it with Python (saving/closing again?).