saving an image to bytes and uploading to boto3 returning content-MD5 mismatch

user3610691 picture user3610691 · Mar 29, 2016 · Viewed 12.4k times · Source

I'm trying to pull an image from s3, quantize it/manipulate it, and then store it back into s3 without saving anything to disk (entirely in-memory). I was able to do it once, but upon returning to the code and trying it again it did not work. The code is as follows:

import boto3
import io
from PIL import Image

client = boto3.client('s3',aws_access_key_id='',
        aws_secret_access_key='')
cur_image = client.get_object(Bucket='mybucket',Key='2016-03-19 19.15.40.jpg')['Body'].read()

loaded_image = Image.open(io.BytesIO(cur_image))
quantized_image = loaded_image.quantize(colors=50)
saved_quantized_image = io.BytesIO()
quantized_image.save(saved_quantized_image,'PNG')
client.put_object(ACL='public-read',Body=saved_quantized_image,Key='testimage.png',Bucket='mybucket')

The error I received is:

botocore.exceptions.ClientError: An error occurred (BadDigest) when calling the PutObject operation: The Content-MD5 you specified did not match what we received.

It works fine if I just pull an image, and then put it right back without manipulating it. I'm not quite sure what's going on here.

Answer

Nathaniel Ford picture Nathaniel Ford · Jan 12, 2017

I had this same problem, and the solution was to seek to the beginning of the saved in-memory file:

out_img = BytesIO()
image.save(out_img, img_type)
out_img.seek(0)  # Without this line it fails
self.bucket.put_object(Bucket=self.bucket_name,
                       Key=key,
                       Body=out_img)