裁剪保存的图片黑边问题

某些机型上,截图生成的报告,存到手机中会有黑边的问题;不管是设置scale缩放比为1,画布的宽高为截取内容的width、height,都没有办法解决;

解决方式

获取图片的像素信息

我们创建一个canvas,渲染图片,然后通过 getImageData 方法拿到图片信息。 drawImage: 绘制图像,将图片绘制到画布上 getImageData: 返回一个ImageData对象,获取像素数据

javascript 复制代码
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

const image = new Image();
image.onload = draw;
image.src = url;
// image.src = dom.toDataURL(); // 导出图片
image.crossOrigin = "Anonymous";

function draw() {
    canvas.width = image.width;
    canvas.height = image.height;

    ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const { data, width, height } = imageData;
}

打印出来的图片信息为:

  • width: 图片宽度;
  • height: 图片高度;
  • colorSpace: 色彩模式,这里是srgb;
    • ps: 颜色范围的色域标准,sRGB色域应用广泛,包括Windows、Photoshop、大部分浏览器、显示屏等的默认配置都是sRGB
  • data: 色彩信息,可以被使用作为查看初始像素数据。每个像素用 4 个 1bytes 值 (按照红,绿,蓝和透明值的顺序; 这就是"RGBA"格式) 来代表。;

我们重点来看看data:

  • data是个数组;
  • 每4个元素构成一个RGBA像素块;
  • 每个元素的值范围都是0-255;
  • RGB代表红绿蓝三原色;
  • A代表透明度(0是完全透明,255是不透明);

假如存在两个,都是黑色的像素点,宽度为2, 高度为1,值为[0, 0, 0, 255, 0, 0, 0, 255]。 那么他的格式就是:

javascript 复制代码
{r: 0, g: 0, b: 0, a: 255}, {r: 0, g: 0, b: 0, a: 255}

获取像素块索引

我们已知widthheight,col为列,row为行,两层循环构造每一个网格,便利所有网格的像素,如果有色彩则设置裁剪的起点和终点。

像素操作

索引值从 0 到 (高度× 宽度 ×4)-1 例如,要读取图片中位于第 50 行,第 200 列的像素的蓝色部份,你会写以下代码: (50 * (imageData.width * 4)) + (200 * 4)) + 2 根据行、列读取某像素点的 R/G/B/A 值的公式: ((50 * (imageData.width * 4)) + (200 * 4)) + 0/1/2/3;

javascript 复制代码
for (let col = 0; col < width; col++) {
    for (let row = 0; row < height; row++) {
        // 当前像素块相对于图片的索引位置
        const pxIndex = (row * width + col) * 4;
    }
}

获取每个像素块的RGBA信息

javascript 复制代码
const pxStartIndex = pxIndex;
const pxData = {
    r: data[pxStartIndex],
    g: data[pxStartIndex + 1],
    b: data[pxStartIndex + 2],
    a: data[pxStartIndex + 3]
};

计算裁剪的起点和终点坐标

我们需要将png图片周围的透明区域去掉。所以先判断是否存在色彩:

javascript 复制代码
// 不透明
const colorExist = pxData.a !== 0;

起点和终点初始化值一定要先设置成极限值,也就是两点互换位置,

javascript 复制代码
let startX = width,
    startY = height,
    endX = 0,
    endY = 0;
  • startX坐标取当前col和startX的最小值;
  • endX坐标取当前col和endX的最大值;
  • startY坐标取当前row和startY的最小值;
  • endY坐标取当前row和endY的最大值;

如果之前初始化的时候没有取极限,使用Math.min判断的时候一直会是0;

javascript 复制代码
if (colorExist) {
    startX = Math.min(col, startX);
    endX = Math.max(col, startX);
    startY = Math.min(row, startY);
    endY = Math.max(row, endY);
}

根据计算的起点终点进行裁剪

javascript 复制代码
const cropCanvas = document.createElement("canvas");
const cropCtx = cropCanvas.getContext("2d");
cropCanvas.width = endX - startX;
cropCanvas.height = endY - startY;
cropCtx.drawImage(
    image,
    startX,
    startY,
    cropCanvas.width,
    cropCanvas.height,
    0,
    0,
    cropCanvas.width,
    cropCanvas.height
);

// 裁剪后的图像字符串
console.log(cropCanvas.toDataURL());
相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom10 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试