已知不规则图形的坐标,如何从图形中抠出来这块图,类似于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>
下班了,先这样吧,溜了溜了
###凸多边形还好,如果不是凸多边形, 点在多边形内这个算法就够折腾人的,看都看不懂。如果这个算法有了,就是扣像素的问题了。
###难点是个不规则图形
如果是区域在颜色上有明显差异的,可以通过 imageData 逐一颜色筛选给抠出来。
或是区域边界有明显的差异区别应该也可以。
否则的话,你给 PS 它也不能自动抠出来。
绘图前将 CanvasRenderingContext2D.globalCompositeOperation设为 "source-in"
,这样画出来的是两个图形交叠的地方,也就达到了用一个形状去剪切另一个形状的效果。
然后根据剪切出来的图形裁剪出合适的盒子。