You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Pillow在Python Lambda中生成GIF时图像方向异常求助

解决AWS Lambda中Pillow合成GIF时的图像方向异常问题

问题根源是图片的EXIF方向元数据:部分图片在拍摄或编辑后会携带旋转信息,Pillow默认不会自动应用这些旋转设置,导致合成GIF时两张图片方向不一致。

解决方案

添加一个辅助函数处理图片的EXIF方向,确保每张图片都以正确的原始方向显示后再合成GIF。

修改后的完整代码如下:

import json
import boto3
from PIL import Image
from io import BytesIO
import uuid

s3_client = boto3.client("s3")
dynamodb = boto3.client("dynamodb")

def fix_image_orientation(image):
    # 读取图片的EXIF方向信息
    exif = image.getexif()
    orientation = exif.get(0x0112)
    # 根据EXIF方向值纠正图片旋转
    if orientation == 3:
        image = image.rotate(180, expand=True)
    elif orientation == 6:
        image = image.rotate(270, expand=True)
    elif orientation == 8:
        image = image.rotate(90, expand=True)
    return image

def makeGIF(orig_string, after_string):
    # 打开图片并应用方向纠正
    orig_img = Image.open(BytesIO(orig_string))
    after_img = Image.open(BytesIO(after_string))
    
    orig_img = fix_image_orientation(orig_img)
    after_img = fix_image_orientation(after_img)
    
    frames = [orig_img, after_img]
    frame_one = frames[0]
    frame_one.save('/tmp/new_gif.gif', format="GIF", append_images=[frames[1]],
                save_all=True, duration=600, loop=0, optimize=False)

def lambda_handler(event, context):
    try:
        s3 = event["Records"][0]['s3']
        print("S3 object reveived::",s3)
        
        if s3['object']['key'][-1] == '/': return
        splitted = s3['object']['key'].split("/")
        if len(splitted) != 3:
            print("ERROR:: Folder hierarchy is not valid!")
            return {}
        
        afterFilename = splitted[-1].replace("+", " ")
        print('Filename::', afterFilename)
        if afterFilename[0:6] not in ['after_', 'AFTER_', 'After_']:
            print('Error::', 'Filename does not starts with after_, After_ or AFTER_')
            return {}
        
        EXT = ['.jpg', '.jpeg', '.png']
        
        origFilename = afterFilename[6:]
        origKey = f"original/{splitted[1]}/{origFilename}"
        fileWithoutExt = origFilename.split(".")[0]

        BUCKET = s3['bucket']['name']
    
        file_content_orig = None
        try:
            file_content_orig = s3_client.get_object(Bucket=BUCKET, Key=origKey)["Body"].read()
        except:
            for ext in EXT:
                try:
                    print("LOOKING::", f"original/{splitted[1]}/{fileWithoutExt}{ext}")
                    file_content_orig = s3_client.get_object(Bucket=BUCKET, Key=f"original/{splitted[1]}/{fileWithoutExt}{ext}")["Body"].read()
                    print("FOUND::", f"original/{splitted[1]}/{fileWithoutExt}{ext}")
                    break
                except: pass
        if file_content_orig is None:
            print('Error::', 'No original image found looked (jpg, jpeg, png)')
            return {}
        print("LOOKING::", f"after/{splitted[1]}/{afterFilename}")
        file_content_after = s3_client.get_object(Bucket=BUCKET, Key=f"after/{splitted[1]}/{afterFilename}")["Body"].read()
        
        makeGIF(file_content_orig, file_content_after)
        
        gifKey = f"gif/{splitted[1]}/gif_{fileWithoutExt}.gif"
    
        with open('/tmp/new_gif.gif', 'rb') as f:
            s3_client.upload_fileobj(f, BUCKET, gifKey)
        
        itemId = uuid.uuid4().hex
        
        bucketLink = f"https://{BUCKET}.s3.us-east-2.amazonaws.com"
        print("bucketLink", bucketLink)
        item = {
            "id": {'S': itemId},
            "folder_name": {'S': splitted[1]},
            "image_name": {'S': origFilename},
            "original_link": {'S': f"{bucketLink}/{origKey}"},
            "download_link": {'S': f"{bucketLink}/{s3['object']['key']}"},
            "gif_link": {'S': f"{bucketLink}/{gifKey}"}
        }
        
        dynamodb.put_item(TableName='fototone-db-table', Item = item)
            
        return {
            'statusCode': 200,
            'body': json.dumps({"message": "Successfully proceessed", "filename": origFilename })
        }
    except Exception as ex:
        print("ERROR:: Some error occured", ex)
        return {}

关键说明

  • fix_image_orientation函数读取图片的EXIF方向标签(0x0112),根据不同的方向值对图片进行旋转纠正:
    • 3 = 图片需要旋转180度
    • 6 = 图片需要逆时针旋转270度(等同于顺时针90度)
    • 8 = 图片需要逆时针旋转90度
  • 使用expand=True参数确保旋转后的图片完整显示,不会被裁剪。

内容的提问来源于stack exchange,提问作者RareWatch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:01:03