将调整大小后的图像上传到S3

18

我正在尝试将调整大小后的图像上传到S3:

fp = urllib.urlopen('http:/example.com/test.png')
img = cStringIO.StringIO(fp.read())

im = Image.open(img)
im2 = im.resize((500, 100), Image.NEAREST)  
AK = 'xx' # Access Key ID 
SK = 'xx' # Secret Access Key

conn = S3Connection(AK,SK) 
b = conn.get_bucket('example')
k = Key(b)
k.key = 'example.png'
k.set_contents_from_filename(im2)

但我遇到了一个错误:

 in set_contents_from_filename
    fp = open(filename, 'rb')
TypeError: coercing to Unicode: need string or buffer, instance found
3个回答

58

在上传到s3之前,您需要将输出图像转换为一组字节。您可以将图像写入文件,然后上传该文件,或者您可以使用cStringIO对象以避免像我这样写入磁盘:

import boto
import cStringIO
import urllib
import Image

#Retrieve our source image from a URL
fp = urllib.urlopen('http://example.com/test.png')

#Load the URL data into an image
img = cStringIO.StringIO(fp.read())
im = Image.open(img)

#Resize the image
im2 = im.resize((500, 100), Image.NEAREST)  

#NOTE, we're saving the image into a cStringIO object to avoid writing to disk
out_im2 = cStringIO.StringIO()
#You MUST specify the file type because there is no file name to discern it from
im2.save(out_im2, 'PNG')

#Now we connect to our s3 bucket and upload from memory
#credentials stored in environment AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
conn = boto.connect_s3()

#Connect to bucket and create key
b = conn.get_bucket('example')
k = b.new_key('example.png')

#Note we're setting contents from the in-memory string provided by cStringIO
k.set_contents_from_string(out_im2.getvalue())

在这段代码中,您在哪里添加MIME类型? 我正在将文件上传到S3,但它们显示为不可读的文件。 - captDaylight
3
要设置MIME类型,可以在set_contents_from_string调用中的参数中添加headers={"Content-Type": "image/png"}。Boto默认会尝试猜测MIME类型,但这样可以让您手动设置它。 - secretmike
很棒的答案。我建议做一个改变,使用强大的requests模块而不是过时的urllib模块。 - tatlar
@tatlar 我同意,requests比urllib好得多。我只在这里使用它,因为原始帖子中使用了它。 - secretmike
谢谢@secretmike!这是唯一一个清晰解释这个问题的帖子。 - Gershon Herczeg

0
print ("loading object", input_bucket, input_key)
response = s3client.get_object(Bucket=input_bucket, Key=input_key)
print("s3 get object response", response)

body = response['Body']

image = Image.open(body)

print ("generating thumbnail", output_width, output_height)

thumbnail = resizeimage.resize_thumbnail(
    image, [output_width, output_height])
body.close()

print ("saving thumbnail", output_format)

with io.BytesIO() as output:
    thumbnail.save(output, output_format)

    print ("uploading thumbnail", output_bucket, output_key)
    output.seek(0)
    s3client.put_object(Bucket=output_bucket, Key=output_key,
                        Body=output, ContentType=output_content_type)

我已经在Lambda服务中实现了这个功能,可以进行输入和输出流。 - tingyiy

0

我的猜测是Key.set_contents_from_filename期望一个单一的字符串参数,但你传入了im2,它是由Image.resize返回的其他对象类型。我认为你需要将调整大小后的图像写入文件系统作为名称文件,然后将该文件名传递给k.set_contents_from_filename。否则,在Key类中找到另一种方法,可以从内存构造(StringIO或某个对象实例)获取图像内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接