在实际生产中,用户上传图片是很是常见的行为,不管是作一个相册系统,仍是发布文章中带有图片,能够说图片和Web服务是很是紧密的了。可是图片所占用的空间,以及图片的大小等又都是不良莠不齐的,同时有些网站的图片在上传以后,可能被其余平台或者开发者采集而且盗用,这个时候,不少人的作法是在图片上传的时候,进行图像压缩、标准化以及添加水印,可是这一套流程每每又比较占用资源,尤为是大量大尺寸的图片产生时。那么在Serverless架构下,是否有一种方法,能够对图像的压缩与水印实现"一条龙"服务,并且不会由于用户量比较多,而影响用户总体体验呢?html
在前言部分说到,传统的图像处理方法,会比较占用资源,让服务器压力比较大,甚至会影响用户体验:python
那么咱们是否能够经过Serverless架构,实现一个异步处理流程?git
所谓的异步处理流程就是,用户直接上传图片到对象存储,直接将图片等资源进行持久化,而后经过对象存储相关的触发器,触发指定函数,函数进行图像压缩以及图像水印等相关处理,再次进行持久化。github
以相册系统为例:用户上传图片以后,系统进行压缩以及水印并生成缩略图,存储到对象存储中,当用户浏览图片列表时,展现带有水印的缩略图,能够大大提高加载速度,水印能够看做图像的一种版权保护,当用户点击图片查看原图时,能够为用户展现原始图片。这样既能保证原图的存在,就能够提升浏览列表等的速度,也具有初步的版权保护能力。express
图像压缩部分,在这里只用图像的大小做为压缩依据,除此以外还能够对图像的质量进行处理。json
单以尺寸进行压缩处理,能够看做是将一个image
对象和宽度传入,经过resize
方法进行大小的调整,实现压缩功能。浏览器
def compressImage(image, width): height = image.size[1] / (image.size[0] / width) return image.resize((int(width), int(height)))
图像水印部分采用的是文字水印,除了文字水印还能够考虑使用图片水印等。安全
此处为了将水印放在图像的右下角,而且刚好不超出图像范围,进行了每一个字符大小的获取:服务器
height = [] width = [] for eveStr in watermarkStr: thisWidth, thisHeight = drawImage.textsize(eveStr, font) height.append(thisHeight) width.append(thisWidth)
经过这样处理以后,获得的height
列表就是全部即将水印文字的高度,width
列表是全部即将水印文字的宽度。此处要将水印放在右下角只须要在图片总体高度上减去height
列表最大值,图片总体宽度基础上减去width
列表的总和便可:架构
def watermarImage(image, watermarkStr): txtImage = Image.new('RGBA', image.size, (0, 0, 0, 0)) font = ImageFont.truetype("Brimborion.TTF", 40) drawImage = ImageDraw.Draw(txtImage) height = [] width = [] for eveStr in watermarkStr: thisWidth, thisHeight = drawImage.textsize(eveStr, font) height.append(thisHeight) width.append(thisWidth) drawImage.text((txtImage.size[0] - sum(width) - 10, txtImage.size[1] - max(height) - 10), watermarkStr, font=font, fill=(255, 255, 255, 255)) return Image.alpha_composite(image, txtImage)
经过函数的事件描述,能够肯定腾讯云函数的对象存储触发器事件结果为:
{ "Records": [ { "cos": { "cosSchemaVersion": "1.0", "cosObject": { "url": "http://testpic-1253970026.cos.ap-chengdu.myqcloud.com/testfile", "meta": { "x-cos-request-id": "NWMxOWY4MGFfMjViMjU4NjRfMTUyMV8yNzhhZjM=", "Content-Type": "" }, "vid": "", "key": "/1253970026/testpic/testfile", "size": 1029 }, "cosBucket": { "region": "cd", "name": "testpic", "appid": "1253970026" }, "cosNotificationId": "unkown" }, "event": { "eventName": "cos: ObjectCreated:Post", "eventVersion": "1.0", "eventTime": 1545205770, "eventSource": "qcs::cos", "requestParameters": { "requestSourceIP": "192.168.15.101", "requestHeaders": { "Authorization": "q-sign-algorithm=sha1&q-ak=AKIDQm6iUh2NJ6jL41tVUis9KpY5Rgv49zyC&q-sign-time=1545205709;1545215769&q-key-time=1545205709;1545215769&q-header-list=host;x-cos-storage-class&q-url-param-list=&q-signature=098ac7dfe9cf21116f946c4b4c29001c2b449b14" } }, "eventQueue": "qcs:0:lambda:cd:appid/1253970026:default.printevent.$LATEST", "reservedInfo": "", "reqid": 179398952 } }] }
根据这个结构,咱们能够肯定出相关详细信息,例如存储桶/APPID以及图片的Key等。将上面的代码按照函数计算的格式进行改写:
# -*- coding: utf8 -*- import os from PIL import Image, ImageFont, ImageDraw from qcloud_cos_v5 import CosConfig from qcloud_cos_v5 import CosS3Client secret_id = os.environ.get('secret_id') secret_key = os.environ.get('secret_key') region = os.environ.get('region') cosClient = CosS3Client(CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key)) def compressImage(image, width): height = image.size[1] / (image.size[0] / width) return image.resize((int(width), int(height))) def watermarImage(image, watermarkStr): txtImage = Image.new('RGBA', image.size, (0, 0, 0, 0)) font = ImageFont.truetype("Brimborion.TTF", 40) drawImage = ImageDraw.Draw(txtImage) height = [] width = [] for eveStr in watermarkStr: thisWidth, thisHeight = drawImage.textsize(eveStr, font) height.append(thisHeight) width.append(thisWidth) drawImage.text((txtImage.size[0] - sum(width) - 10, txtImage.size[1] - max(height) - 10), watermarkStr, font=font, fill=(255, 255, 255, 255)) return Image.alpha_composite(image, txtImage) def main_handler(event, context): for record in event['Records']: bucket = record['cos']['cosBucket']['name'] + '-' + record['cos']['cosBucket']['appid'] key = "/".join(record['cos']['cosObject']['key'].split("/")[3:]) download_path = '/tmp/{}'.format(key.split('/')[-1]) download_path = '/tmp/{}'.format(key.split('/')[-1]) upload_path = '/tmp/new_mp4-{}'.format(key.split('/')[-1]) # 下载图片 response = cosClient.get_object(Bucket=bucket, Key=key) response['Body'].get_stream_to_file(download_path) # 图片处理 image = Image.open(download_path) image = compressImage(image, width=500) image = watermarImage(image, "Hello Serverless") image.save(upload_path) # 上传图片 cosClient.put_object_from_local_file( Bucket=bucket, LocalFilePath=upload_path, Key="/compress-watermark/" + key.split('/')[-1] )
此时,新建serverless.yaml
文件:
MyPicture: component: "@serverless/tencent-scf" inputs: name: MyPicture codeUri: ./ handler: index.main_handler runtime: Python3.6 region: ap-guangzhou description: My Picture Compress And Watermark memorySize: 128 timeout: 20 environment: variables: secret_id: 用户密钥id secret_key: 用户密钥key region: ap-guangzhou events: - cos: name: picture-1256773370.cos.ap-guangzhou.myqcloud.com parameters: bucket: picture-1256773370.cos.ap-guangzhou.myqcloud.com filter: prefix: source/ events: cos:ObjectCreated:* enable: true
能够看到,这个函数有一个cos
触发器,触发器是针对存储桶picture-1256773370
下面source/
目录下的资源建立进行触发。
将项目经过经过serverless
进行部署:
部署完成以后,咱们在存储桶picture-1256773370
中,新建source/
目录与compress-watermark/
目录。
前者用来上传文件,后者用来生成新的文件。随机搜索一张图片:
能够看到这张图片4.5M,仍是蛮大的,将这个图片上传到source/
目录下:
稍等片刻,能够在compress-watermark/
目录下发现有一个新的文件生成:
将文件下载下来,查看详情:
能够看到,图片尺寸,明显变小,而且从4.5M压缩到了340K,与此同时图像右下角出现了预设的水印标志。
至此,咱们完成了经过COS触发器实现的图片压缩与水印功能。
本实验成功实现了用户上传图像,经过Serverless架构对其进行压缩与增长水印的功能。在这个功能中,咱们能够看到,经过Serverless架构能够解决不少传统生产中遇到的问题,而且能够更节约资源,节约成本对常见的问题进行新策略的定制,以本文为例,当咱们的服务面临高并发的时候,传统状况下,极可能会因为图像压缩,水印的操做致使咱们的服务挂掉,可是经过这样一个策略,就算是高并发出现,也仅仅是将图片传入对象存储,至于转换的逻辑、压缩的逻辑以及水印的逻辑等都是有Serverless架构帮咱们实现。对咱们而言能够说是既安全稳定,又节约成本和资源。
做为抛砖引玉的文章,本文仅仅以压缩与水印为例,除此以外,还能够有图像标准化、不一样尺寸图像制做、视频压缩、不一样分辨率的视频制做甚至是能够经过深度学习对图像进行打标签等。这些的一切均可以异步完成,交给Serverless架构完成。
咱们诚邀您来体验最便捷的 Serverless 开发和部署方式。在试用期内,相关联的产品及服务均提供免费资源和专业的技术支持,帮助您的业务快速、便捷地实现 Serverless!
3 秒你能作什么?喝一口水,看一封邮件,仍是 —— 部署一个完整的 Serverless 应用?
复制连接至 PC 浏览器访问:https://serverless.cloud.tencent.com/deploy/express
3 秒极速部署,当即体验史上最快的 Serverless HTTP 实战开发!
传送门:
- GitHub: github.com/serverless
- 官网:serverless.com
欢迎访问:Serverless 中文网,您能够在 最佳实践 里体验更多关于 Serverless 应用的开发!