python-docx-template icon indicating copy to clipboard operation
python-docx-template copied to clipboard

inline image support for bytes from file or network

Open liudonghua123 opened this issue 2 years ago • 7 comments

Is your feature request related to a problem? Please describe.

I want to render a docx which contains some images from network, I find it is difficult to do it.

I have to download and save as a temp file, use the current InlineImage and then I have to remember to remove it.

Why not directly support image contents as input?

Describe the solution you'd like

Support the image contents when using InlineImage.

Describe alternatives you've considered

n.a.

Additional context

n.a.

liudonghua123 avatar Nov 21 '22 06:11 liudonghua123

I noticed that python-docx is used, and it seems it only support file path instead of file contents.

https://github.com/elapouya/python-docx-template/blob/5d9bba118ac3c0c0f3af3242884945e526a5d4c9/docxtpl/inline_image.py#L23-L30

https://github.com/python-openxml/python-docx/blob/36cac78de080d412e9e50d56c2784e33655cad59/docx/parts/story.py#L50

Maybe we could save the image contents in a file, generate docx and do some cleanup internal.

liudonghua123 avatar Nov 21 '22 07:11 liudonghua123

I found the upstream project python-docx support stream of image.

See:

  • https://python-docx.readthedocs.io/en/latest/user/quickstart.html#adding-a-picture
  • https://github.com/python-openxml/python-docx/blob/36cac78de080d412e9e50d56c2784e33655cad59/docx/document.py#L58-L72
  • https://github.com/python-openxml/python-docx/blob/36cac78de080d412e9e50d56c2784e33655cad59/tests/image/test_image.py#L43-L66

liudonghua123 avatar Nov 21 '22 17:11 liudonghua123

I hope this feature to be added too👏

cw0516 avatar Apr 27 '23 02:04 cw0516

Hello, Its possible to pass an io.BytesIO(bytes) to the InlineImage() function. Perhaps there needs to be a new example leveraging this method: @cw0516 @liudonghua123

fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16]) #plotly Image example
img_bytes = fig.to_image(format="png",width=600, height=350) # plotly image generate bytes
main_visualization = io.BytesIO(img_bytes) # convert bytes to File obj
context = { 'main_visualization': docxtpl.InlineImage(doc, main_visualization) } # python-docx-template will believe this is a File and run seek on it.

radove avatar Feb 28 '24 23:02 radove

Hello, Its possible to pass an io.BytesIO(bytes) to the InlineImage() function. Perhaps there needs to be a new example leveraging this method: @cw0516 @liudonghua123

fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16]) #plotly Image example
img_bytes = fig.to_image(format="png",width=600, height=350) # plotly image generate bytes
main_visualization = io.BytesIO(img_bytes) # convert bytes to File obj
context = { 'main_visualization': docxtpl.InlineImage(doc, main_visualization) } # python-docx-template will believe this is a File and run seek on it.

Yeah, I found new_pic_inline in upstream project docx support IO[bytes], see https://github.com/python-openxml/python-docx/blob/57d3b9ee9cb778e76258653c6dc464d5598ca80b/src/docx/parts/story.py#L60-L65.

liudonghua123 avatar Feb 29 '24 02:02 liudonghua123

And I tested, it worked as expected!

import io
from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm

doc = DocxTemplate("test.docx")
context = { 'company_name' : "World company", 'inline_image': InlineImage(doc, io.BytesIO(open('test.png', 'rb').read()), width=Mm(10), height=Mm(10))}
doc.render(context)
doc.save("generated_doc.docx")

image

liudonghua123 avatar Feb 29 '24 02:02 liudonghua123

I can also use file like object as the second argument of InlineImage.

image

liudonghua123 avatar Feb 29 '24 07:02 liudonghua123