Changing font for part of text in python-pptx - python

I'm using the python-pptx module to create presentations.
How can I change the font properties only for a part of the text?
I currently change the font like this:
# first create text for shape
ft = pres.slides[0].shapes[0].text_frame
ft.clear()
p = ft.paragraphs[0]
run = p.add_run()
run.text = "text"
# change font
from pptx.dml.color import RGBColor
from pptx.util import Pt
font = run.font
font.name = 'Lato'
font.size = Pt(32)
font.color.rgb = RGBColor(255, 255, 255)
Thanks!

In PowerPoint, font properties are applied to a run. In a way, it is what defines a run; a "run" of text sharing the same font treatment, including typeface, size, color, bold/italic, etc.
So to make two bits of text look differently, you need to make them separate runs.

As #scanny says in another post. The post
By "different run", it means you should write the text in first color in a run, then afterwards, write the text in the second color in another run as shown below.
There's also an example in the post, I'll just copy and paste it to here
from docx.shared import RGBColor
# ---reuse existing default single paragraph in cell---
paragraph = cell.paragraphs[0]
###(First run)
#---add distinct runs of text one after the other to
# --- form paragraph contents.
paragraph.add_run("A sentence with a ")
###(Second run)
# ---colorize the run with "red" in it.
red_run = paragraph.add_run("red")
red_run.font.color.rgb = RGBColor(255, 0, 0)
###(Third run)
paragraph.add_run(" word.")

Related

How to highlight all occurrences of a keyword in .pptx file using python

I am able to access the run level of the of the paragraph and also the cell of the table where the keyword is occurring but i don't know how to highlight it. I've read that Powerpoint stores data with uncertainty within runs so i can clear the runs and highlight the text but don't know how to do so here's my code.
from pptx import Presentation
import os
from pptx.dml.color import RGBColor
directory = "D:\Python_Scripts\Email Analysis"
keyword = "payable"
AttachmentsList = os.listdir(directory)
pptxList = list()
foundDocList = list()
for file in AttachmentsList:
if file.endswith(".pptx"):
pptxList.append(os.path.join(directory, file))
for ppt in pptxList:
prs = Presentation(ppt)
for slide in prs.slides:
for shape in slide.shapes:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
if keyword.lower() in run.text.lower():
# code to clear runs and highlight keywords
prs.save("output.pptx")
if shape.has_table:
for row in shape.table.rows:
for cell in row.cells:
if keyword.lower() in cell.text.lower():
# code to clear runs and highlight keywords
prs.save("output.pptx")
Does the following help?
def set_highlight(run, color):
# get run properties
rPr = run._r.get_or_add_rPr()
# Create highlight element
hl = OxmlElement("a:highlight")
# Create specify RGB Colour element with color specified
srgbClr = OxmlElement("a:srgbClr")
setattr(srgbClr, "val", color)
# Add colour specification to highlight element
hl.append(srgbClr)
# Add highlight element to run properties
rPr.append(hl)
return run
It's from my md2pptx open source project.

How to create a text shape with python pptx?

I want to add a text box to a presentation with python pptx. I would like to add a text box with several paragraphs in the specific place and then format it (fonts, color, etc.). But since text shape object always comes with the one paragraph in the beginning, I cannot edit first of my paragraphs. The code sample looks like this:
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
p = tf.add_paragraph()
p.text = "This is a first paragraph"
p.font.size = Pt(11)
p = tf.add_paragraph()
p.text = "This is a second paragraph"
p.font.size = Pt(11)
Which creates output like this:
I can add text to this first line with tf.text = "This is text inside a textbox", but it won't be editable in terms of fonts or colors. So is there any way how I can omit or edit that line, so all paragraphs in the box would be the same?
Access the first paragraph differently, using:
p = tf.paragraphs[0]
Then you can add runs, set fonts and all the rest of it just like with a paragraph you get back from tf.add_paragraph().

How to make text fit inside a python curses textbox?

