Skip to main content

JavaScript + Canvas 裁剪图片

JavaScript 操作 DOM Canvas 实现裁剪图片。常用 3 种保持图片长宽比的裁剪方法:

  • cover(保证图片的短边显示出来)
  • contain(保证图片的长边显示出来)
  • fill(拉伸图片)

Cover

把短边找出来,基于短边缩放裁剪窗口。

function clipCoverImage(w: number, h: number, clipw: number, cliph: number) {
  const scale = w < h ? clipw / w : cliph / h
  const [centerX, centerY] = [w / 2, h / 2]
  const [srcClipW, srcClipH] = [clipw / scale, cliph / scale]
  return {
    sx: centerX - srcClipW / 2,
    sy: centerY - srcClipW / 2,
    sw: srcClipW,
    sh: srcClipH,
  }
}

Contain

和上方反过来,基于长边缩放裁剪窗口。实现方法和上方一样,只是缩放基于长边。

- w < h
+ w > h
+ function clipCotainImage(w: number, h: number, clipw: number, cliph: number) {
+  const scale = w > h ? clipw / w : cliph / h
  const [centerX, centerY] = [w / 2, h / 2]
  const [srcClipW, srcClipH] = [clipw / scale, cliph / scale]
  return {
    sx: centerX - srcClipW / 2,
    sy: centerY - srcClipW / 2,
    sw: srcClipW,
    sh: srcClipH,
  }
}

E.g. 制作缩略图

function makeThumbnail(imgsrc: string, contentType: string, quality: number) {
  return new Promise((resolve, reject) => {
    const img = createElement('img')
    img.crossOrigin = 'anonymous'
    img.onload = () => {
      const canvas = createElement('canvas')
      const ctx = canvas.getContext('2d')
      const [clipw, cliph] = [200, 100]
      const { sx, sy, sw, sh } = clipCoverImage(img.width, img.height, clipw, cliph)
      canvas.hidden = true
      canvas.style.display = 'none'
      canvas.width = clipw
      canvas.height = cliph
      ctx.drawImage(img, sx, sy, sw, sh, 0, 0, clipw, cliph)
      document.body.appendChild(canvas)
      const dataUrl = canvas.toDataURL(contentType, quality)
      document.body.removeChild(canvas)
      resolve(dataUrl)
    }
    img.onerror = reject
    img.src = imgsrc
  })
}