TableStyle is overwritten by document style - python

Because the original project seems inactive I have to replicate my Issue here at StackOverflow.
It seems to me that the global document style does overwrite lower styles e.g. TableStyle. I assume I misunderstand the concept here.
See this code as an example
#!/usr/bin/env python3
import os
import docx
document = docx.Document()
document.styles['Normal'].font.name = 'Fira Mono'
document.styles['Normal'].font.size = docx.shared.Pt(8)
my_tab_style = document.styles.add_style('MyTab', docx.enum.style.WD_STYLE_TYPE.TABLE)
my_tab_style.font.name = 'Fira Sans'
my_tab_style.font.size = docx.shared.Pt(20)
p = document.add_paragraph('Should be Fira Mono 8pt')
tab = document.add_table(rows=1, cols=1, style='MyTab')
tab.rows[0].cells[0].text = 'Should be Fira Sans 20pt'
document.save('test.docx')
os.system('start test.docx')
I would expect the document text in "Fira Mono 8pt" and the table content in "Fira Sans 20pt". But it isn't.
When you outcomment the document style lines
# document.styles['Normal'].font.name = 'Fira Mono'
# document.styles['Normal'].font.size = docx.shared.Pt(8)
the table style is taken into account.

Related

cannot make text rtl with python-docx

yes i know many questions about this issue exists but i couldn't make any of them work.
i have python 3.7 and python-docx 0.8.11.
i have tried many solutions including this one
from docx import Document, enum
document = Document()
mystyle = document.styles.add_style('mystyle', enum.style.WD_STYLE_TYPE.CHARACTER)
run = document.add_paragraph().add_run(text)
run.style = mystyle
font = run.font
font.rtl = True
document.save('test.docx')
also
from docx import Document, enum
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
doc = Document()
rtlstyle = doc.styles.add_style('rtl', enum.style.WD_STYLE_TYPE.PARAGRAPH)
rtlstyle.font.rtl = True
p = doc.add_paragraph(text)
p.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
p.style = rtlstyle
doc.save('test.docx')
nothing worked so far
see this : https://stackoverflow.com/posts/73133074/revisions
also as mensiond here put this before your text: u'\u202B' + "your text"
or u'\u202E' if didn't work

How to apply strike-through using python-docx

My problem is that when I apply the strike-through or double strike-through formatting and save the file it is not reflected in output file.
Following code does not do the trick:
from docx import Document
document = Document()
p = document.add_paragraph()
p.add_run('Strike through the following text').strike = True
document.save('demo.docx')
This should do the job:
p.add_run('Strike through the following text').font.strike = True
strike is a property of the font object : docs
EDIT
If multiple font properties were to be changed the code should be :
sentence = p.add_run('Strike through the following text')
sentence.font.strike = True
sentence.font.name = 'Comic Sans MS'

How to change the font size of an python pptx object

