Search code examples
pythondjangopowerpointpython-pptxbytesio

Django the powerpoint generated using python-pptx library has error message


I use python-pptx v0.6.2 to generate powerpoint. I read a exist powerpoint into BytesIO, then do some modification and save it. I can download the file successfully, and I'm sure the content can be write into the file. But when I open the powerpoint, it will popup a error message "Powerpoint found a problem with content in foo.pptx. Powerpoint can attempt to repair the presatation.", then I have to click "repair" button, the powerpoint will display as "repaired" mode. My Python version is 3.5.2 and Django version is 1.10. Below is my code:

with open('foo.pptx', 'rb') as f:
    source_stream = BytesIO(f.read())
prs = Presentation(source_stream)

first_slide = prs.slides[0]
title = first_slide.shapes.title
subtitle = first_slide.placeholders[1]
title.text = 'Title'
subtitle.text = "Subtitle"

response = HttpResponse(content_type='application/vnd.ms-powerpoint')
response['Content-Disposition'] = 'attachment; filename="sample.pptx"'
prs.save(source_stream)
ppt = source_stream.getvalue()
source_stream.close()
response.write(ppt)
return response

Any help is appreciate, thanks in advance!


Solution

  • It looks like you've got problems with the IO.

    The first three lines can be replaced by:

    prs = Presentation('foo.pptx')
    

    Placing the file into a memory-based stream just uses unnecessary resources.

    On the writing, you're writing to that original (unnecessary) stream, which is dicey. I suspect that because you didn't seek(0) that you're appending onto the end of it. Also it's conceptually more complicated to deal with reuse.

    If you use a fresh BytesIO buffer for the save I think you'll get the proper behavior. It's also better practice because it decouples the open, modify, and save, which you can then factor into separate methods later.

    If you eliminate the first BytesIO you should just need the one for the save in order to get the .pptx "file" into the HTTP response.