3

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!

yedpodtrzitko
  • 9,035
  • 2
  • 40
  • 42
Leon Chen
  • 53
  • 1
  • 8
  • So what is the question? `.pptx` is basically a renamed `.zip` file. Try to rename it to `.zip` and inspect manually what's inside. – yedpodtrzitko Feb 09 '17 at 14:20

1 Answers1

2

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.

scanny
  • 26,423
  • 5
  • 54
  • 80
  • 2
    Hi Scanny, Thank for your answer. Follow your advice, I replaced first three lines with "prs = Presentation('foo.pptx')", and before "prs.save(source_stream)" I insert the code "source_stream = BytesIO()". Finally the generated powerpoint work perfect! – Leon Chen Feb 10 '17 at 06:19
  • My god you're a life-saver. Was breaking my head the last 48 hours and just re-instantiating the BytesIO to write every time worked like magic! Thanks scanny and Leon! TIL BytesIO can act weird. – TheWiz Nov 15 '22 at 17:39