我正在尝试在画布上编写旋转文本(在各种角度),但希望不要重叠文本。因此,在旋转画布之后,在填写文本之前,我尝试使用measureText().width
和getImageData()
测试文本背景,以确定没有任何文本可以使用新文本。旋转画布时,我找不到文本(彩色像素)。这是我的问题的简化版本(使用矩形)。我想知道为什么没有找到彩色像素?
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid black;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var cWidth=300, cHeight= 150;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// Rotate context around centre point
ctx.translate( cWidth/2, cHeight/2);
ctx.rotate(20 * Math.PI / 180);
// Draw 100x50px rectangle at centre of rotated ctx
ctx.fillStyle = "yellow";
ctx.fillRect(-50, -25, 100, 50);
// Is my rotated rectangle really there?
// i.e. any coloured pixels at rotated cxt centre
imgData = ctx.getImageData(-50, -25, 100, 50);
// All rectangle pixels should be coloured
for (var j=0; j<imgData.data.length; j++){
if (imgData.data[j] > 0){
alert ("Coloured");
break;
};
};
// Why none is found?
</script>
</body>
</html>
佩卡
答案 0 :(得分:1)
问题是翻译功能。您需要考虑排量。
试试这个:
imgData = ctx.getImageData(-50+cWidth/2,-25+cHeight/2,100,50);
答案 1 :(得分:0)
您的代码存在的问题是getImageData()
针对的是canvas
的错误部分。 x
和y
坐标应具有translate()
函数的相同值。这就是你的代码的样子:
// Translate the rectangle, rotate it and fill it
ctx.translate(cWidth/2, cHeight/2);
ctx.rotate(20 * Math.PI / 180);
ctx.fillStyle = "yellow";
ctx.fillRect(-50, -25, 100, 50);
// Get the rectangle rotation
var imgData = ctx.getImageData(cWidth/2, cHeight/2, 100, 50);
这是带有完整代码的JSfiddle。我希望我的回答可以帮到你!
答案 2 :(得分:0)
通用答案。
这个答案适用于任何类型的转换,并且依赖于2D上下文转换在javascript中镜像的事实。它逐个获取像素。另一种方法是通过变换渲染框的角并找到包含变换框的边界框来将像素作为块。使用该框来获取图像数据。您仍然需要转换要检查的每个像素地址,因为图像数据还将包含渲染框外部的额外像素。这可能比下面给出的解决方案更快,如果搜索的像素之间的距离很远,如果找到你想要的像素的几率很高并且你可以提前摆脱迭代,下面的解决方案会更好。
您需要使用此答案底部的转换API
var mMatrix = new Transform(); // creates a default matrix
// define the bounds
const box = {x : -50, y : -25, w : 100, h : 50}; // our box
ctx.translate( cWidth/2, cHeight/2); // set the context transform
ctx.rotate(20 * Math.PI / 180);
// draw the stuff
ctx.fillStyle = "yellow";
ctx.fillRect(box.x, box.y, box.w, box.h);
// mirror the ctx transformations
mMatrix.translate(cWidth/2, cHeight/2).rotate(20 * Math.PI / 180);
var ix,iy,x,y;
var v = new Transform.Vec(); // create a working vec to save memory usage and anyoning GC hits
for(iy = 0; iy < box.h; iy ++){ // for each vertical pixel
for(ix = 0; iy < box.w; ix ++){ // for each horizontal
v.x = ix + 0.5 + box.x; // use pixel center
v.y = iy + 0.5 + box.y;
mMatrix.applyToVec(v); // transform into screen coords.
v.x = Math.floor(v.x); // get rid of grogens
v.y = Math.floor(v.y);
// now we have the pixel address corresponding to the box coordinate ix,iy
// get one pixel first check if it is on the canvas
if(v.x >= 0 && v.x < ctx.canvas.width && v.y >= 0 && v.y < ctx.canvas.height){
var pD = ctx.getImageData(v.x,v.y,1,1).data;
var red = pD[0];
var green = pD[1];
var blue = pD[2];
var alpha = pD[3];
// now you have the RGB values
... do what ever you want with that info
}
}
}
转换API
这是答案所需的转换API。它是我编写的API的缩减,你可以用你想要的东西(除了邪恶的东西)。请参阅答案以了解用法这只是非常基础,您可以在网上找到更全面的Transform API(但我认为您不会发现它更快)
请参阅底部的评论以获取方法详细信息。大多数功能都是可链接的。
代码段无法运行。
var Transform = (function () {
var tx, ty, v1, v2, v3, mat;
// work vecs and transform provide pre assigned working memory
v1 = new Vec();
v2 = new Vec();
v3 = new Vec();
mat = new Transform();
ty = tx = 0;
function Transform(xAxisX, xAxisY, yAxisX, yAxisY, originX, originY) {
if (xAxisX === undefined) { // create identity matrix
this.xAxis = new Vec(); // Default vec is 1,0
this.yAxis = new Vec(0, 1);
this.origin = new Vec(0, 0);
} else if (yAxisY === undefined) { // if only 3 arguments assume that the 3 arguments are vecs
this.xAxis = new Vec(xAxisX.x, xAxisX.y); //
this.yAxis = new Vec(xAxisY.x, xAxisY.y);
this.origin = new Vec(yAxisY.x, xAxisY.y);
} else {
this.xAxis = new Vec(xAxisX, xAxisY); // Default vec is 1,0
this.yAxis = new Vec(yAxisX, yAxisY);
this.origin = new Vec(originX, originY);
}
};
function Vec(x, y) {
if (x === undefined || x === null) {
this.x = 1;
this.y = 0;
} else {
this.x = x;
this.y = y;
}
};
Vec.prototype = {
copy : function () {
return new Vec(this.x, this.y);
},
setAs : function (vec, y) { // set this to the value of vec, or if two arguments vec is x and y is y
if (y !== undefined) {
this.x = vec;
this.y = y;
return this;
}
this.x = vec.x;
this.y = vec.y;
return this;
}
}
Transform.prototype = {
xAxis : undefined,
yAxis : undefined,
origin : undefined,
Vec : Vec, // expose the Vec interface
copy : function () {
return new Transform(this.xAxis, this.yAxis, this.origin);
},
setAs : function (transform) {
this.xAxis.x = transform.xAxis.x;
this.xAxis.y = transform.xAxis.y;
this.yAxis.x = transform.yAxis.x;
this.yAxis.y = transform.yAxis.y;
this.origin.x = transform.origin.x;
this.origin.y = transform.origin.y;
return;
},
reset : function () { // resets this to the identity transform
this.xAxis.x = 1;
this.xAxis.y = 0;
this.yAxis.x = 0;
this.yAxis.y = 1;
this.origin.x = 0;
this.origin.y = 0;
return this;
},
apply : function (x, y) { // returns an object {x : trabsformedX, y : trabsformedY} the returned object does not have the Vec prototype
return {
x : x * this.xAxis.x + y * this.yAxis.x + this.origin.x,
y : x * this.xAxis.y + y * this.yAxis.y + this.origin.y
};
},
applyToVec : function (vec) { // WARNING returns this not the vec.
tx = vec.x * this.xAxis.x + vec.y * this.yAxis.x + this.origin.x;
vec.y = vec.x * this.xAxis.y + vec.y * this.yAxis.y + this.origin.y;
vec.x = tx;
return this;
},
invert : function () { // inverts the transform
// first check if just a scale translated identity matrix and invert that as it is quicker
if (this.xAxis.y === 0 && this.yAxis.x === 0 && this.xAxis.x !== 0 && this.yAxis.y !== 0) {
this.xAxis.x = 1 / this.xAxis.x;
this.xAxis.y = 0;
this.yAxis.x = 0;
this.yAxis.y = 1 / this.yAxis.y;
this.origin.x = -this.xAxis.x * this.origin.x;
this.origin.y = -this.yAxis.y * this.origin.y;
return this;
}
var cross = this.xAxis.x * this.yAxis.y - this.xAxis.y * this.yAxis.x;
v1.x = this.yAxis.y / cross;
v1.y = -this.xAxis.y / cross;
v2.x = -this.yAxis.x / cross;
v2.y = this.xAxis.x / cross;
v3.x = (this.yAxis.x * this.origin.y - this.yAxis.y * this.origin.x) / cross;
v3.y = - (this.xAxis.x * this.origin.y - this.xAxis.y * this.origin.x) / cross;
this.xAxis.x = v1.x;
this.xAxis.y = v1.y;
this.yAxis.x = v2.x;
this.yAxis.y = v2.y;
this.origin.x = v3.x;
this.origin.y = v3.y;
return this;
},
asInverse : function (transform) { // creates a new or uses supplied transform to return the inverse of this matrix
if (transform === undefined) {
transform = new Transform();
}
if (this.xAxis.y === 0 && this.yAxis.x === 0 && this.xAxis.x !== 0 && this.yAxis.y !== 0) {
transform.xAxis.x = 1 / this.xAxis.x;
transform.xAxis.y = 0;
transform.yAxis.x = 0;
transform.yAxis.y = 1 / this.yAxis.y;
transform.origin.x = -transform.xAxis.x * this.origin.x;
transform.origin.y = -transform.yAxis.y * this.origin.y;
return transform;
}
var cross = this.xAxis.x * this.yAxis.y - this.xAxis.y * this.yAxis.x;
transform.xAxis.x = this.yAxis.y / cross;
transform.xAxis.y = -this.xAxis.y / cross;
transform.yAxis.x = -this.yAxis.x / cross;
transform.yAxis.y = this.xAxis.x / cross;
transform.origin.x = (this.yAxis.x * this.origin.y - this.yAxis.y * this.origin.x) / cross;
transform.origin.y = - (this.xAxis.x * this.origin.y - this.xAxis.y * this.origin.x) / cross;
return transform;
},
multiply : function (transform) { // multiplies this with transform
var tt = transform;
var t = this;
v1.x = tt.xAxis.x * t.xAxis.x + tt.yAxis.x * t.xAxis.y;
v1.y = tt.xAxis.y * t.xAxis.x + tt.yAxis.y * t.xAxis.y;
v2.x = tt.xAxis.x * t.yAxis.x + tt.yAxis.x * t.yAxis.y;
v2.y = tt.xAxis.y * t.yAxis.x + tt.yAxis.y * t.yAxis.y;
v3.x = tt.xAxis.x * t.origin.x + tt.yAxis.x * t.origin.y + tt.origin.x;
v3.y = tt.xAxis.y * t.origin.x + tt.yAxis.y * t.origin.y + tt.origin.y;
t.xAxis.x = v1.x;
t.xAxis.y = v1.y;
t.yAxis.x = v2.x;
t.yAxis.y = v2.y;
t.origin.x = v3.x;
t.origin.y = v3.y;
return this;
},
rotate : function (angle) { // Multiply matrix by rotation matrix at angle
var xdx = Math.cos(angle);
var xdy = Math.sin(angle);
v1.x = xdx * this.xAxis.x + (-xdy) * this.xAxis.y;
v1.y = xdy * this.xAxis.x + xdx * this.xAxis.y;
v2.x = xdx * this.yAxis.x + (-xdy) * this.yAxis.y;
v2.y = xdy * this.yAxis.x + xdx * this.yAxis.y;
v3.x = xdx * this.origin.x + (-xdy) * this.origin.y;
v3.y = xdy * this.origin.x + xdx * this.origin.y;
this.xAxis.x = v1.x;
this.xAxis.y = v1.y;
this.yAxis.x = v2.x;
this.yAxis.y = v2.y;
this.origin.x = v3.x;
this.origin.y = v3.y;
return this;
},
scale : function (scaleX, scaleY) { // Multiply the matrix by scaleX and scaleY
this.xAxis.x *= scaleX;
this.xAxis.y *= scaleY;
this.yAxis.x *= scaleX;
this.yAxis.y *= scaleY;
this.origin.x *= scaleX;
this.origin.y *= scaleY;
return this;
},
translate : function (x, y) { // Multiply the matrix by translate Matrix
this.origin.x += x;
this.origin.y += y;
return this;
},
setTransform : function (xAxisX, xAxisY, yAxisX, yAxisY, originX, originY) {
this.xAxis.x = xAxisX;
this.xAxis.y = xAxisY;
this.yAxis.x = yAxisX;
this.yAxis.y = yAxisY;
this.origin.x = originX;
this.origin.y = originY;
return this;
},
transform : function (xAxisX, xAxisY, yAxisX, yAxisY, originX, originY) {
var t = this;
v1.x = xAxisX * t.xAxis.x + yAxisX * t.xAxis.x;
v1.y = xAxisY * t.xAxis.x + yAxisY * t.xAxis.y;
v2.x = xAxisX * t.yAxis.x + yAxisX * t.yAxis.x;
v2.y = xAxisY * t.yAxis.x + yAxisY * t.yAxis.y;
v3.x = xAxisX * t.origin.x + yAxisX * t.origin.y + originX;
v3.y = xAxisY * t.origin.x + yAxisY * t.origin.y + originY;
t.xAxis.x = v1.x;
t.xAxis.y = v1.y;
t.yAxis.x = v2.x;
t.yAxis.y = v2.y;
t.origin.x = v3.x;
t.origin.y = v3.y;
return this;
},
contextTransform : function (ctx) {
ctx.transform(this.xAxis.x, this.xAxis.y, this.yAxis.x, this.yAxis.y, this.origin.x, this.origin.y);
return this;
},
contextSetTransform : function (ctx) {
ctx.Settransform(this.xAxis.x, this.xAxis.y, this.yAxis.x, this.yAxis.y, this.origin.x, this.origin.y);
return this;
},
setFromCurrentContext : function(ctx){
if(ctx && typeof ctx.currentTransform === "object"){
var mat = ctx.currentTransform;
this.xAxis.x = mat.a;
this.xAxis.y = mat.b;
this.yAxis.x = mat.c;
this.yAxis.y = mat.d;
this.origin.x = mat.e;
this.origin.y = mat.f;
}
return this;
}
}
if(typeof document.createElement("canvas").getContext("2d").currentTransform !== "object"){
Transform.prototype.setFromCurrentContext = undefined;
}
return Transform;
})();
/*
rotate(angle) // Multiply matrix by rotation matrix at angle. Same as ctx.rotate
scale(scaleX, scaleY) // Multiply the matrix by scaleX and scaleY. Same as ctx.scale
translate(x, y) // Multiply the matrix by translate Matrix. Same as ctx.translate
setTransform(xAxisX, xAxisY, yAxisX, yAxisY, originX, originY) //Replaces the current reansform with the new values. Same as ctx.setTransform
transform(xAxisX, xAxisY, yAxisX, yAxisY, originX, originY) // multiplies this transform with the supplied transform. Same as ctx.transform
Transform.xAxis // Vec object defining the direction and scale of the x Axis. Values are in canvas pixel coordinates
Transform.yAxis // Vec object defining the direction and scale of the y Axis. Values are in canvas pixel coordinates
Transform.origin // Vec object defining canvas pixel coordinates of the origin
Transform.Vec // interface to a vec object with basic interface needed to support Transform
Transform.reset() // resets the transform to the identity matrix (the default matrix used by 2D context)
Transform.copy() // creates a new copy of this object
Transform.setAs(transform) // sets the content of this to the values of the argument transform
Transform.apply(x, y) { // Transforms the coords x,y by multiplying them with this. Returns an object {x : trabsformedX, y : trabsformedY} the returned object does not have the Vec prototype
Transform.applyToVec(vec) // transforms the point vec. WARNING returns this not the vec.
Transform.invert() // inverts the transform
Transform.asInverse(transform) // creates a new or uses supplied transform to return the inverse of this matrix
Transform.multiply(transform) // multiplies this with transform
Transform.contextTransform(ctx) // multiplies the supplied context (ctx) transform by this.
Transform.contextSetTransform(ctx) // set the supplied context (ctx) transform to this
Transform.setFromCurrentContext(ctx) // Only for supported browser. Sets this to the supplied context current transformation. May not be available if there is no browser support
There is also access to the very simple Vec object. To create a vec `new Transform.Vec(x,y)`
*/