这篇文章主要介绍“如何用Serverless给网站图片加水印”,在日常操作中,相信很多人在如何用Serverless给网站图片加水印问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何用Serverless给网站图片加水印”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
传统的加水印的方法,通常是在流程内进行。即:
这种做法虽然可行,但是无疑会增加单次请求,服务端的压力,如果是高并发的情况下,或者多人上传多张大图的时候,那么可能就会造成自身服务器资源效果过大。
如果在加水印过程中失败,就有可能导致图像存储失败,致使数据丢失,并不理智。所以后来有人做了如下改进:
这样做法的好处就是 —— 我们可以快速将图片存储,存储之后通过一个单独处理的线程,对任务列表进行处理,这样一方面是可以保证我们马上把用户上传的图片存储,并且可以显示,同时也可以在后台进行水印处理,待处理之后,再将图片覆盖或者单独存储,用户如果需要读取图片时,可以自动变为已经水印后的图片。
这种做法相对于前者来说可能稍微复杂一些,但是实际上却是在数据上更加稳定,服务端压力更小,更加可控的一种操作。但是,这整个流程还是要在自己的服务器上做完,现在已经有很多人将图片等资源存储到腾讯云的 对象存储(COS)中,那么可不可以通过某些 COS 触发器与云函数 SCF 结合,实现一个不在自己服务器加水印的流程呢?
本文将以腾讯云函数 SCF 的函数模板(Python 语言)为例,进行一个简单的分享。
在无服务器云函数中,选择模板函数:
通过搜索「图像」关键词,选中图像压缩,并且确定建立。保存之后,点击函数代码,进行代码编写。
有些人可能对 COS 触发器还不是很了解,此时可以点击配置,来熟悉 COS 触发器样式:
可以看到如下:
{ "Records":[ { "event": { "eventVersion":"1.0", "eventSource":"qcs::cos", "eventName":"cos: ObjectCreated: *", "eventTime":1501054710, "eventQueue":"qcs:0:cos:gz:1251111111:cos", "requestParameters":{ "requestSourceIP": "111.111.111.111", "requestHeaders":{ "Authorization": "上传的鉴权信息" } } }, "cos":{ "cosSchemaVersion":"1.0", "cosNotificationId":"设置的或返回的 ID", "cosBucket":{ "name":"bucketname", "appid":"appId", "region":"gz" }, "cosObject":{ "key":"/appid/bucketname/DSC_0002.JPG", "size":2598526, "meta":{ "Content-Type": "text/plain", "x-cos-meta-test": "自定义的 meta", "x-image-test": "自定义的 meta" }, "url": "访问文件的源站url" } } } ] }
这里面可以看到整个一个数据结构,需要注意 Records 是一个数组格式,其次就是:
"cosBucket":{"name":"bucketname","appid":"appId","region":"gz"}
这里面是由该 bucket 触发
"cosObject":{"key":"/appid/bucketname/DSC_0002.JPG","size":2598526,"meta":{"Content-Type":"text/plain","x-cos-meta-test":"自定义的 meta","x-image-test":"自定义的 meta"},"url":"访问文件的源站 url"}
这里面的 key 是在上述 bucket 中新建的文件名字。
所以,我们可以按照我们的实际情况,将上面的内容简单修改一下,成为我们格式,以便测试(在生产中,这个是自动生成的触发格式,并不需要我们修改,我们修改只是为了测试.
{ "Records":[ { "event": { "eventVersion":"1.0", "eventSource":"qcs::cos", "eventName":"cos: ObjectCreated: *", "eventTime":1501054710, "eventQueue":"qcs:0:cos:gz:1251111111:cos", "requestParameters":{ "requestSourceIP": "111.111.111.111", "requestHeaders":{ "Authorization": "上传的鉴权信息" } } }, "cos":{ "cosSchemaVersion":"1.0", "cosNotificationId":"设置的或返回的 ID", "cosBucket":{ "name":"mytestcos", "appid":"appId", "region":"gz" }, "cosObject":{ "key":"test.png", "size":2598526, "meta":{ "Content-Type": "text/plain", "x-cos-meta-test": "自定义的 meta", "x-image-test": "自定义的 meta" }, "url": "访问文件的源站url" } } } ] }
这里主要修改了我的 cosBucket-name: mytestcos,以及 key: test.png
之所以使用现有的模板,是因为该模板的有 PIL 和 qcloud_cos_v5 等相关 package,而这两个 package 正是我们即将需要的,这样就可以省去我们打包函数的流程,只需要进行简单修改即可实现。
添加水印:
def add_word(pic_path, save_path): # 打开图片 im = Image.open(pic_path).convert('RGBA') # 新建一个空白图片,尺寸与打开图片一样 txt = Image.new('RGBA', im.size, (0, 0, 0, 0)) # 设置字体 fnt = ImageFont.truetype("/tmp/font.ttf", 40) # 操作新建的空白图片>>将新建的图片添入画板 d = ImageDraw.Draw(txt) # 在新建的图片上添加字体 d.text((txt.size[0] - 220, txt.size[1] - 80), "By Dfounder", font=fnt, fill=(255, 255, 255, 255)) # 合并两个图片 out = Image.alpha_composite(im, txt) # 保存图像 out.save(save_path)
在添加水印的时候,我们设置的是文字水印,所以需要设置字体和字号:
fnt = ImageFont.truetype("/tmp/font.ttf",40)
此时,我们需要在执行之前,先将字体文件传入到 /tmp/ 文件夹下:
response = client.get_object(Bucket="mytestcos-12567****", Key="font.ttf", ) response['Body'].get_stream_to_file('/tmp/font.ttf')
以我的 cos 为例:
然后,接下来就是对触发的 event 进行解析,包括获得新建的图像名称,从 COS 拉取,放到本地,然后进行水印等,再上传回新的 COS 中:
for record in event['Records']: try: bucket = record['cos']['cosBucket']['name'] + '-' + str(appid) key = record['cos']['cosObject']['key'] key = key.replace('/' + str(appid) + '/' + record['cos']['cosBucket']['name'] + '/', '', 1) download_path = '/tmp/{}'.format(key) upload_path = '/tmp/new_pic-{}'.format(key) # 下载图片 try: response = client.get_object(Bucket=bucket, Key=key, ) response['Body'].get_stream_to_file(download_path) except CosServiceError as e: print(e.get_error_code()) print(e.get_error_msg()) print(e.get_resource_location()) # 图像增加水印 add_word(download_path, upload_path) # 图像上传 response = client.put_object_from_local_file( Bucket=to_bucket, LocalFilePath=upload_path.decode('utf-8'), Key=("upload-" + key).decode('utf-8') ) except Exception as e: print(e)
此处说明一下,为什么要有两个存储桶?
因为我们要把一个存储桶作为触发 SCF 函数的「工具」,如果我们将水印结果再次写回这个存储桶,在不进行额外判断和处理的前提下,那么这个水印后的图片会再次水印,反反复复造成恶劣的循环,所以此处建立两个存储桶,可以降低难度,也可以保护性能,减少 BUG 诞生。
完整代码如下:
# -*- coding: utf-8 -*- from PIL import Image, ImageFont, ImageDraw from qcloud_cos_v5 import CosConfig from qcloud_cos_v5 import CosS3Client from qcloud_cos_v5 import CosServiceError from qcloud_cos_v5 import CosClientError appid = ** # 请替换为您的 APPID secret_id = ***' # 请替换为您的 SecretId secret_key = **' # 请替换为您的 SecretKey region = u'ap-chengdu' # 请替换为您bucket 所在的地域 token = '' to_bucket = 'tobucket-12567***' # 请替换为您用于存放压缩后图片的bucket config = CosConfig(Secret_id=secret_id, Secret_key=secret_key, Region=region, Token=token) client = CosS3Client(config) response = client.get_object(Bucket="mytestcos-12567***", Key="font.ttf", ) response['Body'].get_stream_to_file('/tmp/font.ttf') def add_word(pic_path, save_path): # 打开图片 im = Image.open(pic_path).convert('RGBA') # 新建一个空白图片,尺寸与打开图片一样 txt = Image.new('RGBA', im.size, (0, 0, 0, 0)) # 设置字体 fnt = ImageFont.truetype("/tmp/font.ttf", 40) # 操作新建的空白图片>>将新建的图片添入画板 d = ImageDraw.Draw(txt) # 在新建的图片上添加字体 d.text((txt.size[0] - 220, txt.size[1] - 80), "By Dfounder", font=fnt, fill=(255, 255, 255, 255)) # 合并两个图片 out = Image.alpha_composite(im, txt) # 保存图像 out.save(save_path) def main_handler(event, context): for record in event['Records']: try: bucket = record['cos']['cosBucket']['name'] + '-' + str(appid) key = record['cos']['cosObject']['key'] key = key.replace('/' + str(appid) + '/' + record['cos']['cosBucket']['name'] + '/', '', 1) download_path = '/tmp/{}'.format(key) upload_path = '/tmp/new_pic-{}'.format(key) # 下载图片 try: response = client.get_object(Bucket=bucket, Key=key, ) response['Body'].get_stream_to_file(download_path) except CosServiceError as e: print(e.get_error_code()) print(e.get_error_msg()) print(e.get_resource_location()) # 图像增加水印 add_word(download_path, upload_path) # 图像上传 response = client.put_object_from_local_file( Bucket=to_bucket, LocalFilePath=upload_path.decode('utf-8'), Key=("upload-" + key).decode('utf-8') ) except Exception as e: print(e)
这里面需要注意这几个参数:appid、secret_id、secret_key、to_bucket
这几个参数的来源如下:
而 secretid,secretkey 则需要在这里获取:
之前我已经上传了一个测试图片在这个 bucket 中,名字是:test.png
图片是这样子:
然后我们进行一下测试:
可以看到,已经测试成功,接下来我们可以去我们的目标 bucket 中看看:
可以看到成功生成了一个图片:
可以看到图片的右下角,有我们代码中添加的水印:
到此,关于“如何用Serverless给网站图片加水印”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。