使用 Python 解析包含来自 AWS Lambda 的图像的 Base64 编码数据
Parsing Base64 encoded data containing an image from AWS Lambda with Python
我有一个带有 POST
方法的 Lambda 函数设置,它应该能够接收图像作为 multi-form 数据、加载图像、进行一些计算和 return 一个简单的数字数组。 Lambda 函数位于 API 网关后面,集成 Lambda-Proxy 并且 multipart/form-data
设置为二进制媒体类型。
但是,我似乎一辈子都想不出如何解析 return 来自 AWS Lambda 的 multi-form 数据。
event['body']
包含 base64 编码的数据,我不能在这里 post 因为它占用太多 space。
我使用以下代码片段来解析 multi-form 数据:
from requests_toolbelt.multipart import decoder
multipart_string = base64.b64decode(body)
content_type = data['event']['headers']['Content-Type']
multipart_data = decoder.MultipartDecoder(multipart_string, content_type)
其中 content_type
是 'multipart/form-data; boundary=--------------------------881952313555430391739156'
。
运行 像这样通过 multipart_data
的组件..
for part in multipart_data.parts:
print(part.content)
print(part.headers)
给出这个。内容(太长 post)如下所示:
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\ ... x00\x7f\xff\xd9'
和 headers:
{b'Content-Disposition': b'form-data; name="image"; filename="8281460-3x2-700x467.jpg"', b'Content-Type': b'image/jpeg'}
不过,我还是不太清楚a) 哪一部分内容是实际图像? b) 如何提取图像,例如使用 Image.open
?
将其放入 PIL
补充资料:
这是我用来 POST 图像和 return 事件数据的小型 Flask 应用程序:
import json
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def hello(event, context):
response = {
"statusCode": 200,
"event": event
}
return {
"body": json.dumps(response),
}
这里是 POSTMAN 请求 Python 代码:
import requests
url = "url-to-lambda-function"
payload = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"image\"; filename=\"8281460-3x2-700x467.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--"
headers = {
'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
'User-Agent': "PostmanRuntime/7.18.0",
'Accept': "*/*",
'Cache-Control': "no-cache",
'Content-Type': "multipart/form-data; boundary=--------------------------881952313555430391739156",
'Accept-Encoding': "gzip, deflate",
'Content-Length': "30417",
'Connection': "keep-alive",
'cache-control': "no-cache"
}
response = requests.request("POST", url, data=payload, headers=headers)
print(response.text)
AWS documentation 表示(rest)API 网关的最大负载大小为 10MB。
您没有提供图像大小,但如果超过 10MB,则考虑重新设计您的架构。我建议将您的图像上传到 S3,这样您的 lambda 函数就会 return 一个 signed url。将图像上传到 S3 后,您可以在 lambda 函数中获取该对象并进行计算。
https://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjectPreSignedURLDotNetSDK.html
对于来到这里的任何人,这就是我最终解决它的方式:
body = event["body"]
content_type = event["headers"]["Content-Type"]
body_dec = base64.b64decode(body)
multipart_data = decoder.MultipartDecoder(body_dec, content_type)
binary_content = []
for part in multipart_data.parts:
binary_content.append(part.content)
imageStream = io.BytesIO(binary_content[0])
imageFile = Image.open(imageStream)
imageArray = np.array(imageFile)
这将产生一个您可以使用的数组,因为对我来说,困难在于理解 multipart/form-data 是如何再次拼接在一起的。
要添加到 tmo 的回答中:我的 multipart/form-data 帖子(到具有 API 网关代理集成的 AWS lambda)要求我访问 content-type header 而不是:
content_type = event['multiValueHeaders']['Content-Type'][0]
然后从 tmo 的 binary_content 列表访问 form-data 的部分:
...
file_content = binary_content[0]
filename = str(binary_content[1].decode())
team_id = str(binary_content[2].decode())
我有一个带有 POST
方法的 Lambda 函数设置,它应该能够接收图像作为 multi-form 数据、加载图像、进行一些计算和 return 一个简单的数字数组。 Lambda 函数位于 API 网关后面,集成 Lambda-Proxy 并且 multipart/form-data
设置为二进制媒体类型。
但是,我似乎一辈子都想不出如何解析 return 来自 AWS Lambda 的 multi-form 数据。
event['body']
包含 base64 编码的数据,我不能在这里 post 因为它占用太多 space。
我使用以下代码片段来解析 multi-form 数据:
from requests_toolbelt.multipart import decoder
multipart_string = base64.b64decode(body)
content_type = data['event']['headers']['Content-Type']
multipart_data = decoder.MultipartDecoder(multipart_string, content_type)
其中 content_type
是 'multipart/form-data; boundary=--------------------------881952313555430391739156'
。
运行 像这样通过 multipart_data
的组件..
for part in multipart_data.parts:
print(part.content)
print(part.headers)
给出这个。内容(太长 post)如下所示:
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\ ... x00\x7f\xff\xd9'
和 headers:
{b'Content-Disposition': b'form-data; name="image"; filename="8281460-3x2-700x467.jpg"', b'Content-Type': b'image/jpeg'}
不过,我还是不太清楚a) 哪一部分内容是实际图像? b) 如何提取图像,例如使用 Image.open
?
PIL
补充资料:
这是我用来 POST 图像和 return 事件数据的小型 Flask 应用程序:
import json
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def hello(event, context):
response = {
"statusCode": 200,
"event": event
}
return {
"body": json.dumps(response),
}
这里是 POSTMAN 请求 Python 代码:
import requests
url = "url-to-lambda-function"
payload = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"image\"; filename=\"8281460-3x2-700x467.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--"
headers = {
'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
'User-Agent': "PostmanRuntime/7.18.0",
'Accept': "*/*",
'Cache-Control': "no-cache",
'Content-Type': "multipart/form-data; boundary=--------------------------881952313555430391739156",
'Accept-Encoding': "gzip, deflate",
'Content-Length': "30417",
'Connection': "keep-alive",
'cache-control': "no-cache"
}
response = requests.request("POST", url, data=payload, headers=headers)
print(response.text)
AWS documentation 表示(rest)API 网关的最大负载大小为 10MB。 您没有提供图像大小,但如果超过 10MB,则考虑重新设计您的架构。我建议将您的图像上传到 S3,这样您的 lambda 函数就会 return 一个 signed url。将图像上传到 S3 后,您可以在 lambda 函数中获取该对象并进行计算。 https://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjectPreSignedURLDotNetSDK.html
对于来到这里的任何人,这就是我最终解决它的方式:
body = event["body"]
content_type = event["headers"]["Content-Type"]
body_dec = base64.b64decode(body)
multipart_data = decoder.MultipartDecoder(body_dec, content_type)
binary_content = []
for part in multipart_data.parts:
binary_content.append(part.content)
imageStream = io.BytesIO(binary_content[0])
imageFile = Image.open(imageStream)
imageArray = np.array(imageFile)
这将产生一个您可以使用的数组,因为对我来说,困难在于理解 multipart/form-data 是如何再次拼接在一起的。
要添加到 tmo 的回答中:我的 multipart/form-data 帖子(到具有 API 网关代理集成的 AWS lambda)要求我访问 content-type header 而不是:
content_type = event['multiValueHeaders']['Content-Type'][0]
然后从 tmo 的 binary_content 列表访问 form-data 的部分:
...
file_content = binary_content[0]
filename = str(binary_content[1].decode())
team_id = str(binary_content[2].decode())