【问题标题】:AWS S3 image saving loses metadataAWS S3 图像保存丢失元数据
【发布时间】:2017-05-08 14:27:13
【问题描述】:

我正在使用用 python 2.7x 编写的 AWS Lambda 函数,该函数下载、保存到 /tmp ,然后将图像文件上传回存储桶。

我的图像元数据从原始存储桶开始,带有 Content-Type= image/jpeg 等 http 标头。

用 PIL 保存我的图像后,所有标题都消失了,我只剩下 Content-Type = binary/octet-stream

据我所知,由于 PIL 的工作方式,image.save 正在丢失标题。如何保留元数据或至少将其应用于新保存的图像?

我看到帖子暗示此元数据在 exif 中,但我试图从原始文件中获取 exif 信息并应用于保存的文件,但没有成功。反正我不清楚它是否在 exif 数据中。

部分代码来说明我在做什么:

def resize_image(image_path):
    with Image.open(image_path) as image:
    image.save(upload_path, optimize=True)

def handler(event, context):
    global upload_path
    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key'].encode("utf8"))

        download_path = '/tmp/{}{}'.format(uuid.uuid4(), file_name)
        upload_path = '/tmp/resized-{}'.format(file_name)

        s3_client.download_file(bucket, key, download_path)

        resize_image(download_path)
        s3_client.upload_file(upload_path, '{}resized'.format(bucket), key)

感谢 Sergey,我改为使用 get_object 但响应缺少元数据:

response = s3_client.get_object(Bucket=bucket,Key=key)

response= {u'Body': , u'AcceptRanges': 'bytes', u'ContentType': 'image/jpeg', 'ResponseMetadata': {'HTTPStatusCode': 200, 'RetryAttempts': 0, ' HostId': 'au30hBMN37/ti0WCfDqlb3t9ehainumc9onVYWgu+CsrHtvG0u/zmgcOIvCCBKZgQrGoooZoW9o=', 'RequestId': '1A94D7F01914A787', 'HTTPHeaders': {'content-length': '84053', 'x-amz-3-7'x-amz-3-7 ti0WCfDqlb3t9ehainumc9onVYWgu+CsrHtvG0u/zmgcOIvCCBKZgQrGoooZoW9o=', 'accept-ranges': 'bytes', 'expires': 'Sun, 01 Jan 2034 00:00:00 GMT', 'server': 'AmazonS3', 'last-modified': '星期五,2016 年 12 月 23 日 15:21:56 GMT','x-amz-request-id':'1A94D7F01914A787','etag':'"9ba59e5457da0dc40357f2b53715619d"','缓存控制':'max-age=2592000 ,public', 'date': 'Fri, 23 Dec 2016 15:21:58 GMT', 'content-type': 'image/jpeg'}}, u'LastModified': datetime.datetime(2016, 12, 23 , 15, 21, 56, tzinfo=tzutc()), u'ContentLength': 84053, u'Expires': datetime.datetime(2034, 1, 1, 0, 0, tzinfo=tzutc()), u'ETag ': '"9ba59e5457da0dc40357f2b53715619d"', u'CacheControl': 'max-age=2592000,pu blic', u'元数据': {}}

如果我使用: 元数据 = 响应['ResponseMetadata']['HTTPHeaders']

元数据 = {'content-length': '84053', 'x-amz-id-2': 'f5UAhWzx7lulo3cMVF8hdVRbHnhdnjHWRDl+LDFkYm9pubjL0A01L5yWjgDjWRE4TjRnjqDeA0U=', 'accept-ranges': 'bytes', 'expires': ' 2034 年 1 月 1 日 00:00:00 GMT','server':'AmazonS3','last-modified':'Fri,2016 年 12 月 23 日 15:47:09 GMT','x-amz-request-id':' 4C69DF8A58EF3380', 'etag': '"9ba59e5457da0dc40357f2b53715619d"', 'cache-control': 'max-age=2592000,public', '日期': 'Fri, 23 Dec 2016 15:47:10 GMT', 'content-类型':'图像/JPEG'}

用 put_object 保存

s3_client.put_object(Bucket=bucket+'resized',Key=key, Metadata=metadata, Body=downloadfile) 

在 s3 中创建了大量额外的元数据,包括它不将 content-type 保存为 image/jpeg 而是保存为 binary/octet-stream 并且它确实创建了元数据 x-amz-meta-content-type =图片/JPEG

【问题讨论】:

    标签: python amazon-s3 python-imaging-library


    【解决方案1】:

    内容类型信息不在您上传的文件中,必须以某种方式猜测或提取。这是您必须手动或使用工具执行的操作。使用fairly small dictionary,您可以猜出大多数文件类型。

    当您上传文件或对象时,您有机会指定其内容类型。否则 S3 默认为 application/octet-stream

    以boto3 python包为例:

    s3client.upload_file(
        Filename=local_path,
        Bucket=bucket,
        Key=remote_path,
        ExtraArgs={
            "ContentType": "image/jpeg"
        }
    )
    

    【讨论】:

      【解决方案2】:

      您混淆了由 AWS S3 与对象一起存储的 S3 元数据和存储在文件本身中的 EXIF 元数据。

      download_file() 没有从 S3 获取对象属性。您应该改用get_object()https://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.get_object

      然后你可以使用put_objects()和相同的属性来上传新文件:https://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.put_object

      【讨论】:

      • 谢谢!我快到了。 get_object 返回空元数据。知道为什么会这样吗?查看问题的输出
      • boto3 中获取元数据非常简单。这里有一个单线供您尝试:print(boto3.resource('s3').Object(bucket_name='stackoverflow-41292005', key='test.txt').metadata)。您应该看到:{'keyname1': 'test1', 'keyname2': 'test2'}。 (当然,您的 IAM 用户必须拥有 s3:* 操作的权限)。
      • 这对我不起作用。元数据 = {}。正如我上面所说,元数据是空的。我以不同的方式抓住了它。即使那样,如果您尝试保存内容类型会被更改(请参阅编辑问题)
      • 你可能有一个过时的 SDK。在aws.amazon.com/sdk-for-python 获取最新的 Python SDK
      • 我在lamda中使用AWS提供的sdk。我会找出他们在用什么。我刚刚发现这篇文章回答了有关元数据stackoverflow.com/questions/34550816/… 的其余问题基本上,我不再需要检索它,因为我现在可以设置我想要的。感谢您让我走这么远
      猜你喜欢
      • 1970-01-01
      • 2018-08-11
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      相关资源
      最近更新 更多