首页 > 编程语言 >AWS S3 Lambda Python脚本函数实现图片自动转换为webp并上传至s3

AWS S3 Lambda Python脚本函数实现图片自动转换为webp并上传至s3

时间:2024-05-03 09:23:06浏览次数:26  
标签:convert format s3 bucket AWS S3 key os resize

Amazon S3 自动转换图片格式

 Amazon S3 存储桶 新增文件自动触发 AWS Lambda。Lambda 取 S3 文件做转换并存回去 S3 同一个目录下,并增加相应的后缀名。 并且支持通过API Gateway的方式触发对图片进行修改并输出。 本 Lab 使用 Python Pillow 做图片转换,读者可以参考 Pillow 文档进行功能扩展。

import os
import logging
import boto3
import json
import io
import urllib.parse
import PIL
from PIL import Image
from botocore.exceptions import ClientError

os.environ = {
    "preserv-original_format": "False",
    "convert_format": "WebP",
    "convert_postfix": ".webp",
    "resize_feature": "FixSize",
    "resize_Percentile_w": "0.5",
    "resize_Percentile_h": "0.5",
    "resize_Fixsize_w": "640",
    "resize_FixSize_h": "640",
    "save_quality": "95",
    "jpeg_progressive":
        "True",
    "auto_orientation": "True"
}

preserv_original_format = os.environ['preserv_original_format'] == 'True'
# True: detect original image format and keep it to target
# False: convert original image to the format as below
convert_format = os.environ['convert_format']  # Target format
convert_postfix = os.environ['convert_postfix']  # Target file postfix
resize_feature = os.environ['resize_feature']  # Disable: do not resize image

# PercentileNoRatio: resize base on below resize_Percentile and DO NOT keep ratio
# FixSizeNoRatio: resize base on below FixSize and DO NOT keep ratio
resize_Percentile_w = float(os.environ['resize_Percentile_w'])
resize_Percentile_h = float(os.environ['resize_Percentile_h'])
resize_FixSize_w = int(os.environ['resize_FixSize_w'])
resize_Fixsize_h = int(os.environ['resize_FixSize_h'])

save_quality = int(os.environ['save_quality'])  # output image quality for webp, jpeg ...
jpeg_progressive = os.environ['jpeg_progressive'] == 'True'  # progressive mode for JPEG
auto_orientation = os.environ['auto_orientation'] == 'True'  # auto rotate iange based on exif info

# TODO: Watermark with text,
# TODO: Blur, Contract, Bright, Sharp, Rotate

logger = logging.getLogger()
logger.setLevel(logging.INFO)
key_id = 'yourKeyId'
secret = 'yourSecret'
awsRegion = 'ap-south-1'
client = boto3.client('S3', aws_access_key_id=key_id, aws_secret_access_key=secret, region_name=awsRegion)


# get img from s3
def load_s3(bucket, key):
    logger.info('load from s3://{bucket}/{key}')

    try:
        response = client.get_object(
            Bucket=bucket,
            Key=key
        )
        logger.info(json.dumps(response, default=str))
    except Exception as e:
        logging.error(json.dumps(e, default=str))
        os.exit(e)

    return response[' Body'].read()


# get s3 url
def url_s3(bucket, key):
    logger.info('url from s3://{bucket}/{key}')

    try:
        response = client.generate_presigned_url(
            ClientMethod='get_object',
            Params={'Bucket': bucket, 'Key': key},
            ExpiresIn=3600, HttpMethod='Get'
        )

        logger.info(json.dumps(response, default=str))
    except Exception as e:
        logging.error(json.dumps(e, default=str))
        os.exit(0)
    return response


