You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中使用四个坐标点实现图片裁剪?

基于任意四点的JavaScript图片裁剪实现

Canvas的drawImage()确实只能处理矩形区域的裁剪/绘制,但要实现任意四边形(四个坐标点)的图片裁剪,核心思路是通过透视变换将四边形区域映射到一个矩形Canvas上,从而得到裁剪后的结果。

实现步骤

  • 计算从原图四边形点到目标矩形的透视变换矩阵
  • 在Canvas上应用该变换矩阵,将原图的四边形区域"变形"为矩形
  • 提取目标Canvas的内容作为最终裁剪后的图片

具体代码实现

1. 透视变换矩阵计算函数

这个函数负责根据四个源点(原图上的裁剪区域)和四个目标点(输出矩形的四个角),求解出Canvas需要的变换矩阵:

// 计算透视变换矩阵:从四个源点映射到四个目标点
function getPerspectiveTransform(srcPoints, dstPoints) {
  const [s1, s2, s3, s4] = srcPoints;
  const [d1, d2, d3, d4] = dstPoints;

  const matrix = [];
  // 为每个点构建方程组
  addPoint(s1, d1);
  addPoint(s2, d2);
  addPoint(s3, d3);
  addPoint(s4, d4);

  function addPoint(s, d) {
    matrix.push([s.x, s.y, 1, 0, 0, 0, -s.x * d.x, -s.y * d.x]);
    matrix.push([0, 0, 0, s.x, s.y, 1, -s.x * d.y, -s.y * d.y]);
  }

  const result = [d1.x, d1.y, d2.x, d2.y, d3.x, d3.y, d4.x, d4.y];
  // 高斯消元求解矩阵参数
  for (let i = 0; i < 8; i++) {
    let maxRow = i;
    for (let j = i + 1; j < 8; j++) {
      if (Math.abs(matrix[j][i]) > Math.abs(matrix[maxRow][i])) maxRow = j;
    }
    [matrix[i], matrix[maxRow]] = [matrix[maxRow], matrix[i]];
    [result[i], result[maxRow]] = [result[maxRow], result[i]];

    const div = matrix[i][i];
    for (let j = i; j < 8; j++) matrix[i][j] /= div;
    result[i] /= div;

    for (let j = 0; j < 8; j++) {
      if (j !== i && matrix[j][i] !== 0) {
        const factor = matrix[j][i];
        for (let k = i; k < 8; k++) matrix[j][k] -= factor * matrix[i][k];
        result[j] -= factor * result[i];
      }
    }
  }

  // 返回适配Canvas transform的矩阵参数
  return [result[0], result[1], result[3], result[4], result[2], result[5], result[6], result[7]];
}

2. 裁剪主函数

封装裁剪逻辑,接收原图、四个源点、输出尺寸,返回裁剪后的图片:

function cropImageByFourPoints(img, srcPoints, outputWidth, outputHeight) {
  // 目标矩形的四个角点(对应输出Canvas的边界)
  const dstPoints = [
    {x: 0, y: 0},
    {x: outputWidth, y: 0},
    {x: 0, y: outputHeight},
    {x: outputWidth, y: outputHeight}
  ];

  // 创建临时Canvas处理变换
  const tempCanvas = document.createElement('canvas');
  const ctx = tempCanvas.getContext('2d');
  tempCanvas.width = outputWidth;
  tempCanvas.height = outputHeight;

  // 应用透视变换并绘制原图
  const transformMatrix = getPerspectiveTransform(srcPoints, dstPoints);
  ctx.transform(...transformMatrix);
  ctx.drawImage(img, 0, 0);

  // 生成裁剪后的图片对象
  const croppedImg = new Image();
  croppedImg.src = tempCanvas.toDataURL();
  return croppedImg;
}

3. 使用示例

// 加载图片后执行裁剪
const img = new Image();
img.crossOrigin = 'anonymous'; // 跨域图片需设置
img.src = 'your-image-url.jpg';
img.onload = function() {
  // 定义原图上的四个裁剪点(顺序:左上、右上、左下、右下)
  const srcPoints = [
    {x: 50, y: 50},
    {x: 250, y: 60},
    {x: 40, y: 250},
    {x: 260, y: 240}
  ];
  // 裁剪后输出的尺寸
  const outputWidth = 200;
  const outputHeight = 200;

  const croppedImg = cropImageByFourPoints(img, srcPoints, outputWidth, outputHeight);
  // 将裁剪后的图片添加到页面
  document.body.appendChild(croppedImg);
};

注意事项

  • 源点的顺序必须和目标点对应(左上→左上、右上→右上),否则变换结果会错乱
  • 处理跨域图片时,需确保图片服务器配置了CORS,同时设置img.crossOrigin = 'anonymous'
  • 上述矩阵求解是简化实现,若需处理极端场景,可结合成熟的线性代数库优化

内容的提问来源于stack exchange,提问作者Sanjay Devadiga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 02:55:42