I would like to change the font size of the title and of the body of my pptx-presentation. I tried to set it via title_shape.font = Pt(15) and body_shape.font = Pt(10), which does not work.
Here is my code:
from pptx import Presentation, util, text
from pptx.util import Cm, Pt
import fnmatch
import os
import contentOf_pptx as contOfPres
# ..............
# Generate presentation
# ..............
prs = Presentation()
#blank_slide_layout = prs.slide_layouts[6] #blank layout, see slide layout in powerpoint
title_only = prs.slide_layouts[5] #title only, see slide layout in powerpoint
# ..............
# set layout
# ..............
bullet_slide_layout = prs.slide_layouts[1]
slide = prs.slides.add_slide(bullet_slide_layout)
shapes = slide.shapes
title_shape = shapes.title
title_shape.font = Pt(15)
body_shape = shapes.placeholders[1]
body_shape.font = Pt(10)
# ..............
# set relevant text objects
# ..............
title_shape.text = 'Test Title'
tf = body_shape.text_frame
tf.text = 'Test SubText'
# ----------------------------------
# Store pptx
# ----------------------------------
prs.save('C:\\tests\\test_pptx_python.pptx')
A Shape object does not have a .font attribute (at least it didn't until you added one by assigning to that name :)
Font is characteristic of a Run object; a run is a sequence of characters that all share the same character formatting, also loosely known as a font.
A Paragraph object also has a .font property which is used the same way, but which specifies the default font for the runs in a paragraph. Individual runs in that paragraph can override that default by setting the attributes of their own font object.
If you only want one font for the shape (which is common), probably the fastest way is:
shape.text_frame.paragraphs[0].font.size = Pt(15)
which works because most shapes only contain a single paragraph (and all must contain at least one).
More thorough would be:
for paragraph in shape.text_frame.paragraphs:
paragraph.font.size = Pt(15)
and more thorough still would be:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
run.font.size = Pt(15)
More details on this are in the documentation here:
https://python-pptx.readthedocs.io/en/latest/user/text.html
Here is a simple approach that worked for me:
slide = prs.slides.add_slide(blank_slide_layout)
slide.shapes.title.text = "The Title of My Slide"
slide.shapes.title.text_frame.paragraphs[0].font.size = Pt(15)

Creating a table in python docx and use small_caps (python-docx)

This is what I have tried:
from docx import Document
from docx.shared import Inches
from docx.shared import Pt
table = document.add_table(rows= 3, cols = 1)
row = table.rows[0]
runner = row.cells[0].paragraphs[0].add_run('Summary')
runner.bold = True
runner.small_caps = True
document.save('demo.docx')
I am trying to create a table and small caps the text but cannot get the syntax right
I have figured how to use small caps for text.
runner_font = runner.font
runner_font.size = Pt(14)
runner_font.small_caps = True
runner_font.bold = True
I believe bold and italic are properties that built in under both add_run and font. But for small_caps, all_caps, color can be called under font only.

How does platypus "guess" bold and italic styles?

Here's my code. My first function is based on the /Lib/site-packages/reportlab/lib/styles.py source code, to create an array of style:
def create_styles(p_tuples):
retour = StyleSheet1()
parent = None
for p_name, font_name, font in p_tuples:
# (!) change path if Linux:
ttf_file = "C:/Windows/Fonts/{}.ttf".format(font)
pdfmetrics.registerFont(TTFont(font_name, ttf_file))
if parent is None:
p = ParagraphStyle(name=p_name,
fontName=font_name,
fontSize=10,
leading=12)
retour.add(p)
parent = p
else:
retour.add(ParagraphStyle(name=p_name,
parent=parent,
fontName=font_name,
fontSize=10,
leading=12))
return retour
Then I build my own array with my installed fonts:
def render_to_response(self, context, **response_kwargs):
# this is a response for Django, but the question is about styles
response = HttpResponse(content_type='application/pdf; charset=utf-8')
# ! Hint : no filename -> the browser extracts it from the URL!
# -> create URLs like http://pdfreportlab.com/extract/myfilename.pdf
# this is the way to go to have 100% working UTF-8 filenames!
response['Content-Disposition'] = 'attachment; filename=""'
my_styles = self.create_styles([
('ms-regular', 'montserrat-regular',
'Montserrat-Regular'),
('ms-black', 'montserrat-black',
'Montserrat-Black'),
('ms-black-italic', 'montserrat-black-italic',
'Montserrat-BlackItalic'),
('ms-bold', 'montserrat-bold',
'Montserrat-Bold'),
('ms-bold-italic', 'montserrat-bold-italic',
'Montserrat-BoldItalic'),
])
doc = SimpleDocTemplate(response)
elements = []
c = canvas.Canvas(response, pagesize=A4, )
for idx in my_styles.byName:
p = Paragraph("Hello World <i>italic</i> <b>bold</b>",
style=my_styles[idx])
width, height = p.wrapOn(c, A4[0], A4[1])
elements.append(p)
doc.build(elements)
return response
Everything is working except the (very annoying) fact that the <i></i> and <b></b> tags are ignored! It only uses the current font in the style.
How could you modify my code so that it takes in account the tags and I finally get styles with the tags in the text itself?
You need to register a font family if you want Platypus to auto-select fonts - you're creating a different style for every font variant so of course the <i> and <b> tags have no effect - it doesn't know what fonts to use for them as the passed style references a single font.
Here's how to build a style using a font family:
from reportlab.lib.styles import ParagraphStyle
from reportlab.pdfbase.pdfmetrics import registerFont, registerFontFamily
from reportlab.pdfbase.ttfonts import TTFont
def create_paragraph_style(name, font_name, **kwargs):
ttf_path = "C:/Windows/Fonts/{}.ttf"
family_args = {} # store arguments for the font family creation
for font_type in ("normal", "bold", "italic", "boldItalic"): # recognized font variants
if font_type in kwargs: # if this type was passed...
font_variant = "{}-{}".format(font_name, font_type) # create font variant name
registerFont(TTFont(font_variant, ttf_path.format(kwargs[font_type])))
family_args[font_type] = font_variant # add it to font family arguments
registerFontFamily(font_name, **family_args) # register a font family
return ParagraphStyle(name=name, fontName=font_name, fontSize=10, leading=12)
Then you can create your paragraph style as:
pstyle = create_paragraph_style("ms", "montserrat",
normal="Montserrat-Regular",
bold="Montserrat-Bold",
boldItalic="Montserrat-BoldItalic")
assuming, of course, that you have TTF files with those names in your fonts directory.
You can then add it to your stylesheet (especially if you want parent inheritance - make sure you add it as an argument to be forwarded to the ParagraphStyle creation) or directly use it as:
p = Paragraph("Hello World <i>italic</i> <b>bold</b> <b><i>boldItalic</i></b>", style=pstyle)
(the standalone italic won't be affected as we didn't define it in the family, tho).

Categories

Resources