问答

canvas如何从图片中抠出来一块图片保存下来?

作者:admin 2021-04-22 我要评论

已知不规则图形的坐标,如何从图形中抠出来这块图,类似于ps中的抠图(将抠出来的图放到新创建的画布,然后保存)? ### script type="text/javascript" const i...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

已知不规则图形的坐标,如何从图形中抠出来这块图,类似于ps中的抠图(将抠出来的图放到新创建的画布,然后保存)?

###
<script type="text/javascript">
    const imgLink = './avatar.png';
    const points = [
        { x: 0, y: 0 },
        { x: 0.5, y: 0 },
        { x: 0.5, y: 0.5 },
    ];
    
    
    function getImg(src) {
        return new Promise(resolve => {
            const img = new Image();
            img.addEventListener('load', () => resolve(img));
            img.addEventListener('error',() => resolve(null));
            img.src = src;
        });
    }
    function getRect(points) {
        const x = points.map(it => it.x);
        const y = points.map(it => it.y);
        const minX = Math.min(...x);
        const maxX = Math.max(...x);
        const minY = Math.min(...y);
        const maxY = Math.max(...y);
        console.log(x, y);
        return {
            x: minX, y: minY,
            width: maxX - minX,
            height: maxY - minY,
        };
    }
    function createCanvas({ width, height }) {
        const cvs = document.createElement('canvas');
        const ctx = cvs.getContext('2d');
        cvs.width = width;
        cvs.height = height;
        cvs.style.cssText = `
         height: ${height}px;
         width: ${width}px;
         `;
        return {
            cvs, ctx
        }
    }
    function outputImage(imageData, { width, height }) {
        const { cvs, ctx } = createCanvas({ width, height })
        ctx.putImageData(imageData, 0, 0)
        const src = cvs.toDataURL('image/png')
        return getImg(src)
    }
    async function clip({ imgLink, points }) {
        const img = await getImg(imgLink);
        console.log(img, img.width, img.height);
        if (!img || !img.height || points.length < 3) return;
        const { cvs, ctx } = createCanvas(img)
        const { width, height } = img;
        points = points.map(it => ({ x: it.x * width, y: it.y * height }));
        ctx.beginPath();
        const [point] = points;
        console.log(point, points);
        ctx.moveTo(point.x, point.y);
        points.forEach(point => {
            ctx.lineTo(point.x, point.y);
        });
        ctx.closePath();
        ctx.clip();
        ctx.drawImage(img, 0, 0);
        const rect = getRect(points);
        console.log(rect);
        const data = ctx.getImageData(rect.x, rect.y, rect.width, rect.height)
        const image = await outputImage(data, rect)
        document.body.appendChild(cvs);
        document.body.appendChild(image);
    }
    clip({
        imgLink,
        points
    });
</script>

image.png

下班了,先这样吧,溜了溜了

###

凸多边形还好,如果不是凸多边形, 点在多边形内这个算法就够折腾人的,看都看不懂。如果这个算法有了,就是扣像素的问题了。

###

难点是个不规则图形
如果是区域在颜色上有明显差异的,可以通过 imageData 逐一颜色筛选给抠出来。
或是区域边界有明显的差异区别应该也可以。
否则的话,你给 PS 它也不能自动抠出来。

###

绘图前将 CanvasRenderingContext2D.globalCompositeOperation设为 "source-in",这样画出来的是两个图形交叠的地方,也就达到了用一个形状去剪切另一个形状的效果。
然后根据剪切出来的图形裁剪出合适的盒子。

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 求助!Mysql workbench connections出

    求助!Mysql workbench connections出

  • c++ 的dll 转golang可以调用

    c++ 的dll 转golang可以调用

  • c++的 new int{10}  和 new int(10) 有

    c++的 new int{10} 和 new int(10) 有

  • Grafana MySQL为数据源时, 折线图无法

    Grafana MySQL为数据源时, 折线图无法

腾讯云代理商
海外云服务器