新年到:让Serverless给你头像加点装饰

新年要到了,明天就是2020了,还没人送你头像装饰?让Serverless架构送你吧!

先分享一下地址:(http://serverless.0duzhan.com/app/new_year_add_photo_decorate/)

整体预览:

主要功能就是选择一个图片,上传自己的头像,然后点击生成就可以:

代码也很简单:

import base64, json
from PIL import Image
import uuid


def return_msg(error, msg):
    return_data = {
        "uuid": str(uuid.uuid1()),
        "error": error,
        "message": msg
    }
    print(return_data)
    return return_data


def do_circle(base_pic):
    icon_pic = Image.open(base_pic).convert("RGBA")
    icon_pic = icon_pic.resize((500, 500), Image.ANTIALIAS)
    icon_pic_x, icon_pic_y = icon_pic.size
    temp_icon_pic = Image.new('RGBA', (icon_pic_x + 600, icon_pic_y + 600), (255, 255, 255))
    temp_icon_pic.paste(icon_pic, (300, 300), icon_pic)
    ima = temp_icon_pic.resize((200, 200), Image.ANTIALIAS)
    size = ima.size

    # 因为是要圆形,所以需要正方形的图片
    r2 = min(size[0], size[1])
    if size[0] != size[1]:
        ima = ima.resize((r2, r2), Image.ANTIALIAS)

    # 最后生成圆的半径
    r3 = 60
    imb = Image.new('RGBA', (r3 * 2, r3 * 2), (255, 255, 255, 0))
    pima = ima.load()  # 像素的访问对象
    pimb = imb.load()
    r = float(r2 / 2)  # 圆心横坐标

    for i in range(r2):
        for j in range(r2):
            lx = abs(i - r)  # 到圆心距离的横坐标
            ly = abs(j - r)  # 到圆心距离的纵坐标
            l = (pow(lx, 2) + pow(ly, 2)) ** 0.5  # 三角函数 半径

            if l < r3:
                pimb[i - (r - r3), j - (r - r3)] = pima[i, j]
    return imb


def add_decorate(base_pic):
    try:
        base_pic = "./base/%s.png" % (str(base_pic))
        user_pic = Image.open("/tmp/picture.png").convert("RGBA")
        temp_basee_user_pic = Image.new('RGBA', (440, 440), (255, 255, 255))
        user_pic = user_pic.resize((400, 400), Image.ANTIALIAS)
        temp_basee_user_pic.paste(user_pic, (20, 20))
        temp_basee_user_pic.paste(do_circle(base_pic), (295, 295), do_circle(base_pic))
        temp_basee_user_pic.save("/tmp/output.png")
        return True
    except Exception as e:
        print(e)
        return False


def main_handler(event, context):
    try:
        print("将接收到的base64图像转为pic")
        imgData = base64.b64decode(json.loads(event["body"])["pic"].split("base64,")[1])
        with open('/tmp/picture.png', 'wb') as f:
            f.write(imgData)

        basePic = json.loads(event["body"])["base"]
        addResult = add_decorate(basePic)
        if addResult:
            with open("/tmp/output.png", "rb") as f:
                base64Data = str(base64.b64encode(f.read()), encoding='utf-8')
            return return_msg(False, {"picture": base64Data})
        else:
            return return_msg(True, "饰品添加失败")
    except Exception as e:
        return return_msg(True, "数据处理异常: %s" % str(e))


def test():
    with open("test.png", 'rb') as f:
        image = f.read()
        image_base64 = str(base64.b64encode(image), encoding='utf-8')
    event = {
        "requestContext": {
            "serviceId": "service-f94sy04v",
            "path": "/test/{path}",
            "httpMethod": "POST",
            "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
            "identity": {
                "secretId": "abdcdxxxxxxxsdfs"
            },
            "sourceIp": "14.17.22.34",
            "stage": "release"
        },
        "headers": {
            "Accept-Language": "en-US,en,cn",
            "Accept": "text/html,application/xml,application/json",
            "Host": "service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com",
            "User-Agent": "User Agent String"
        },
        "body": "{\"pic\":\"%s\", \"base\":\"1\"}" % image_base64,
        "pathParameters": {
            "path": "value"
        },
        "queryStringParameters": {
            "foo": "bar"
        },
        "headerParameters": {
            "Refer": "10.0.2.14"
        },
        "stageVariables": {
            "stage": "release"
        },
        "path": "/test/value",
        "queryString": {
            "foo": "bar",
            "bob": "alice"
        },
        "httpMethod": "POST"
    }
    print(main_handler(event, None))


if __name__ == "__main__":
    test()

在我的目录下还有几个图片文件:

image

另外这个代码需要依赖pillow,但是我电脑时mac的,pillow又有二进制,所以之前的项目就派上用场了:

http://serverless.0duzhan.com/app/new_year_greeting_card/

image

下载之后,直接放目录下:

image

然后还需要有一个前端页面,用mui,index页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>2020头像大变样 - 头像SHOW - 自豪的采用腾讯云Serverless架构!</title>
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <script type="text/javascript">

        thisPic = null

        function getFileUrl(sourceId) {
            var url;
            thisPic = document.getElementById(sourceId).files.item(0)
            if (navigator.userAgent.indexOf("MSIE") >= 1) { // IE
                url = document.getElementById(sourceId).value;
            } else if (navigator.userAgent.indexOf("Firefox") > 0) { // Firefox
                url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
            } else if (navigator.userAgent.indexOf("Chrome") > 0) { // Chrome
                url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
            }
            return url;
        }

        function preImg(sourceId, targetId) {
            var url = getFileUrl(sourceId);
            var imgPre = document.getElementById(targetId);
            imgPre.aaaaaa = url;
            imgPre.style = "display: block;";
        }

        function clickChose() {
            document.getElementById("imgOne").click()
        }

        function getNewPhoto() {
            document.getElementById("result").innerText = "系统处理中,请稍后..."

            var oFReader = new FileReader();
            oFReader.readAsDataURL(thisPic);
            oFReader.onload = function (oFREvent) {
                var xmlhttp;
                if (window.XMLHttpRequest) {
                    // IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
                    xmlhttp = new XMLHttpRequest();
                } else {
                    // IE6, IE5 浏览器执行代码
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                xmlhttp.onreadystatechange = function () {
                    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                        if (JSON.parse(xmlhttp.responseText)["error"]) {
                            document.getElementById("result").innerText = JSON.parse(xmlhttp.responseText)["message"];
                        } else {
                            document.getElementById("result").innerText = "长按保存图像";
                            document.getElementById("new_photo").aaaaaa = "data:image/png;base64," + JSON.parse(xmlhttp.responseText)["message"]["picture"];
                            document.getElementById("new_photo").style = "display: block;";
                        }
                    }
                }

                var url = " http://service-8d3fi753-1256773370.bj.apigw.tencentcs.com/release/new_year_add_photo_decorate"
                var obj = document.getElementsByName("base");
                var baseNum = "1"
                for (var i = 0; i < obj.length; i++) {
                    console.log(obj[i].checked)
                    if (obj[i].checked) {
                        baseNum = obj[i].value;
                    }
                }
                xmlhttp.open("POST", url, true);
                xmlhttp.setRequestHeader("Content-type", "application/json");
                var postData = {
                    pic: oFREvent.target.result,
                    base: baseNum
                }
                xmlhttp.send(JSON.stringify(postData));

            }

        }

    </script>
    <!--标准mui.css-->
    <link rel="stylesheet" href="./css/mui.min.css">
</head>
<body>
<h3 style="text-align: center; margin-top: 30px">2020头像SHOW</h3>
<div class="mui-card">
    <div class="mui-card-content">
        <div class="mui-card-content-inner">
            第一步:选择一个你喜欢的图片
        </div>
    </div>
    <div class="mui-content">
        <ul class="mui-table-view mui-grid-view mui-grid-9">
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/1.png" width="100%"><input type="radio" name="base" value="1" checked></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/2.png" width="100%"><input type="radio" name="base" value="2"></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/11.png" width="100%"><input type="radio" name="base" value="11"></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/4.png" width="100%"><input type="radio" name="base" value="4"></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/5.png" width="100%"><input type="radio" name="base" value="5"></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/6.png" width="100%"><input type="radio" name="base" value="6"></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/12.png" width="100%"><input type="radio" name="base" value="12"></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/8.png" width="100%"><input type="radio" name="base" value="8"></label></li>
            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3"><label>
                <img aaaaaa="./base/3.png" width="100%"><input type="radio" name="base" value="3"></label></li>
        </ul>
    </div>
</div>
<div class="mui-card">
    <div class="mui-card-content">
        <div class="mui-card-content-inner">
            第二步:上传一张你的头像
        </div>
        <div>
            <form>
                <input type="file" name="imgOne" id="imgOne" onchange="preImg(this.id, 'photo')" style="display: none;"
                       accept="image/*">
                <center style="margin-bottom: 10px">
                    <input type="button" value="点击此处上传头像" onclick="clickChose()"/>
                    <img id="photo" aaaaaa="" width="300px" , height="300px" style="display: none;"/>
                </center>
            </form>
        </div>
    </div>
</div>

<div class="mui-card">
    <div class="mui-card-content">
        <div class="mui-card-content-inner">
            第三步:点击生成按钮获取新年头像
        </div>
        <div>
            <center style="margin-bottom: 10px">
                <input type="button" value="生成新年头像" onclick="getNewPhoto()"/>
                <p id="result"></p>
                <img id="new_photo" aaaaaa="" width="300px" , height="300px" style="display: none;"/>
            </center>
        </div>
    </div>
</div>

<p style="text-align: center">
    本项目自豪的<br>通过Serverless Framework<br>搭建在腾讯云SCF上
</p>

</body>
</html>

最后再来一个Yaml:

new_year_add_photo_decorate:
  component: "@serverless/tencent-scf"
  inputs:
    name: myapi_new_year_add_photo_decorate
    codeUri: ./new_year_add_photo_decorate
    handler: index.main_handler
    runtime: Python3.6
    region: ap-beijing
    description: 新年为头像增加饰品
    memorySize: 128
    timeout: 5
    events:
      - apigw:
          name: serverless
          parameters:
            serviceId: service-8d3fi753
            environment: release
            endpoints:
              - path: /new_year_add_photo_decorate
                description: 新年为头像增加饰品
                method: POST
                enableCORS: true
                param:
                  - name: pic
                    position: BODY
                    required: 'FALSE'
                    type: string
                    desc: 原始图片
                  - name: base
                    position: BODY
                    required: 'FALSE'
                    type: string
                    desc: 饰品ID

myWebsite:
  component: '@serverless/tencent-website'
  inputs:
    code:
      aaaaaa: ./new_year_add_photo_decorate/web
      index: index.html
      error: index.html
    region: ap-beijing
    bucketName: new-year-add-photo-decorate

还有还有我开源的git地址:

https://github.com/anycodes/ServerlessPractice


image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容