如何在我使用路径绘制的梯形html画布上拟合图像 [英] how to to fit an image on a trapezium html canvas which I drew using path
问题描述
[我想在笔记本电脑屏幕上添加另一张图片.var ctx = myCanvas.getContext('2d');
[I want to add another image over the laptop screen`var ctx = myCanvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(13,28);
ctx.lineTo(237,7);
ctx.lineTo(285,105);
ctx.lineTo(73,151);
ctx.closePath();
ctx.lineWidth = 0.5;
ctx.strokeStyle = 'blue';
ctx.stroke();
//ctx.clip();
//ctx.rotate(-20*Math.PI/180);
var img = new Image;
img.onload = function()
{
var width = img.width;
var height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height,
0, 0, myCanvas.width, myCanvas.height);
}
};
img.src = reader.result;
`][1]
如何倾斜图像以适应梯形ctx我已经创建了
how do I skew the image to fit in the trapezium ctx that i have created
推荐答案
为什么2D API是2D
canvas 2D API被称为2D API是有充分理由的。它只能进行2D变换。
Why 2D API is 2D
The canvas 2D API is called a 2D API for a very good reason. It can only do 2D transformations.
你的形状......
The shape you have...
上图为您的形状添加注释。线A,C不平行。
The above image annotates your shape. Lines A,C are not parallel.
画布2D变换不适合矩形到那个形状,因为它没有足够的信息来处理会聚线以及如何在像素收敛时缩放像素。
The canvas 2D transformation can not fit a rectangle to that shape as it does not carry enough information to deal with the converging lines and how to scale the pixels as they converge.
你能做的最好就是近似
下一个图像使用两条线将形状平分。这些线将用于创建最适合使用2D变换的形状的变换。
The next image bisects the shape using two lines. These lines will be used to create the transform that will best fit the shape using the 2D transformation.
我们使用二等分线来定义变换的x和y轴,并使用每个的长度来确定比例。图像的中心点是其中一条二等分线的中心。
We use the bisecting lines to define the x and y axis of the transform and use the length of each to determine the scale. The center point of the image is the center of one of the bisecting lines.
const ctx = canvas.getContext("2d");
const path = [13, 28, 237, 7, 285, 105, 73, 151];
const imageURL = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/Sarcoramphus_papa_%28K%C3%B6nigsgeier_-_King_Vulture%29_-_Weltvogelpark_Walsrode_2013-01.jpg/675px-Sarcoramphus_papa_%28K%C3%B6nigsgeier_-_King_Vulture%29_-_Weltvogelpark_Walsrode_2013-01.jpg";
function setStyle(style){
Object.keys(style).forEach(key => ctx[key] = style[key]);
}
function drawPath(path, style) {
var i = 0;
setStyle(style);
ctx.beginPath();
ctx.moveTo(path[i++], path[i++]);
while (i < path.length) {
ctx.lineTo(path[i++], path[i++]);
}
ctx.closePath();
ctx.stroke();
}
function markPath(path, style, marks) {
var i = 0;
var len = path.length;
setStyle(style);
while (i < len) {
ctx.fillText(
marks[i >> 1],
(path[i] + path[((i++) + 2) % len]) / 2,
(path[i] + path[((i++) + 2) % len]) / 2
);
}
}
function bisectPath(path, modulo, style) {
var i = 0;
var len = path.length;
setStyle(style);
ctx.beginPath();
while (i < len) {
ctx.moveTo(
(path[i] + path[((i++) + 2) % len]) / 2,
(path[i] + path[((i++) + 2) % len]) / 2
);
i += modulo;
ctx.lineTo(
(path[i] + path[((i++) + 2) % len]) / 2,
(path[i] + path[((i++) + 2) % len]) / 2
);
i -= modulo + 2;
}
ctx.stroke();
}
// functions to create lines, get vectors, length and normals
function getLine(x1,y1,x2,y2){
return {
p1 : { x : x1 , y : y1 },
p2 : { x : x2 , y : y2 }
};
}
function getVec(line){
line.vec = {
x : line.p2.x - line.p1.x,
y : line.p2.y - line.p1.y
};
return line;
}
function getNormal(line){
line.len = Math.hypot(line.vec.x, line.vec.y);
line.norm = {
x : line.vec.x / line.len,
y : line.vec.y / line.len,
};
return line;
}
// create the 2 bisecting lines
var line1 = getNormal( getVec( getLine(
(path[0] + path[2]) / 2,
(path[1] + path[3]) / 2,
(path[4] + path[6]) / 2,
(path[5] + path[7]) / 2
)));
var line2 = getNormal( getVec( getLine(
(path[6] + path[0]) / 2,
(path[7] + path[1]) / 2,
(path[2] + path[4]) / 2,
(path[3] + path[5]) / 2
)));
// create an image to fit
var image = new Image;
image.src = imageURL;
image.onload = function(){
var w, h, sx, sy, cx, cy;
w = this.width;
h = this.height;
// calculate the image scales
sx = line2.len / w;
sy = line1.len / h;
// calculate the center
cx = (line1.p1.x + line1.p2.x) / 2;
cy = (line1.p1.y + line1.p2.y) / 2;
// now we have all the information needed to create the transformation
ctx.setTransform(
line2.norm.x * sx, // scale and direction of x axis
line2.norm.y * sx,
line1.norm.x * sy, // scale and direction of y axis
line1.norm.y * sy,
cx, cy, // the origin coordinate (0,0)
);
// Draw the image offset from its center by half its width and heigth
ctx.drawImage(this, -w / 2, -h / 2);
// reset the transformation
ctx.setTransform(1,0,0,1,0,0);
// draw the guides
drawPath(path, {
lineWidth : 0.5,
strokeStyle : "blue"
});
bisectPath(path, 2, {
lineWidth : 1,
strokeStyle : "white"
});
markPath(path, {
font : "18px arial",
textAlign : "center",
textBaseline : "middle",
fillStyle : "black"
}, ["A", "B", "C", "D"]);
}
<canvas id=canvas height=160></canvas>
这是你可以做的最好的canvas 2D API。您可以渲染每个像素来计算3D变换以适合您拥有的形状。取决于可能需要一些时间(CPU)的图像大小,结果将是正常的。
That is the best you can do with the canvas 2D API. You could render each pixel calculating the 3D transform to fit the shape you have. Depending on the image size that can take some time (CPU) to do and the result will be OK.
如果你真的需要3D变换,你应该使用webGL。 SO和网上有很多关于如何做到这一点的例子
If you really need the 3D transform you should use webGL. There are plenty of examples on SO and the web on how to do that
这篇关于如何在我使用路径绘制的梯形html画布上拟合图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!