Add replace_medias() utility (useful for header/footer images)

This commit is contained in:
Eric Lapouyade 2017-09-03 20:36:31 +02:00
parent a4fa1b4f26
commit b7947ca10c
17 changed files with 72 additions and 2 deletions

View File

@ -1,3 +1,7 @@
0.4.0 (2017-09-03)
------------------
- Add replace_medias() utility (useful for header/footer images)
0.3.9 (2017-06-27)
------------------
- Fix exception in fix_table()

View File

@ -165,6 +165,20 @@ in your python code ::
in your docx template just use ``{{ mylisting }}``
With ``Listing()``, you will keep the current character styling (except after a ``\a`` as you start a new paragraph).
Replace docx medias
-------------------
It is not possible to dynamically add images in header/footer, but you can change them.
The idea is to put a dummy picture in your template, render the template as usual, then replace the dummy picture with another one.
You can do that for all medias at the same time.
Note: for images, the aspect ratio will be the same as the replaced image
Note2 : it is important to have the source media files as they are required to calculate their CRC to find them in the docx
Syntax to replace dummy_header_pic.jpg and dummy2.jpg in mydoc.docx::
replace_medias('mydoc.docx',[('dummy_header_pic.jpg','header_pic_i_want.jpg'),('dummy2.png','mycompany.png')])
Jinja custom filters
--------------------

View File

@ -5,7 +5,7 @@ Created : 2015-03-12
@author: Eric Lapouyade
'''
__version__ = '0.3.9'
__version__ = '0.4.0'
from lxml import etree
from docx import Document
@ -14,6 +14,9 @@ from jinja2 import Template
from cgi import escape
import re
import six
import binascii
import os
import zipfile
NEWLINE = '</w:t><w:br/><w:t xml:space="preserve">'
NEWPARAGRAPH = '</w:t></w:r></w:p><w:p><w:r><w:t xml:space="preserve">'
@ -297,6 +300,35 @@ class InlineImage(object):
def __str__(self):
return self.xml
def replace_medias(docx_filename,src_dst_lst):
"""Utility function replace any media by another into a docx
This has been done mainly because it is not possible to add images in docx header/footer.
With this function, put a dummy picture in your header/footer, then specify it with its replacement in this function
Syntax: replace_medias('mydoc.docx',[('dummy_header_pic.jpg','header_pic_i_want.jpg'),('dummy2.png','mycompany.png')])
Note: for images, the aspect ratio will be the same as the replaced image
Note2 : it is important to have the source media files as they are required to calculate their CRC to find them in the docx
"""
crc_to_new_media = {}
for src,dst in src_dst_lst:
with open(src,'rb') as fh:
buf = fh.read()
crc = (binascii.crc32(buf) & 0xFFFFFFFF)
with open(dst,'rb') as fh:
crc_to_new_media[crc] = fh.read()
backup_filename = '%s_before_replace_medias' % docx_filename
os.rename(docx_filename,backup_filename)
with zipfile.ZipFile(backup_filename) as zin:
with zipfile.ZipFile(docx_filename, 'w') as zout:
for item in zin.infolist():
buf = zin.read(item.filename)
if item.filename.startswith('word/media/') and item.CRC in crc_to_new_media:
zout.writestr(item, crc_to_new_media[item.CRC])
else:
zout.writestr(item, buf)
os.remove(backup_filename)

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
'''
Created : 2017-09-03
@author: Eric Lapouyade
'''
from docxtpl import DocxTemplate, replace_medias
DEST_FILE = 'test_files/header_footer_image.docx'
tpl=DocxTemplate('test_files/header_footer_image_tpl.docx')
context = {
'mycompany' : 'The World Wide company',
}
tpl.render(context)
tpl.save(DEST_FILE)
replace_medias(DEST_FILE,[('test_files/dummy_pic_for_header.png','test_files/python.png')])

View File

@ -2,7 +2,7 @@ import subprocess
import glob
import six
tests = glob.glob('[A-Za-z]*.py')
tests = sorted(glob.glob('[A-Za-z]*.py'))
excludes = ['runtests.py']
for test in tests:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.