# convert
def img_convert(body, convent_format):
    try:
        logger.info('ready to open Image By PIL ...')
        im = Image.open(io.BytesIO(body))
        logger.info('open Image By PIL success...')

        if preserv_original_format:
            convert_format = im.format

            # resize
        if resize_feature.lower() == 'percentile':
            logger.info('resizing percentile and keep ratio ...')
            w, h = im.size
            w, h = int(w * resize_Percentile_w), int(h * resize_Percentile_h)
            im.thumbnail((w, h))
        if resize_feature.lower() == 'fixsize':
            logger.info('resizing fixsize and keep ratio ...')
            w, h = im.size
            w, h = int(w * resize_Percentile_w), int(h * resize_Percentile_h)
        im.thumbnail((w, h))
        if resize_feature.lower() == 'fixsize':
            logger.info('resizing fixsize and keep ratio ...')
            w, h = resize_FixSize_w, resize_Fixsize_h
            im.thumbnail((w, h))
        if resize_feature.lower() == 'pencentilenometer':
            logger.info('resizing percentile and ignore ratio ...')
            w, h = im.size
            w, h = int(w * resize_Percentile_w), int(h * resize_Percentile_h)
            im = im.resize((w, h), resample=Image.BICUBIC)
        if resize_feature.lower() == 'fixsizeoratio':
            logger.info('resizing fixsizeoratio and igore ratio...')
            w, h = resize_FixSize_w,
            resize_Fixsize_h
            im = im.resize((w, h), resample=Image.BICUBIC)

        logger.info('target size: {im.size}')

        # convert PNG RGBA mode to RGB for JPEG
        if im.mode != 'RGB' and convert_format.lower() == 'jpeg':
            im = im.convert(mode='RGB')

        # save to target format
        in_mem_img = io.BytesIO()
        im.save(in_mem_img, format=convert_format, lossless=True, quality=save_quality, progressive=jpeg_progressive)
        in_mem_img.seek(0)

    except Exception as e:
        logger.error(json.dumps(e, default=str))
        os.exit(0)

    return in_mem_img


# put img to s3
def save_s3(bucket, key, body):
    logger.info(' save to s3://{bucket}/{key}')

    try:
        response = client.put_object(
            Bucket=bucket,
            Key=key, Body=body,
            ContentType="image/webp"
        )
        logger.info(json.dumps(response, default=str))
    except Exception as e:
        logging.error(json.dumps(e, default=str))
        os.exit(0)
    return


# change key from input/ to output/ and change postfix
def change_key(key, convert, postfix):
    key_pre = os.path.splitext(key)[0]

    if not preserv_original_format:
        key_new = key_pre + convert_postfix
    else:
        key_new = key_pre + os.path.splitext(key)[1]
    return key_new

# check image is exists
def exists_image(bucket, key):
    try:
        response = client.head_object(Bucket=bucket, Key=key)
        return True
    except ClientError as ce:
        if ce.response["Error"]["Code"] == "404":
            print("Key: {key} does not exist!")
        else:
            print("Something else went wrong")
        return False
    except Exception as e:
        return False


def lambda_handler(event, context):
    logger.info(json.dumps(event, default=str))
    bucket = 'your_bucket'
    key = 'input/20201106-a1.jpg?image_process=image/format, webp'
    format_key = "image_process=image/format,"

    # 是否包含要做转换的格式
    if format_key not in key:
        return

    source_key = key.split(format_key)[0]
    image_format = key.split(format_key)[1]

    # 转换目标格式
    filepath, tempfilename = os.path.split(source_key)
    filename, extension = os.path.splitext(tempfilename)

    target_key = filepath + '/' + filename + '.' + image_format

    first_req = url_s3(bucket, target_key)

    print(first_req)

    # 是否已存在webp
    if exists_image(bucket, target_key):
        return {
            'statusCode': 301,
            "body": 'Redirect',
            "Location": first_req
        }

    else:
        # 1. 加载原图
        img_org = load_s3(bucket, source_key)
        # 2.转换为目标格式
        body = img_convert(img_org, convert_format)
        # 3.放到新目录
        # key_new = change_key(source_key, convert_postfix)
        # 4.webp上传至s3
        save_s3(bucket, target_key, body)
        # 5.返回webp的地址
        new_img_org = url_s3(bucket, target_key)

        target_key = filepath + '/' + filename + '.' + image_format
        first_req = url_s3(bucket, target_key)
        print(first_req)

        # 是否已存在webp
        if exists_image(bucket, target_key):
            return {
                'statusCode': 301,
                'body': 'Redirect',
                "Location": first_req
            }

        else:
            # 1. 加载原图
            img_org = load_s3(bucket, source_key)
            # 2.转换为目标格式
            body = img_convert(img_org, convert_format)
            # 3.放到新目录
            # key_new = change_key(source_key, convert_postfix)
            # 4.webp上传至s3
            save_s3(bucket, target_key, body)
            # 5.返回webp的地址
            new_img_org = url_s3(bucket, target_key)
            return {
                'statusCode': 301,
                "body": 'Redirect',
                "Location": new_img_org
            }

