It seems the module docx
doesn't work with EMF
files.
The work around that I mean is here:
import shutil
import zipfile
temp_dir = "_temp"
old_docx = "doc.docx"
new_docx = "doc_new.docx"
old_emf = temp_dir + "/word/media/image1.emf"
new_emf = "new_image.emf"
# unpack content of the docx file into the temp folder
with zipfile.ZipFile(old_docx, "r") as z:
files = z.namelist()
for f in files: z.extract(f, temp_dir)
# replace the image
shutil.copyfile(new_emf, old_emf)
# pack all files from temp folder back into the new docx file
with zipfile.ZipFile(new_docx, "a") as z:
for f in files: z.write(temp_dir + "/" + f, f)
# remove the temp folder
shutil.rmtree(temp_dir)
Typical structure of a docx file:
doc.docx
│
├─ [Content_Types].xml
│
├─ _rels
│ └─ .rels
│
├─ docProps
│ ├─ app.xml
│ └─ docProps
│
└─ word
├─ document.xml <-- text is here
├─ fontTable.xml
├─ settings.xml
├─ webSettings.xml
├─ styles.xml
│
├─ _rels
│ └─ document.xml.rels
│
├─ theme
│ └─ theme1.xml
│
└─ media
└─ image1.emf <-- your image is here
It unpacks content of the doc file doc.docx
in temporary folder _temp
, then it replaces the file image1.emf
inside the temp dir with another file new_image.emf
from current dir. Then it packs the content of the temp folder back into doc_new.docx
file and removes the temp dir.
Note: new image will have the same size in the new_doc.docx
as old one.
So the workflow can be like this: you make template docx file, place there manually template emf picture and save the docx file. Then you take the new emf image, put the image next to the docx file and run the script. This way you get new a docx file with the new emf image.
I suppose you have many emf images, so it makes sense to add in this script a couple lines that it be able to take several images and make several docx files.
It will work fine if all the emf images have the same size. In case they have different size it will take more coding to handle with xml data.
Update
I've figured out how to get sizes of emf image. So here is full solution:
from docx import Document
import shutil
import zipfile
temp_dir = "_temp"
old_docx = "doc.docx"
new_docx = "doc_new.docx"
old_emf = temp_dir + "/word/media/image1.emf" # don't change this line
new_emf = "img5.emf"
# unpack content of the docx file into temp folder
with zipfile.ZipFile(old_docx, "r") as z:
files = z.namelist()
for f in files: z.extract(f, temp_dir)
# replace the image
shutil.copyfile(new_emf, old_emf)
# pack all files from temp folder back into the new docx file
with zipfile.ZipFile(new_docx, "a") as z:
for f in files: z.write(temp_dir + "/" + f, f)
# remove temp folder
shutil.rmtree(temp_dir)
# get sizes of the emf image
with open(new_emf, "rb") as f:
f.read(16)
w1, w2 = f.read(1).hex(), f.read(1).hex()
f.read(2)
h1, h2 = f.read(1).hex(), f.read(1).hex()
width = int(str(w2) + str(w1), 16) * 762
height = int(str(h2) + str(h1), 16) * 762
# open the new docx file and set the sizes for the image
doc = Document(new_docx)
img = doc.inline_shapes[0] # suppose the first image is the image
img.width = width
img.height = height
doc.save(new_docx)