logo NodeSeekbeta

在 cloudflare workers 中压缩图片

/**
 * Fetch and log a request
 * @param {Request} request
 */
export default {
  async fetch(request) {
    // Parse request URL to get access to query string
    let url = new URL(request.url)

    // Cloudflare-specific options are in the cf object.
    let options = { cf: { image: {} } }

    // Copy parameters from query string to request options.
    // You can implement various different parameters here.
    if (url.searchParams.has("fit")) options.cf.image.fit = url.searchParams.get("fit")
    if (url.searchParams.has("width")) options.cf.image.width = url.searchParams.get("width")
    if (url.searchParams.has("height")) options.cf.image.height = url.searchParams.get("height")
    if (url.searchParams.has("quality")) options.cf.image.quality = url.searchParams.get("quality")

    // Your Worker is responsible for automatic format negotiation. Check the Accept header.
    const accept = request.headers.get("Accept");
    if (/image\/avif/.test(accept)) {
      options.cf.image.format = 'avif';
    } else if (/image\/webp/.test(accept)) {
      options.cf.image.format = 'webp';
    }

    // Get URL of the original (full size) image to resize.
    // You could adjust the URL here, e.g., prefix it with a fixed address of your server,
    // so that user-visible URLs are shorter and cleaner.
    const imageURL = url.searchParams.get("image")
    if (!imageURL) return new Response('Missing "image" value', { status: 400 })

    try {
      // TODO: Customize validation logic
      const { hostname, pathname } = new URL(imageURL)

      // Optionally, only allow URLs with JPEG, PNG, GIF, or WebP file extensions
      // @see https://developers.cloudflare.com/images/url-format#supported-formats-and-limitations
      if (!/\.(jpe?g|png|gif|webp)$/i.test(pathname)) {
        return new Response('Disallowed file extension', { status: 400 })
      }

      // Demo: Only accept "example.com" images
      if (hostname !== 'example.com') {
        return new Response('Must use "example.com" source images', { status: 403 })
      }
    } catch (err) {
      return new Response('Invalid "image" value', { status: 400 })
    }

    // Build a request that passes through request headers
    const imageRequest = new Request(imageURL, {
      headers: request.headers
    })

    // Returning fetch() with resizing options will pass through response with the resized image.
    return fetch(imageRequest, options)
  }
}

效果:
原图:
image
压缩后:
image

体积对比:
image

搬运自:https://developers.cloudflare.com/images/transform-images/transform-via-workers/

12
  • @应无所住 #1 我是觉得,存储得是原图,展示可选原图和压缩后的 xhj008

  • 用worker转码和压缩,是很好的办法
    可以避免很多转码漏洞,还有一些svg的针对攻击
    据我所知,v2ex站自建了图像转码微服务

  • @Flare #5 是的,只能说 cf 活菩萨

  • @vlvie #6

    Cf Image以前是收费的,现在免费了一些额度

  • 我安装官方示例配置,将format设置为avif
    let options = { cf: { image: {quality: 80, format: "avif"} } }
    但是生成的还是jpg格式的图片

    我查看文档, 发现要开启 cf 控制台 images 中的转换才能变格式 (并且转换需要绑定一个域名)
    于是我开启转换并设置路由到我的域名上

    这时候的确是可以转换了, 但是生成的是webp
    在代码中已经设置格式为avif ,生成的还是webp

    请问楼主是如何部署的, 能够生成avif?

  • @vlvie #9

    我测试了一个下午发现了原因

    Cloudflare还是太鸡贼了

    虽然免费压缩

    但是他也挺小气的

    总的来说, 压缩分为3种(优先于你预设的格式)

    jpg webp avif

    • 当分辨率太高时, 只会使用jpg压缩(速度最快,效果最差,但是最省资源)
    • 分辨率中等时, 使用webp压缩(速度中等, 效果中等)
    • 分辨率比较小时,使用avif压缩(速度最慢, 效果最好, 最费资源)

    经过我一个下午的测试
    avif 和 webp 之间的界限是316w像素
    只有图片小于等于316w像素时, 才会激活avif压缩

12

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有73243位seeker

🎉欢迎新用户🎉