I am writing a python program that open a docx file and writing text into it. using "aspose.words"
and I have two problems:
I have a problem that when I open a file its starting with the sentence
"Evaluation Only. Created with Aspose.Words. Copyright 2003-2021 Aspose Pty Ltd."
and I want to delete that line after I creating the file (I can delete it manually so it's deletable)
my second problem is when I am using "font.bold = True" on an english text it's working just fine but when I am using it on an text that in other language its doesen't work.
Someone know how can I solves those two problems (it's the first time I am using "aspose.words")
here is my code:
import aspose.words as aw
def main():
doc = aw.Document()
builder = aw.DocumentBuilder(doc)
writeDest(1, builder)
doc.save("out.docx")
def writeDest(designation, builder):
font = builder.font
font.size = 12
font.bold = True
font.name = "David"
paragraphFormat = builder.paragraph_format
paragraphFormat.alignment = aw.ParagraphAlignment.RIGHT
label = 'ייעוד: ' + str(designation)
builder.write(label)
builder.write("\n")
font.bold = False
if designation == 1:
file = open('destenationTextFiles/1', encoding="utf8")
for word in file:
builder.write(word)
builder.write('\n')
font.bold = True
builder.write(':תיקון ')
builder.write("\n")
font.bold = False
file.close()
file = open("destenationTextFiles/fixed1", encoding="utf8")
for word in file:
builder.write(word)
file.close()
if __name__ == "__main__":
main()
This message indicates you are using Aspose.Words in evaluation mode. Please see the following article to learn more about evaluation version limitations of Aspose.Words.
To test Aspose.Words for Python without these limitations you can request a temporary 30 days license.
To format right-to-left text you should use bidi font properties. For example see the following python code:
import aspose.words as aw
def main():
doc = aw.Document()
builder = aw.DocumentBuilder(doc)
# Define a set of font settings for left-to-right text.
builder.font.name = "Courier New"
builder.font.size = 16
builder.font.italic = False
builder.font.bold = False
builder.font.locale_id = 1033
# Define another set of font settings for right-to-left text.
builder.font.name_bi = "David"
builder.font.size_bi = 24
builder.font.italic_bi = True
builder.font.bold_bi = True
builder.font.locale_id_bi = 1037;
# We can use the Bidi flag to indicate whether the text we are about to add
# with the document builder is right-to-left. When we add text with this flag set to true,
# it will be formatted using the right-to-left set of font settings.
builder.font.bidi = True
builder.write("ברוך הבא")
# Set the flag to false, and then add left-to-right text.
# The document builder will format these using the left-to-right set of font settings.
builder.font.bidi = False
builder.write(" Hello world!")
doc.save("C:\\Temp\\Font.Bidi.docx")
if __name__ == "__main__":
main()
I'd like to generate an odf file with odfpy, and am stuck on underlining text.
Here is a minimal example inspired from official documentation, where i can't find any information about what attributes can be used and where.
Any suggestion?
from odf.opendocument import OpenDocumentText
from odf.style import Style, TextProperties
from odf.text import H, P, Span
textdoc = OpenDocumentText()
ustyle = Style(name="Underline", family="text")
#uprop = TextProperties(fontweight="bold") #uncommented, this works well
#uprop = TextProperties(attributes={"fontsize":"26pt"}) #this either
uprop = TextProperties(attributes={"underline":"solid"}) # bad guess, wont work !!
ustyle.addElement(uprop)
textdoc.automaticstyles.addElement(ustyle)
p = P(text="Hello world. ")
underlinedpart = Span(stylename=ustyle, text="This part would like to be underlined. ")
p.addElement(underlinedpart)
p.addText("This is after the style test.")
textdoc.text.addElement(p)
textdoc.save("myfirstdocument.odt")
Here is how I finally got it:
I created a sample document with underlining using libreoffice, and unzipped it. Looking in styles.xml part of the extracted files, I got the part that makes underlining in the document:
<style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text">
<style:text-properties fo:color="#000080" fo:language="zxx" fo:country="none" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/>
</style:style>
The interesting style attributes are named: text-underline-style,
text-underline-width and text-underline-color.
To use them in odfpy, '-' characters must be removed, and attributes keys must be used as str (with quotes) like in the following code. A correct style family (text in our case) must be specified in the Style constructor call.
from odf.opendocument import OpenDocumentText
from odf.style import Style, TextProperties
from odf.text import H, P, Span
textdoc = OpenDocumentText()
#underline style
ustyle = Style(name="Underline", family="text") #here style family
uprop = TextProperties(attributes={
"textunderlinestyle":"solid",
"textunderlinewidth":"auto",
"textunderlinecolor":"font-color"
})
ustyle.addElement(uprop)
textdoc.automaticstyles.addElement(ustyle)
p = P(text="Hello world. ")
underlinedpart = Span(stylename=ustyle, text="This part would like to be underlined. ")
p.addElement(underlinedpart)
p.addText("This is after the style test.")
textdoc.text.addElement(p)
textdoc.save("myfirstdocument.odt")
I need to write into a docx file from python (which i'm a bit new at) but i have to do it written rtl. After days of googling, the best I could do is this:
from docx import Document
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT as WD_STYLE_TYPE
from docx.shared import Pt
from docx.shared import Inches, Pt
# create docx file
document = Document()
# create paragraph
para = document.add_paragraph()
# create run
run = para.add_run("Hello World")
# create style
mystyle = document.styles.add_style("mystyle", 2)
run.style = mystyle
font = run.font
font.rtl = True # SET RIGHT TO LEFT
document.save(r"C:\Users\USER\Desktop\Code\TofesEfes\WordTes.docx")
the problem is that for some reason the code just ignores this line:
font.rtl = True # SET RIGHT TO LEFT
If I try to change it to:
font.bold = True # SET FONT TO BOLD
the font will come out bold.
I also tried changing the text to be in a rtl languge and nothin changed.
Does anyone here have any idea why it's doing this?
The intention is to transcribe .docx files to have modified font and font sizes while keeping the run attributes such as bold, underline, italic etc. I'll then add some headers and graphics to the newly created target.docx files
How to reconstruct paragraphs from runs? Each one, currently, gets it's own separate line!
from docx import Document
from docx.shared import Pt
def main(filename):
try:
src_doc = Document(filename)
trg_doc = Document()
style = trg_doc.styles['Normal']
font = style.font
font.name = 'Times'
font.size = Pt(11)
for p_cnt in range(len(src_doc.paragraphs)):
for r_cnt in range(len(src_doc.paragraphs[p_cnt].runs)):
curr_run = src_doc.paragraphs[p_cnt].runs[r_cnt]
print('Run: ', curr_run.text)
paragraph = trg_doc.add_paragraph()
if curr_run.bold:
paragraph.add_run(curr_run.text).bold = True
elif curr_run.italic:
paragraph.add_run(curr_run.text).italic = True
elif curr_run.underline:
paragraph.add_run(curr_run.text).underline = True
else:
paragraph.add_run(curr_run.text)
trg_doc.save('../Output/the_target.docx')
except IOError:
print('There was an error opening the file')
if __name__ == '__main__':
main("../Input/Current_File.docx
Input:
1.0 PURPOSE The purpose of this procedure is to ensure all feedback is logged, documented and any resulting complaints are received, evaluated, and reviewed in accordance with 21 CFR Part 820 and ISO 13485
Output:
PURPOSE The purpose of this procedure is to ensure
all feedback is logged,
documented and any resulting complaints are received,
evaluated, and reviewed
in accordance with 21 CFR P art 820
and ISO 13485 .
You're adding a new paragraph for each run. Your core loop needs to look more like this:
for src_paragraph in src_doc.paragraphs:
tgt_paragraph = tgt_doc.add_paragraph()
for src_run in src_paragraph.runs:
print('Run: ', src_run.text)
tgt_run = tgt_paragraph.add_run(src_run.text)
if src_run.bold:
tgt_run.bold = True
if src_run.italic:
tgt_run.italic = True
if src_run.underline:
tgt_run.underline = True
Replaced
for p_cnt in range(len(src_doc.paragraphs)):
for r_cnt in range(len(src_doc.paragraphs[p_cnt].runs)):
curr_run = src_doc.paragraphs[p_cnt].runs[r_cnt]
Where the construction of runs occur I use a construction similar to that suggested by Scanny. Here each run doesn't become a paragraph.
src_doc = docx.Document(path)
trgt_doc = docx.api.Document()
# Generate new Target file from Source File
for src_paragraph in src_doc.paragraphs:
src_paragraph_format = src_paragraph.paragraph_format
# Get Target section(s) for Headers/Footers
sections = trgt_doc.sections
section = sections[0]
sectPr = section._sectPr
footer = section.footer
paragraph = footer.paragraphs[0]
trgt_paragraph = trgt_doc.add_paragraph()
trgt_paragraph_format = trgt_paragraph.paragraph_format
trgt_paragraph.style.name = src_paragraph.style.name
trgt_paragraph_format.left_indent = src_paragraph_format.left_indent
trgt_paragraph_format.right_indent = src_paragraph_format.right_indent
trgt_paragraph_format.space_before = Pt(2)
trgt_paragraph_format.space_after = Pt(2)
font = trgt_paragraph.style.font
font.name = 'Times'
font.size = Pt(11)
# Transcribe source file runs
for src_run in src_paragraph.runs:
trgt_run = trgt_paragraph.add_run(src_run.text)
trgt_paragraph_format = trgt_paragraph.paragraph_format
if src_run.font.highlight_color == WD_COLOR_INDEX.BRIGHT_GREEN:
trgt_run.font.highlight_color = WD_COLOR_INDEX.BRIGHT_GREEN
if src_run.bold:
trgt_run.bold = True
if src_run.italic:
trgt_run.italic = True
if src_run.underline:
trgt_run.underline = True*
I am using python 2.7 with docx and I would like to change the background and text color of cells in my table based on condition.
I could not find any usefull resources about single cell formatting
Any suggestions?
Edit 1
my code
style_footer = "DarkList"
style_red = "ColorfulList"
style_yellow = "LightShading"
style_green = "MediumShading2-Accent6"
style_transperent = "TableNormal"
for a,rec in enumerate(data):
#V headinh se piše prvo polje iz table heada
document.add_heading(rec['tableHead'][0][0], level=1)
image_path = imageFolder + "\\" + slike[a]
document.add_picture(image_path, height=Inches(3.5))
#y += 28
#worksheet.insert_image( y, 1,imageFolder + "/" + slike[a])
for i, head in enumerate(rec['tableHead']):
table = document.add_table(rows=1, cols = len(head))
hdr_cells = table.rows[0].cells
for a in range(0,len(head)):
hdr_cells[a].text = head[a]
for a,body in enumerate(rec['tableData']):
row_cells = table.add_row().cells
for a in range(0,len(body)):
if body[a]['style'] == 'footer':
stil = style_footer
elif body[a]['style'] == 'red':
stil = style_red
elif body[a]['style'] == 'yellow':
stil = style_yellow
elif body[a]['style'] == 'green':
stil = style_green
else:
stil = style_transperent
row_cells[a].add_paragraph(body[a]['value'], stil)
document.save(wordDoc)
All cells are still the same.
If you want to color fill a specific cell in a table you can use the code below.
For example let's say you need to fill the first cell in the first row of your table with the RGB color 1F5C8B:
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
shading_elm_1 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
table.rows[0].cells[0]._tc.get_or_add_tcPr().append(shading_elm_1)
Now if you want to also fill the second cell in the first row with the same color, you should create a new element
otherwise if you use the same element as above the fill will move on and will disappear from the first cell...
shading_elm_2 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
table.rows[0].cells[1]._tc.get_or_add_tcPr().append(shading_elm_2)
...and so on for other cells.
Source: https://groups.google.com/forum/#!topic/python-docx/-c3OrRHA3qo
With Nikos Tavoularis' solution, we have to create a new element for every cell.
I have created a function that achieves this. Works in Python revision 3.5.6 and python-docx revision 0.8.10
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
def set_table_header_bg_color(table.rows[row_ix].cell):
"""
set background shading for Header Rows
"""
tblCell = cell._tc
tblCellProperties = tblCell.get_or_add_tcPr()
clShading = OxmlElement('w:shd')
clShading.set(qn('w:fill'), "00519E") #Hex of Dark Blue Shade {R:0x00, G:0x51, B:0x9E}
tblCellProperties.append(clShading)
return cell
"""
End of set_table_header_bg_color Function
"""
# main function
"""
..
..
..
1. Load Document
..
2. Access the required section
..
3. Load the required Table
..
4. Traverse to the cell by accessing the rows object
..
"""
for each_row in table.rows :
for each_cell in each_row.cells:
if each_cell.value satisfies a condition:
set_table_header_bg_color(each_cell)
"""
5. Continue execution
"""
What we found is that, if you do cell.add_paragraph('sometext', style_object), it will keep the existing empty paragraph and add an additional paragraph with the style, which is not ideal.
What you will want to do is something like:
# replace the entire content of cell with new text paragraph
cell.text = 'some text'
# assign new style to the first paragraph
cell.paragraphs[0].style = style_object
Note that the style is applied to the paragraph not the cell, which isn't ideal for background colors (since it won't fill the enter cell if you have some padding. I haven't found a way around that (except in the case where you want EVERY cell to have a background color, you can apply a style to table.style).
Also, make sure that your styles are defined. You can check
styles = documents.styles
for s in styles:
print s.name
to see all the styles you have. You can define new styles and also load a template document with pre-defined styles already.
It looks like instead of using the cell.text = "Something" method you need to use the cell.add_paragraph("SomeText", a_style) with a defined style - probably one of:
ColorfulGrid
ColorfulGrid-Accent1
ColorfulGrid-Accent2
ColorfulGrid-Accent3
ColorfulGrid-Accent4
ColorfulGrid-Accent5
ColorfulGrid-Accent6
Full list here.
If you use the “default” template document - otherwise you will have to create your own.
Taking from Nikos Tavoularis answer I would just change the shading_elm_1 declaration, as if you include the cell color in a loop for instance things might get messy.
As such, my suggestion would be:
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
table.rows[0].cells[0]._tc.get_or_add_tcPr().append(parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w'))))
I made a video demonstrating a way to do it here I took inspiration from the people above but I still had issues so I made this too help others.
https://www.youtube.com/watch?v=1Mgb95yigkk&list=PL_W7lgC2xeJfWBUllp7ALKOM5GUBMCVoP
from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
document = Document("youfile.docx")
Table = document.tables[0]
#GET CELLS XML ELEMENT
cell_xml_element = Table.rows[1].cells[0]._tc
#RETRIEVE THE TABLE CELL PROPERTIES
table_cell_properties = cell_xml_element.get_or_add_tcPr()
#CREATE SHADING OBJECT
shade_obj = OxmlElement('w:shd')
#SET THE SHADING OBJECT
shade_obj.set(qn('w:fill'), "ff00ff")
#APPEND THE PROPERTIES TO THE TABLE CELL PROPERTIES
table_cell_properties.append(shade_obj)
document.save("yoursavefile.docx")
The code above will change the first cellof the second row of the first table in the document.Example of the output.
If you want to loop through the cells in a row use:
def color_row(row=0):
'make row of cells background colored, defaults to column header row'
row = t.rows[row]
for cell in row.cells:
shading_elm_2 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
cell._tc.get_or_add_tcPr().append(shading_elm_2)
run the function to color cells in the second row
color_row(2)
If you want to change the text color too, you can set it on the runs within the cell. I wrote this function to handle the cell background and text colors together (using Nikos' method for the fill):
def shade_cell(cell, fill=None, color=None):
if fill:
shading_elm = parse_xml(r'<w:shd {} w:fill="{}"/>'.format(nsdecls('w'), fill))
cell._tc.get_or_add_tcPr().append(shading_elm)
if color:
for p in cell.paragraphs:
for r in p.runs:
r.font.color.rgb = RGBColor.from_string(color)
I originally tried to expand Nikos' solution by adding w:color="XXXXXX" to the w:shd tag but that didn't work for me. However setting the font color on each run got the result I wanted.
I have compiled the previous answers and added some features.
Feel free to test: Create new file run the "main" part at the bottom.
""" adder for python-docx in order to change text style in tables:
font color, italic, bold
cell background color
based on answers on
https://stackoverflow.com/questions/26752856/python-docx-set-table-cell-background-and-text-color
"""
import docx # import python-docx (in order to create .docx report file)
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
def change_table_cell(cell, background_color=None, font_color=None, font_size=None, bold=None, italic=None):
""" changes the background_color or font_color or font style (bold, italic) of this cell.
Leave the params as 'None' if you do not want to change them.
params:
cell: the cell to manipulate
background_color: name for the color, e.g. "red" or "ff0000"
font_color:
font_size: size in pt (e.g. 10)
bold: requested font style. True or False, or None if it shall remain unchanged
italic: requested font style. True or False, or None if it shall remain unchanged
background_color: the color of cells background"""
if background_color:
shading_elm = parse_xml(r'<w:shd {} w:fill="{}"/>'.format(nsdecls('w'), background_color))
cell._tc.get_or_add_tcPr().append(shading_elm)
if font_color:
for p in cell.paragraphs:
for r in p.runs:
r.font.color.rgb = docx.shared.RGBColor.from_string(font_color)
if font_size:
for p in cell.paragraphs:
for r in p.runs:
r.font.size = docx.shared.Pt(font_size)
if bold is not None:
for p in cell.paragraphs:
for r in p.runs:
r.bold = bold
if italic is not None:
for p in cell.paragraphs:
for r in p.runs:
r.italic = italic
def change_table_row(table_row, background_color=None, font_color=None, font_size=None, bold=None, italic=None):
for cell in table_row.cells:
change_table_cell(cell, background_color=background_color, font_color=font_color, font_size=font_size,
bold=bold,
italic=italic)
if __name__ == "__main__": # do the following code only if we run the file itself
#document = docx.Document('template.docx') # create an instance of a word document, use the style that we have defined in 'template.docx'
document = docx.Document()
num_rows = 4
num_cols = 3
table = document.add_table(rows=num_rows, cols=num_cols) # create empty table
#table.style = document.styles['MyTableStyleBlue'] # test overwriting the predefined style
# fill table
for row in range(num_rows):
for col in range(num_cols):
table.rows[row].cells[col].text = f'row/col=({row},{col})'
""" change color (see https://stackoverflow.com/questions/26752856/python-docx-set-table-cell-background-and-text-color) """
# Nikos Tavoularis answered Apr 18, 2017 at 8:38
shading_elm_1 = parse_xml(r'<w:shd {} w:fill="1F5C8B"/>'.format(nsdecls('w')))
table.rows[0].cells[0]._tc.get_or_add_tcPr().append(shading_elm_1)
# test new function derived from dyoung's answere of May 25 at 7:34, 2022
change_table_cell(table.rows[0].cells[0], background_color=None, font_color="ff0000", bold=False)
change_table_cell(table.rows[1].cells[2], background_color="00ff00", font_color="ff0000", font_size=20, bold=True)
change_table_row(table.rows[3], background_color="lightgreen", font_color="0000ff", italic=True) # https://www.delftstack.com/howto/python/colors-in-python/
document.save('table_shading_test.docx')