{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2020-05-04-image-compression","result":{"data":{"currentBlog":{"id":"60cdbe64-7a7b-5d2a-a46c-135944060867","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020511/1589207417692-ZalNtxgQAC_small.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-05-04T00:00:00.000Z","title":"Serverless 实现图片压缩与水印","description":"图片和 Web 服务非常紧密，在 Serverless 架构下，是否有一种方法，可以对图像的压缩与水印实现「一条龙」服务，而且不会因为用户量比较多，而影响用户整体体验呢？","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","图片压缩"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":179,"sentences":36,"paragraphs":36},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-05-04-image-compression.md","fields":{"slug":"/best-practice/2020-05-04-image-compression/","keywords":["go","python","serverless","函数计算","云函数","image","width","水印","cos","height","图片","size","txtImage"]},"html":"<p>上传图片是很常见的用户需求，无论是做一个相册系统，还是发布文章中带有图片，都有上传图片的场景，可以说图片和 Web 服务是紧密相连的了。但是图片大小等属性又参差不齐的，而且图片在上传之后，还可能会被其他平台采集并且盗用。这个时候，就需要进行图像压缩、标准化以及添加水印等操作，这一套流程下来很占用计算资源。那么在 Serverless 架构下，是否可以对图像的压缩与水印实现「一条龙」服务，而且不会因为用户量比较多，而影响整体体验呢？</p>\n<p>一起试试！</p>\n<h2 id=\"serverless-与图像处理\"><a href=\"#serverless-%E4%B8%8E%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86\" aria-label=\"serverless 与图像处理 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Serverless 与图像处理</h2>\n<p>传统的图像处理，会比较占用资源，让服务器压力山大，影响用户体验：</p>\n<p><img src=\"https://img.serverlesscloud.cn/tmp/2-5-1.png\"></p>\n<p>我们尝试通过 Serverless 架构，实现一个异步处理流程 —— 用户直接上传图片到对象存储，将图片等资源进行持久化，然后通过对象存储相关的触发器，触发指定函数，函数进行图像压缩以及水印等相关处理，再次进行持久化。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/2-5-2.png\"></p>\n<p>以相册系统为例：用户上传图片之后，系统进行压缩以及水印并生成缩略图，存储到对象存储中。当用户浏览图片列表时，展示带有水印的缩略图，可以大大提升加载速度。水印还可以看作图像的一种版权保护，当用户点击图片查看原图时，可以为用户展示原始图片。这样既能保证原图的存在，也可以浏览列表加载速度，还具备初步的版权保护能力。</p>\n<h3 id=\"一、图像压缩\"><a href=\"#%E4%B8%80%E3%80%81%E5%9B%BE%E5%83%8F%E5%8E%8B%E7%BC%A9\" aria-label=\"一、图像压缩 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>一、图像压缩</h3>\n<p>这里只用图像的大小作为压缩依据，除此之外还可以对图像的质量进行处理。</p>\n<p>单以尺寸进行压缩处理，可以看作是将一个 <code class=\"language-text\">image</code> 对象的宽度传入，通过 <code class=\"language-text\">resize</code> 方法进行大小调整，实现压缩功能。</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"57907343569112450000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`def compressImage(image, width):\n    height = image.size[1] / (image.size[0] / width)\n    return image.resize((int(width), int(height)))`, `57907343569112450000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">def</span> <span class=\"token function\">compressImage</span><span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> width<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    height <span class=\"token operator\">=</span> image<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">/</span> width<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> image<span class=\"token punctuation\">.</span>resize<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">int</span><span class=\"token punctuation\">(</span>width<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">int</span><span class=\"token punctuation\">(</span>height<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"二、图像水印\"><a href=\"#%E4%BA%8C%E3%80%81%E5%9B%BE%E5%83%8F%E6%B0%B4%E5%8D%B0\" aria-label=\"二、图像水印 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>二、图像水印</h3>\n<p>这部分采用文字水印，当然也可以使用图片水印等。</p>\n<p>此处为了将水印放在图像的右下角，并且不超出图像范围，进行了每个字符大小的获取：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"5642985741159956000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`height = []\nwidth = []\nfor eveStr in watermarkStr:\n    thisWidth, thisHeight = drawImage.textsize(eveStr, font)\n    height.append(thisHeight)\n    width.append(thisWidth)`, `5642985741159956000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\">height <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\nwidth <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n<span class=\"token keyword\">for</span> eveStr <span class=\"token keyword\">in</span> watermarkStr<span class=\"token punctuation\">:</span>\n    thisWidth<span class=\"token punctuation\">,</span> thisHeight <span class=\"token operator\">=</span> drawImage<span class=\"token punctuation\">.</span>textsize<span class=\"token punctuation\">(</span>eveStr<span class=\"token punctuation\">,</span> font<span class=\"token punctuation\">)</span>\n    height<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span>thisHeight<span class=\"token punctuation\">)</span>\n    width<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span>thisWidth<span class=\"token punctuation\">)</span></code></pre></div>\n<p>通过这样处理之后，得到的 <code class=\"language-text\">height</code> 列表就是所有即将水印文字的高度，<code class=\"language-text\">width</code> 列表是所有即将水印文字的宽度。此处要将水印放在右下角只需要在图片整体高度上减去 <code class=\"language-text\">height</code> 列表最大值，图片整体宽度基础上减去 <code class=\"language-text\">width</code> 列表的总和即可：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"22955694728028650000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`def watermarImage(image, watermarkStr):\n    txtImage = Image.new('RGBA', image.size, (0, 0, 0, 0))\n    font = ImageFont.truetype(&quot;Brimborion.TTF&quot;, 40)\n    drawImage = ImageDraw.Draw(txtImage)\n    height = []\n    width = []\n    for eveStr in watermarkStr:\n        thisWidth, thisHeight = drawImage.textsize(eveStr, font)\n        height.append(thisHeight)\n        width.append(thisWidth)\n    drawImage.text((txtImage.size[0] - sum(width) - 10, txtImage.size[1] - max(height) - 10),\n                   watermarkStr, font=font,\n                   fill=(255, 255, 255, 255))\n    return Image.alpha_composite(image, txtImage)`, `22955694728028650000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">def</span> <span class=\"token function\">watermarImage</span><span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> watermarkStr<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    txtImage <span class=\"token operator\">=</span> Image<span class=\"token punctuation\">.</span>new<span class=\"token punctuation\">(</span><span class=\"token string\">'RGBA'</span><span class=\"token punctuation\">,</span> image<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    font <span class=\"token operator\">=</span> ImageFont<span class=\"token punctuation\">.</span>truetype<span class=\"token punctuation\">(</span><span class=\"token string\">\"Brimborion.TTF\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">40</span><span class=\"token punctuation\">)</span>\n    drawImage <span class=\"token operator\">=</span> ImageDraw<span class=\"token punctuation\">.</span>Draw<span class=\"token punctuation\">(</span>txtImage<span class=\"token punctuation\">)</span>\n    height <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    width <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token keyword\">for</span> eveStr <span class=\"token keyword\">in</span> watermarkStr<span class=\"token punctuation\">:</span>\n        thisWidth<span class=\"token punctuation\">,</span> thisHeight <span class=\"token operator\">=</span> drawImage<span class=\"token punctuation\">.</span>textsize<span class=\"token punctuation\">(</span>eveStr<span class=\"token punctuation\">,</span> font<span class=\"token punctuation\">)</span>\n        height<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span>thisHeight<span class=\"token punctuation\">)</span>\n        width<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span>thisWidth<span class=\"token punctuation\">)</span>\n    drawImage<span class=\"token punctuation\">.</span>text<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>txtImage<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">-</span> <span class=\"token builtin\">sum</span><span class=\"token punctuation\">(</span>width<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> <span class=\"token number\">10</span><span class=\"token punctuation\">,</span> txtImage<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">-</span> <span class=\"token builtin\">max</span><span class=\"token punctuation\">(</span>height<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                   watermarkStr<span class=\"token punctuation\">,</span> font<span class=\"token operator\">=</span>font<span class=\"token punctuation\">,</span>\n                   fill<span class=\"token operator\">=</span><span class=\"token punctuation\">(</span><span class=\"token number\">255</span><span class=\"token punctuation\">,</span> <span class=\"token number\">255</span><span class=\"token punctuation\">,</span> <span class=\"token number\">255</span><span class=\"token punctuation\">,</span> <span class=\"token number\">255</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> Image<span class=\"token punctuation\">.</span>alpha_composite<span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> txtImage<span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"三、部署到云函数-scf-中\"><a href=\"#%E4%B8%89%E3%80%81%E9%83%A8%E7%BD%B2%E5%88%B0%E4%BA%91%E5%87%BD%E6%95%B0-scf-%E4%B8%AD\" aria-label=\"三、部署到云函数 scf 中 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>三、部署到云函数 SCF 中</h3>\n<p>通过函数的事件描述，可以确定腾讯云函数的对象存储触发器事件结果为：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"82313023231193240000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`{\n  &quot;Records&quot;: [\n  {\n      &quot;cos&quot;: {\n          &quot;cosSchemaVersion&quot;: &quot;1.0&quot;,\n          &quot;cosObject&quot;: {\n              &quot;url&quot;: &quot;http://testpic-1253970026.cos.ap-chengdu.myqcloud.com/testfile&quot;,\n              &quot;meta&quot;: {\n                  &quot;x-cos-request-id&quot;: &quot;NWMxOWY4MGFfMjViMjU4NjRfMTUyMV8yNzhhZjM=&quot;,\n                  &quot;Content-Type&quot;: &quot;&quot;\n              },\n              &quot;vid&quot;: &quot;&quot;,\n              &quot;key&quot;: &quot;/1253970026/testpic/testfile&quot;,\n              &quot;size&quot;: 1029\n          },\n          &quot;cosBucket&quot;: {\n              &quot;region&quot;: &quot;cd&quot;,\n              &quot;name&quot;: &quot;testpic&quot;,\n              &quot;appid&quot;: &quot;1253970026&quot;\n          },\n          &quot;cosNotificationId&quot;: &quot;unkown&quot;\n      },\n      &quot;event&quot;: {\n          &quot;eventName&quot;: &quot;cos: ObjectCreated:Post&quot;,\n          &quot;eventVersion&quot;: &quot;1.0&quot;,\n          &quot;eventTime&quot;: 1545205770,\n          &quot;eventSource&quot;: &quot;qcs::cos&quot;,\n          &quot;requestParameters&quot;: {\n              &quot;requestSourceIP&quot;: &quot;192.168.15.101&quot;,\n              &quot;requestHeaders&quot;: {\n                  &quot;Authorization&quot;: &quot;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&quot;\n              }\n          },\n          &quot;eventQueue&quot;: &quot;qcs:0:lambda:cd:appid/1253970026:default.printevent.\\$LATEST&quot;,\n          &quot;reservedInfo&quot;: &quot;&quot;,\n          &quot;reqid&quot;: 179398952\n      }\n  }]\n}`, `82313023231193240000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"Records\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n  <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"cos\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token property\">\"cosSchemaVersion\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1.0\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"cosObject\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n              <span class=\"token property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"http://testpic-1253970026.cos.ap-chengdu.myqcloud.com/testfile\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token property\">\"meta\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n                  <span class=\"token property\">\"x-cos-request-id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"NWMxOWY4MGFfMjViMjU4NjRfMTUyMV8yNzhhZjM=\"</span><span class=\"token punctuation\">,</span>\n                  <span class=\"token property\">\"Content-Type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span>\n              <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n              <span class=\"token property\">\"vid\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token property\">\"key\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/1253970026/testpic/testfile\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token property\">\"size\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1029</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"cosBucket\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n              <span class=\"token property\">\"region\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"cd\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"testpic\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token property\">\"appid\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1253970026\"</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"cosNotificationId\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"unkown\"</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"event\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token property\">\"eventName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"cos: ObjectCreated:Post\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"eventVersion\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1.0\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"eventTime\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1545205770</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"eventSource\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"qcs::cos\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"requestParameters\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n              <span class=\"token property\">\"requestSourceIP\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"192.168.15.101\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token property\">\"requestHeaders\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n                  <span class=\"token property\">\"Authorization\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"q-sign-algorithm=sha1&amp;q-ak=AKIDQm6iUh2NJ6jL41tVUis9KpY5Rgv49zyC&amp;q-sign-time=1545205709;1545215769&amp;q-key-time=1545205709;1545215769&amp;q-header-list=host;x-cos-storage-class&amp;q-url-param-list=&amp;q-signature=098ac7dfe9cf21116f946c4b4c29001c2b449b14\"</span>\n              <span class=\"token punctuation\">}</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"eventQueue\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"qcs:0:lambda:cd:appid/1253970026:default.printevent.$LATEST\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"reservedInfo\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"reqid\"</span><span class=\"token operator\">:</span> <span class=\"token number\">179398952</span>\n      <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>根据这个结构，我们可以确定出相关详细信息，例如存储桶、APPID，以及图片 Key 等信息。将上面的代码按照函数计算的格式进行改写：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"71404220054221360000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`# -*- coding: utf8 -*-\nimport os\nfrom PIL import Image, ImageFont, ImageDraw\nfrom qcloud_cos_v5 import CosConfig\nfrom qcloud_cos_v5 import CosS3Client\n\nsecret_id = os.environ.get('secret_id')\nsecret_key = os.environ.get('secret_key')\nregion = os.environ.get('region')\ncosClient = CosS3Client(CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key))\n\n\ndef compressImage(image, width):\n    height = image.size[1] / (image.size[0] / width)\n    return image.resize((int(width), int(height)))\n\n\ndef watermarImage(image, watermarkStr):\n    txtImage = Image.new('RGBA', image.size, (0, 0, 0, 0))\n    font = ImageFont.truetype(&quot;Brimborion.TTF&quot;, 40)\n    drawImage = ImageDraw.Draw(txtImage)\n    height = []\n    width = []\n    for eveStr in watermarkStr:\n        thisWidth, thisHeight = drawImage.textsize(eveStr, font)\n        height.append(thisHeight)\n        width.append(thisWidth)\n    drawImage.text((txtImage.size[0] - sum(width) - 10, txtImage.size[1] - max(height) - 10),\n                   watermarkStr, font=font,\n                   fill=(255, 255, 255, 255))\n    return Image.alpha_composite(image, txtImage)\n\n\ndef main_handler(event, context):\n    for record in event['Records']:\n        bucket = record['cos']['cosBucket']['name'] + '-' + record['cos']['cosBucket']['appid']\n        key = &quot;/&quot;.join(record['cos']['cosObject']['key'].split(&quot;/&quot;)[3:])\n        download_path = '/tmp/{}'.format(key.split('/')[-1])\n        download_path = '/tmp/{}'.format(key.split('/')[-1])\n        upload_path = '/tmp/new_mp4-{}'.format(key.split('/')[-1])\n\n        # 下载图片\n        response = cosClient.get_object(Bucket=bucket, Key=key)\n        response['Body'].get_stream_to_file(download_path)\n\n        # 图片处理\n        image = Image.open(download_path)\n        image = compressImage(image, width=500)\n        image = watermarImage(image, &quot;Hello Serverless&quot;)\n        image.save(upload_path)\n\n        # 上传图片\n        cosClient.put_object_from_local_file(\n            Bucket=bucket,\n            LocalFilePath=upload_path,\n            Key=&quot;/compress-watermark/&quot; + key.split('/')[-1]\n        )`, `71404220054221360000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token comment\"># -*- coding: utf8 -*-</span>\n<span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">from</span> PIL <span class=\"token keyword\">import</span> Image<span class=\"token punctuation\">,</span> ImageFont<span class=\"token punctuation\">,</span> ImageDraw\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosConfig\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosS3Client\n\nsecret_id <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_id'</span><span class=\"token punctuation\">)</span>\nsecret_key <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_key'</span><span class=\"token punctuation\">)</span>\nregion <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'region'</span><span class=\"token punctuation\">)</span>\ncosClient <span class=\"token operator\">=</span> CosS3Client<span class=\"token punctuation\">(</span>CosConfig<span class=\"token punctuation\">(</span>Region<span class=\"token operator\">=</span>region<span class=\"token punctuation\">,</span> SecretId<span class=\"token operator\">=</span>secret_id<span class=\"token punctuation\">,</span> SecretKey<span class=\"token operator\">=</span>secret_key<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">compressImage</span><span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> width<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    height <span class=\"token operator\">=</span> image<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">/</span> width<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> image<span class=\"token punctuation\">.</span>resize<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">int</span><span class=\"token punctuation\">(</span>width<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">int</span><span class=\"token punctuation\">(</span>height<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">watermarImage</span><span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> watermarkStr<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    txtImage <span class=\"token operator\">=</span> Image<span class=\"token punctuation\">.</span>new<span class=\"token punctuation\">(</span><span class=\"token string\">'RGBA'</span><span class=\"token punctuation\">,</span> image<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    font <span class=\"token operator\">=</span> ImageFont<span class=\"token punctuation\">.</span>truetype<span class=\"token punctuation\">(</span><span class=\"token string\">\"Brimborion.TTF\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">40</span><span class=\"token punctuation\">)</span>\n    drawImage <span class=\"token operator\">=</span> ImageDraw<span class=\"token punctuation\">.</span>Draw<span class=\"token punctuation\">(</span>txtImage<span class=\"token punctuation\">)</span>\n    height <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    width <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token keyword\">for</span> eveStr <span class=\"token keyword\">in</span> watermarkStr<span class=\"token punctuation\">:</span>\n        thisWidth<span class=\"token punctuation\">,</span> thisHeight <span class=\"token operator\">=</span> drawImage<span class=\"token punctuation\">.</span>textsize<span class=\"token punctuation\">(</span>eveStr<span class=\"token punctuation\">,</span> font<span class=\"token punctuation\">)</span>\n        height<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span>thisHeight<span class=\"token punctuation\">)</span>\n        width<span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span>thisWidth<span class=\"token punctuation\">)</span>\n    drawImage<span class=\"token punctuation\">.</span>text<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>txtImage<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">-</span> <span class=\"token builtin\">sum</span><span class=\"token punctuation\">(</span>width<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> <span class=\"token number\">10</span><span class=\"token punctuation\">,</span> txtImage<span class=\"token punctuation\">.</span>size<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">-</span> <span class=\"token builtin\">max</span><span class=\"token punctuation\">(</span>height<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                   watermarkStr<span class=\"token punctuation\">,</span> font<span class=\"token operator\">=</span>font<span class=\"token punctuation\">,</span>\n                   fill<span class=\"token operator\">=</span><span class=\"token punctuation\">(</span><span class=\"token number\">255</span><span class=\"token punctuation\">,</span> <span class=\"token number\">255</span><span class=\"token punctuation\">,</span> <span class=\"token number\">255</span><span class=\"token punctuation\">,</span> <span class=\"token number\">255</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> Image<span class=\"token punctuation\">.</span>alpha_composite<span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> txtImage<span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">main_handler</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">for</span> record <span class=\"token keyword\">in</span> event<span class=\"token punctuation\">[</span><span class=\"token string\">'Records'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n        bucket <span class=\"token operator\">=</span> record<span class=\"token punctuation\">[</span><span class=\"token string\">'cos'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'cosBucket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'name'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">+</span> <span class=\"token string\">'-'</span> <span class=\"token operator\">+</span> record<span class=\"token punctuation\">[</span><span class=\"token string\">'cos'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'cosBucket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'appid'</span><span class=\"token punctuation\">]</span>\n        key <span class=\"token operator\">=</span> <span class=\"token string\">\"/\"</span><span class=\"token punctuation\">.</span>join<span class=\"token punctuation\">(</span>record<span class=\"token punctuation\">[</span><span class=\"token string\">'cos'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'cosObject'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'key'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token string\">\"/\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token number\">3</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n        download_path <span class=\"token operator\">=</span> <span class=\"token string\">'/tmp/{}'</span><span class=\"token punctuation\">.</span><span class=\"token builtin\">format</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token string\">'/'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token operator\">-</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n        download_path <span class=\"token operator\">=</span> <span class=\"token string\">'/tmp/{}'</span><span class=\"token punctuation\">.</span><span class=\"token builtin\">format</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token string\">'/'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token operator\">-</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n        upload_path <span class=\"token operator\">=</span> <span class=\"token string\">'/tmp/new_mp4-{}'</span><span class=\"token punctuation\">.</span><span class=\"token builtin\">format</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token string\">'/'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token operator\">-</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n        <span class=\"token comment\"># 下载图片</span>\n        response <span class=\"token operator\">=</span> cosClient<span class=\"token punctuation\">.</span>get_object<span class=\"token punctuation\">(</span>Bucket<span class=\"token operator\">=</span>bucket<span class=\"token punctuation\">,</span> Key<span class=\"token operator\">=</span>key<span class=\"token punctuation\">)</span>\n        response<span class=\"token punctuation\">[</span><span class=\"token string\">'Body'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>get_stream_to_file<span class=\"token punctuation\">(</span>download_path<span class=\"token punctuation\">)</span>\n\n        <span class=\"token comment\"># 图片处理</span>\n        image <span class=\"token operator\">=</span> Image<span class=\"token punctuation\">.</span><span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span>download_path<span class=\"token punctuation\">)</span>\n        image <span class=\"token operator\">=</span> compressImage<span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> width<span class=\"token operator\">=</span><span class=\"token number\">500</span><span class=\"token punctuation\">)</span>\n        image <span class=\"token operator\">=</span> watermarImage<span class=\"token punctuation\">(</span>image<span class=\"token punctuation\">,</span> <span class=\"token string\">\"Hello Serverless\"</span><span class=\"token punctuation\">)</span>\n        image<span class=\"token punctuation\">.</span>save<span class=\"token punctuation\">(</span>upload_path<span class=\"token punctuation\">)</span>\n\n        <span class=\"token comment\"># 上传图片</span>\n        cosClient<span class=\"token punctuation\">.</span>put_object_from_local_file<span class=\"token punctuation\">(</span>\n            Bucket<span class=\"token operator\">=</span>bucket<span class=\"token punctuation\">,</span>\n            LocalFilePath<span class=\"token operator\">=</span>upload_path<span class=\"token punctuation\">,</span>\n            Key<span class=\"token operator\">=</span><span class=\"token string\">\"/compress-watermark/\"</span> <span class=\"token operator\">+</span> key<span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token string\">'/'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token operator\">-</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span>\n        <span class=\"token punctuation\">)</span></code></pre></div>\n<p>新建 <code class=\"language-text\">serverless.yaml</code> 文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"39987510540101165000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`MyPicture:\n  component: &quot;@serverless/tencent-scf&quot;\n  inputs:\n    name: MyPicture\n    codeUri: ./\n    handler: index.main_handler\n    runtime: Python3.6\n    region: ap-guangzhou\n    description: My Picture Compress And Watermark\n    memorySize: 128\n    timeout: 20\n    environment:\n      variables:\n        secret_id: 用户密钥id\n        secret_key: 用户密钥key\n        region: ap-guangzhou\n    events:\n      - cos:\n          name: picture-1256773370.cos.ap-guangzhou.myqcloud.com\n          parameters:\n            bucket: picture-1256773370.cos.ap-guangzhou.myqcloud.com\n            filter:\n              prefix: source/\n            events: cos:ObjectCreated:*\n            enable: true`, `39987510540101165000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">MyPicture</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-scf\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> MyPicture\n    <span class=\"token key atrule\">codeUri</span><span class=\"token punctuation\">:</span> ./\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> index.main_handler\n    <span class=\"token key atrule\">runtime</span><span class=\"token punctuation\">:</span> Python3.6\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n    <span class=\"token key atrule\">description</span><span class=\"token punctuation\">:</span> My Picture Compress And Watermark\n    <span class=\"token key atrule\">memorySize</span><span class=\"token punctuation\">:</span> <span class=\"token number\">128</span>\n    <span class=\"token key atrule\">timeout</span><span class=\"token punctuation\">:</span> <span class=\"token number\">20</span>\n    <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">secret_id</span><span class=\"token punctuation\">:</span> 用户密钥id\n        <span class=\"token key atrule\">secret_key</span><span class=\"token punctuation\">:</span> 用户密钥key\n        <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n    <span class=\"token key atrule\">events</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">cos</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> picture<span class=\"token punctuation\">-</span>1256773370.cos.ap<span class=\"token punctuation\">-</span>guangzhou.myqcloud.com\n          <span class=\"token key atrule\">parameters</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">bucket</span><span class=\"token punctuation\">:</span> picture<span class=\"token punctuation\">-</span>1256773370.cos.ap<span class=\"token punctuation\">-</span>guangzhou.myqcloud.com\n            <span class=\"token key atrule\">filter</span><span class=\"token punctuation\">:</span>\n              <span class=\"token key atrule\">prefix</span><span class=\"token punctuation\">:</span> source/\n            <span class=\"token key atrule\">events</span><span class=\"token punctuation\">:</span> cos<span class=\"token punctuation\">:</span>ObjectCreated<span class=\"token punctuation\">:</span>*\n            <span class=\"token key atrule\">enable</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span></code></pre></div>\n<p>可以看到，这个函数有一个 <code class=\"language-text\">cos</code> 触发器，触发器是针对存储桶 <code class=\"language-text\">picture-1256773370</code> 下面 <code class=\"language-text\">source/</code> 目录下的资源创建进行触发。</p>\n<h3 id=\"四、简单测试\"><a href=\"#%E5%9B%9B%E3%80%81%E7%AE%80%E5%8D%95%E6%B5%8B%E8%AF%95\" aria-label=\"四、简单测试 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>四、简单测试</h3>\n<p>通过 <code class=\"language-text\">serverless</code> 进行部署：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/2-5-3.png\"></p>\n<p>部署完成之后，我们在存储桶 <code class=\"language-text\">picture-1256773370</code> 中，新建 <code class=\"language-text\">source/</code> 目录与 <code class=\"language-text\">compress-watermark/</code> 目录。</p>\n<p>前者用来上传文件，后者用来生成新的文件。随机搜索一张图片：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/2-5-4.png\"></p>\n<p>可以看到这张图片 4.5M，还是蛮大的，将这个图片上传到 <code class=\"language-text\">source/</code> 目录下：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/2-5-5.png\"></p>\n<p>稍等片刻，可以在 <code class=\"language-text\">compress-watermark/</code> 目录下发现有一个新的文件生成：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/2-5-6.png\"></p>\n<p>将文件下载下来，查看详情：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/2-5-7.png\"></p>\n<p>可以看到，图片尺寸明显变小，从 4.5M 压缩到了 340K。同时，图像右下角出现了预设的水印标志。</p>\n<p>我们终于完成了通过 COS 触发器实现的图片压缩与水印功能。</p>\n<h2 id=\"总结\"><a href=\"#%E6%80%BB%E7%BB%93\" aria-label=\"总结 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>总结</h2>\n<p>本示例实现了用户上传图像，通过 Serverless 架构对其进行压缩与增加水印的功能。</p>\n<p>在这个功能中，我们可以看到，通过 Serverless 架构可以解决很多传统生产中遇到的问题，并且可以以更少的资源对常见问题进行新策略的定制。以本文为例，当函数服务面临高并发时，传统情况下，很可能会由于图像压缩、水印的操作导致服务宕机，但是通过这样的策略，在高并发的场景，也仅仅是将图片传入对象存储。至于转换逻辑、压缩逻辑以及水印逻辑等都是由 Serverless 架构进行实现，可以说是既安全稳定，又节约成本和资源。</p>\n<p>除此之外，视频制作、深度学习下的标签处理等，也都可以异步完成，交给 Serverless 架构实现。</p>\n<hr>\n<div id='scf-deploy-iframe-or-md'></div>\n<hr>\n<blockquote>\n<p><strong>传送门：</strong></p>\n<ul>\n<li>GitHub: <a href=\"https://github.com/serverless/serverless/blob/master/README_CN.md\">github.com/serverless</a></li>\n<li>官网：<a href=\"https://serverless.com/\">serverless.com</a></li>\n</ul>\n</blockquote>\n<p>欢迎访问：<a href=\"https://serverlesscloud.cn/\">Serverless 中文网</a>，您可以在 <a href=\"https://serverlesscloud.cn/best-practice\">最佳实践</a> 里体验更多关于 Serverless 应用的开发！</p>","tableOfContents":"<ul>\n<li>\n<p><a href=\"/best-practice/2020-05-04-image-compression/#serverless-%E4%B8%8E%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86\">Serverless 与图像处理</a></p>\n<ul>\n<li><a href=\"/best-practice/2020-05-04-image-compression/#%E4%B8%80%E3%80%81%E5%9B%BE%E5%83%8F%E5%8E%8B%E7%BC%A9\">一、图像压缩</a></li>\n<li><a href=\"/best-practice/2020-05-04-image-compression/#%E4%BA%8C%E3%80%81%E5%9B%BE%E5%83%8F%E6%B0%B4%E5%8D%B0\">二、图像水印</a></li>\n<li><a href=\"/best-practice/2020-05-04-image-compression/#%E4%B8%89%E3%80%81%E9%83%A8%E7%BD%B2%E5%88%B0%E4%BA%91%E5%87%BD%E6%95%B0-scf-%E4%B8%AD\">三、部署到云函数 SCF 中</a></li>\n<li><a href=\"/best-practice/2020-05-04-image-compression/#%E5%9B%9B%E3%80%81%E7%AE%80%E5%8D%95%E6%B5%8B%E8%AF%95\">四、简单测试</a></li>\n</ul>\n</li>\n<li><a href=\"/best-practice/2020-05-04-image-compression/#%E6%80%BB%E7%BB%93\">总结</a></li>\n</ul>"},"previousBlog":{"id":"d1450693-7418-5532-8bd4-4fe42f275bdf","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020512/1589274622959-J2kmfdLCPpX436WYvs0D.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-05-05T00:00:00.000Z","title":"Serverless 与人工智能实现微信公众号的智能服务","description":"一般情况下，想给公众号增加更多的功能，需要我们在服务器上搭建后台服务。那么在 Serverless 架构下，能否更简单地实现相同的后台服务呢？","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","人工智能"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":519,"sentences":119,"paragraphs":119},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-05-05-ai-wechat.md","fields":{"slug":"/best-practice/2020-05-05-ai-wechat/","keywords":["python","serverless","函数计算","函数计算服务","event","json","media","time"]}},"nextBlog":{"id":"71466a42-3d49-5877-a603-88867ab2d9e2","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020511/1589207417703-ZalNtxgQAC_small.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-05-03T00:00:00.000Z","title":"Serverless 实现视频压缩与格式转换","description":"在 Serverless 架构的应用案例中，有这样一个非常实在的应用：视频处理，我们应该如何实现它呢？","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","视频处理"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":404,"sentences":48,"paragraphs":48},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-05-03-video-compression.md","fields":{"slug":"/best-practice/2020-05-03-video-compression/","keywords":["go","python","serverless","函数计算","云函数","ffmpeg","视频","copy","output","Serverless"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"60cdbe64-7a7b-5d2a-a46c-135944060867","previousBlogId":"d1450693-7418-5532-8bd4-4fe42f275bdf","nextBlogId":"71466a42-3d49-5877-a603-88867ab2d9e2"}}}