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

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

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

整体预览:

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

代码也很简单:

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()

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

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

Python Package Tool For Tencent Serverless Cloud Function​

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

然后还需要有一个前端页面,用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.src = 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").src = "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 src="./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 src="./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 src="./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 src="./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 src="./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 src="./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 src="./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 src="./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 src="./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" src="" 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" src="" 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:        src: ./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/MyAPICenter​