I've tried many things attempting to make the text stay inside its borders but I can't find a way. Below is what I've already tried.
#!/usr/bin/env python
import curses
import textwrap
screen = curses.initscr()
screen.immedok(True)
try:
screen.border(0)
box1 = curses.newwin(20, 40, 6, 50)
box1.immedok(True)
text = "I want all of this text to stay inside its box. Why does it keep going outside its borders?"
box1.box()
box1.addstr(1, 0, textwrap.fill(text, 39))
#box1.addstr("Hello World of Curses!")
screen.getch()
finally:
curses.endwin()
Your first problem is that calling box1.box() takes up space in your box. It uses up the top row, the bottom row, the first column, and the last column. When you use box1.addstr() to put a string in a box, it starts at col 0, row 0, and so overwrites the box characters. After creating your borders, your box only has 38 available characters per line.
I'm not a curses expert, but one way of resolving this is to create a new box inside box1 that is inset by one character all the way around. That is:
box2 = curses.newwin(18,38,7,51)
Then you can write your text into that box without overwriting the box drawing characters in box1. It's also not necessary to call textwrap.fill; it appears that writing a string to a window with addstr automatically wraps the text. In fact, calling textwrap.fill can interact badly with the window: if text wrap breaks a line at exactly the window width, you may end up with an erroneous blank line in your output.
Given the following code:
try:
screen.border(0)
box1 = curses.newwin(20, 40, 6, 50)
box2 = curses.newwin(18,38,7,51)
box1.immedok(True)
box2.immedok(True)
text = "I want all of this text to stay inside its box. Why does it keep going outside its borders?"
text = "The quick brown fox jumped over the lazy dog."
text = "A long time ago, in a galaxy far, far away, there lived a young man named Luke Skywalker."
box1.box()
box2.addstr(1, 0, textwrap.fill(text, 38))
#box1.addstr("Hello World of Curses!")
screen.getch()
finally:
curses.endwin()
My output looks like this:
The box is part of the window, and uses the same real estate as the text. You can make a subwindow of the first window after drawing a box on the first window. Then write your wrapped text in the subwindow.
Something like
box1 = curses.newwin(20, 40, 6, 50)
box1.immedok(True)
text = "I want all of this text to stay inside its box. Why does it keep going outside its borders?"
box1.box()
box1.refresh()
# derwin is relative to the parent window:
box2 = box1.derwin(18, 38, 1,1)
box2.addstr(1, 0, textwrap.fill(text, 39))
See the description of derwin in the reference.

docx center text in table cells

So I am starting to use pythons docx library. Now, I create a table with multiple rows, and only 2 columns, it looks like this:
Now, I would like the text in those cells to be centered horizontally. How can I do this? I've searched through docx API documentation but I only saw information about aligning paragraphs.
There is a code to do this by setting the alignment as you create cells.
doc=Document()
table = doc.add_table(rows=0, columns=2)
row=table.add_row().cells
p=row[0].add_paragraph('left justified text')
p.alignment=WD_ALIGN_PARAGRAPH.LEFT
p=row[1].add_paragraph('right justified text')
p.alignment=WD_ALIGN_PARAGRAPH.RIGHT
code by: bnlawrence
and to align text to the center just change:
p.alignment=WD_ALIGN_PARAGRAPH.CENTER
solution found here: Modify the alignment of cells in a table
Well, it seems that adding a paragraph works, but (oh, really?) it addes a new paragraph -- so in my case it wasn't an option. You could change the value of the existing cell and then change paragraph's alignment:
row[0].text = "hey, beauty"
p = row[0].paragraphs[0]
p.alignment = docx.enum.text.WD_ALIGN_PARAGRAPH.CENTER
Actually, in the top answer this first "docx.enum.text" was missing :)
The most reliable way that I have found for setting he alignment of a table cell (or really any text property) is through styles. Define a style for center-aligned text in your document stub, either programatically or through the Word UI. Then it just becomes a matter of applying the style to your text.
If you create the cell by setting its text property, you can just do
for col in table.columns:
for cell in col.cells:
cell.paragraphs[0].style = 'My Center Aligned Style'
If you have more advanced contents, you will have to add another loop to your function:
for col in table.columns:
for cell in col.cells:
for par in cell.paragraphs:
par.style = 'My Center Aligned Style'
You can easily stick this code into a function that will accept a table object and a style name, and format the whole thing.
In my case I used this.
from docx.enum.text import WD_ALIGN_PARAGRAPH
def addCellText(row_cells, index, text):
row_cells[index].text = str(text)
paragraph=row_cells[index].paragraphs[0]
paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
font = paragraph.runs[0].font
font.size= Pt(10)
def addCellTextRight(row_cells, index, text):
row_cells[index].text = str(text)
paragraph=row_cells[index].paragraphs[0]
paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
font = paragraph.runs[0].font
font.size= Pt(10)
For total alignment to center I use this code:
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_ALIGN_VERTICAL
for row in table.rows:
for cell in row.cells:
cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
From docx.enum.table import WD_TABLE_ALIGNMENT
table = document.add_table(3, 3)
table.alignment = WD_TABLE_ALIGNMENT.CENTER
For details see a link .
http://python-docx.readthedocs.io/en/latest/api/enum/WdRowAlignment.html

ReportLab: Text with large font size is crammed within paragraph

Using ReportLab, I want to render a block of text with a large font size. Right now, my code places the text within a Paragraph so it can be word wrapped. However, the text turns out crammed together when rendered.
It seems like the height I specified for the Paragraph object is not being taken into account. Is there an attribute for Paragraph that I can add to fix this?
My Code Below:
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.platypus import Paragraph
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER
doc = canvas.Canvas('test.pdf')
p = ParagraphStyle('test')
p.textColor = 'black'
p.borderColor = 'black'
p.borderWidth = 1
p.alignment = TA_CENTER
p.fontSize = 100
para = Paragraph("THIS IS A REALLY LONG AND BIG STRING OF TEXT RIGHT HERE!!!!!", p)
para.wrapOn(doc,1200,1000)
para.drawOn(doc, 0.5*inch, 6*inch)
doc.save()
The answer is to set the leading attribute to 120:
p.leading = 120
By default, a style has a fontSize of 10 with a leading value of 12. The leading parameter specifies the distance down to move when advancing from one text line to the next.

Categories