if __name__ == '__main__':
    print("main function start.")
    result = lambda_handler('', '')
    print("handle success. %s", result)

  

参考文章

https://github.com/xffss/AmazonS3transferimage/blob/69fe698c66f9fc4fa4b96a00843b1556a395b4b1/S3transferimage.ipynb

 

本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。

首发链接:https://www.cnblogs.com/lingyejun/p/18169968 

标签:convert,format,s3,bucket,AWS,S3,key,os,resize
From: https://www.cnblogs.com/lingyejun/p/18169968

相关文章

  • AWS EC2 实例类型命名规则
    AWSEC2(ElasticComputeCloud)实例类型的命名规则反映了实例的性能特征、用途和硬件配置。这些实例类型的名称由几个组件构成,每个组件都提供了关于该实例类型特定方面的信息。理解这一命名规则可以帮助用户更好地选取适合其应用场景的实例类型。EC2实例类型命名结构格式:家族+......
  • 使用 AWS CLI 操作 S3
    使用cp命令将本地文件拷贝到S3,或者将S3中的文件拷贝到本地。awss3cplocal-file-paths3://your-bucket-name/optional-folder-path/remote-file-namelocal-file-path:您的本地机器上的文件路径,比如C:/Documents/example.txt或者/home/user/example.txt。your-bu......
  • 使用 AWS CLI 开发 Amazon EC2
    创建EC2实例:awsec2run-instances--image-idami-04b70fa74e45c3917--count1--instance-typec5a.xlarge--key-name"DefaultSSHKey"--security-groupslaunch-wizard-1--block-device-mappings"[{\"DeviceName\":\"/dev/sda1\......
  • 使用 AWS CLI 开发 Amazon S3
    AmazonS3:AmazonSimpleStorageServiceawss3ls参考:s3命令解释:s3操作S3(上传对象、下载对象):s3apiS3管理(创建桶、删除桶):s3control......
  • 配置 AWS CLI
    使用AWSCLI命令进行配置$awsconfigureAWSAccessKeyID[None]:AWSSecretAccessKey[None]:Defaultregionname[None]:Defaultoutputformat[None]:json手动编辑凭据和配置文件AWSCLI配置文件位于~/.aws目录。有关地区和输出格式的设置位于~/.aws/con......
  • 安装 AWS CLI
    macOS安装:curl"https://awscli.amazonaws.com/AWSCLIV2.pkg"-o"AWSCLIV2.pkg"sudoinstaller-pkgAWSCLIV2.pkg-target/验证安装:aws--versionLinux安装:curl"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"-o"......
  • 如何在aws cli中使用多个配置文件
    awscli使用中,可能会有在多个IAM账户中进行切换的需求,手动切换~/.aws/目录下的config和credentials是十分费力的事情。还好awscli本身就可以支持多个awscredentials配置多个profileawsconfigure时,加上--profile参数来命名不同的账户,依次输入accessid,accesskey,region......
  • (中文规格)FPGA - 现场可编程门阵列: XC7S15-1CPGA196I、LCMXO3L-4300C-5BG256C,FS32K142
    1、XC7S15-1CPGA196I  Spartan®-7现场可编程门阵列产品种类:FPGA-现场可编程门阵列系列:XC7S15逻辑元件数量:12800LE自适应逻辑模块-ALM:2000ALM嵌入式内存:360kbit输入/输出端数量:100I/O电源电压-最小:950mV电源电压-最大:1.05V最小工作温度:-40°C最大工作温度:+100°C数......
  • AWS 文件预签名URL
     1.《获取STS临时授权凭证》2.《通过STS Token分片上传文件》一、相关文档1.AWS S3预签名URL文档:https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/example_s3_Scenario_PresignedUrl_section.htmlAWS S3只针对文件的存储,若想实现阿里云oss通过URL参数对图......
  • @aws-sdk 支持的库
    abort-controllerbody-checksum-nodechunked-stream-reader-nodeclient-accessanalyzerclient-accountclient-acmclient-acm-pcaclient-alexa-for-businessclient-ampclient-amplifyclient-amplifybackendclient-amplifyuibuilderclient-api-gatewayclient-apiga......