簡體   English   中英

Javascript在畫布旋轉時找到像素

[英]Javascript find pixels while canvas is rotated

我正在嘗試在畫布上編寫旋轉文本(在各種角度),但希望不要重疊文本。 因此,在旋轉畫布之后,在填充文本之前,我嘗試使用measureText().widthgetImageData()來測試文本背景,以measureText().width沒有文本已經在那里搞亂了。 旋轉畫布時,我找不到文本(彩色像素)。 這是我的問題的簡化版本(使用矩形)。 我想知道為什么沒有找到彩色像素?

 <!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? // ie 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> 
黃色矩形應與測試圖像數據區域位於相同的點和角度。 什么地方出了錯? 我如何測試旋轉區域的顏色? 作為Javascript的新手,我試着在這個階段避免使用庫。

佩卡

問題是翻譯功能。 您需要考慮位移。

嘗試這個:

imgData = ctx.getImageData(-50+cWidth/2,-25+cHeight/2,100,50);

你的代碼的問題是getImageData()是針對canvas的錯誤部分。 xy坐標應具有與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 我希望我的回答可以幫到你!

一般目的答案。

這個答案適用於任何類型的轉換,並依賴於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)` */ 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM