Skip to content

使用 Cloudflare Worker 处理图片

Published: at 19:51

背景

之前使用 Backblaze B2 和 Cloudflare 搞了一个 10G 存储不限流量的网盘,用作日常文件分享和博客图床,配合 uPic 用起来也很顺手。但是在做博客图床的时候,有个遗憾不支持缩放/剪裁图片,工作中使用阿里云 OSS 处理图片特别顺手,有些忍不了,就想着自己搞一个服务。

Worker 的免费版本只能占用 10ms CPU,经常资源超出占用,裂图频率很高。现在适配了 Vercel Edge,可以套一个 CDN 使用,见 https://chi.miantiao.me/posts/cloudflare-worker-image/

过程

调研了一下,备选了两个方案:

  1. 使用 Cloudflare 代理 Vercel Image。此方案流量需要经过 Cloudflare -> Vercel -> Cloudflare -> Backblaze 多个环节,稳定性和速度都不理想,而且每个月限额 1000 次处理有些寒酸。

  2. 使用 wsrv.nl 公共服务。流量需要经过 Cloudflare -> wsrv.nl -> Cloudflare -> Backblaze 环节依然较多,而且域名还不在自己控制下,如果要控制域名,就得再走一次 Cloudflare Worker,复杂度就更高了。

两个方案都不理想的情况下,就一直在观望。上周在写 Email Worker 的时候发现 Cloudflare Worker 支持 WebAssembly (Wasm),就萌生了使用 Worker + WebAssembly 处理图片的想法。

本想使用之前写 Node.js 时使用的 sharp 但是作者讲 Cloudflare Worker 不支持多线程,sharp 短期内无法运行在 Cloudflare Worker。

网上搜了一下 Rust 流行的类库有 Photon,而且社区也有 Demo。尝试了一下的确可以运行在 Cloudflare Worker。但是这个示例存在两个缺陷:

  1. Photon 需要手动更新,无法最快速度跟随官方更新,
  2. 只能输出 PNG 格式,JPG 图片缩小后体积反而更大了。

结果

根据 Photon + Worker 关键字又调研了以后,参考 DenoFlarejSquash 做了一版新的方案,最终使用官方 Photon (依赖 patch-package)、Squash WebAssembly、Cloudflare Worker 做了一个图片缩放服务。本想支持输出 AVIF 和 JPEG XL 格式,但是由于免费版 Worker 有 1M 大小限制,只得作罢

支持特性:

  1. 支持 PNG、JPG、BMP、ICO、TIFF 格式图片处理
  2. 可输出 JPG、PNG、WEBP 格式图片,默认输出 WEBP 格式图片
  3. 支持管道,可以执行多个操作
  4. 支持 Cloudflare 缓存
  5. 支持图片地址白名单,防滥用
  6. 异常降级,如果处理失败返回原图 (异常场景不缓存)

演示

格式转换

webp

webp

jpg

jpg

png

png

缩放

resize

旋转

rotate

剪裁

rotate

滤镜

filter

图片水印

watermark

文字水印

draw_text

管道操作

缩放+旋转+文字水印

resize & rotate & draw_text

缩放+图片水印

resize & watermark

理论上支持 Photon 的各种操作,有兴趣的可以查看图片地址,按照 Photon 文档修改参数自己尝试。如果发现异常可以评论反馈给我。

分享

此方案已经开源在我的 GitHub,有需要的可以按照文档部署。

ccbikai/cloudflare-worker-image - GitHub


Buy Me A Coffee