【问题标题】:ImageData flip image javascriptImageData 翻转图像 javascript
【发布时间】:2017-07-15 14:20:11
【问题描述】:

如何将 ImageData 对象中包含的图像旋转 45 度?

https://developer.mozilla.org/en/docs/Web/API/ImageData

我不想用我只想要 ImageData 的画布这样做。

【问题讨论】:

  • 翻转是指旋转?
  • 是的,我只想将 imageData 中的图像表示旋转 45 度。
  • imageData 是画布的底层像素数据,因此无论如何您都需要画布。如果您只想旋转图像,CSS 规则转换不会:rotate(45deg);还好吗?
  • 要在画布上旋转,请参阅此答案:stackoverflow.com/questions/17411991/html5-canvas-rotate-image
  • 好吧,看来你们太棒了。我更新了我的问题。

标签: javascript canvas


【解决方案1】:

扫描线渲染。

为什么在imageData??很慢

您可以使用扫描线渲染器。这会逐行扫描新的(目标),计算该点像素的 x,y 坐标,然后设置要匹配的颜色。

该示例通过图像数据数组旋转图像。设置旋转量和旋转中心,并创建一个非常简单的矩阵 (ax,ay,ox,oy) 以将扫描像素 (x,y) 旋转到查找像素 (rx,ry)。解决方案是最近邻查找,但您可以通过rx,ry 像素位置的小数余数解释像素颜色来创建双线性或三等。

const ctx = canvas.getContext("2d");
const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
const doFor = (count, cb) => { var i = 0; while (i < count && cb(i++) !== true); }; 


doFor(150,i=>{
  ctx.fillStyle = "hsl("+randI(360)+",100%,50%)";
  ctx.fillRect(randI(canvas.width),randI(canvas.height),randI(10,20),randI(10,20));
});
ctx.font = "28px Arial black";
ctx.textAlign = "center";
ctx.fillStyle = "black";
ctx.strokeStyle = "white";
ctx.lineWidth = "5";
ctx.lineJoin = "round";
ctx.strokeText("Rotate me!",128,128);
ctx.fillText("Rotate me!",128,128);


// the rotation origin    
const ox = 128;
const oy = 128;
// the rotation amount
const rot = Math.PI / 4; // 45 deg
// the rotated x axis
const ax = Math.cos(rot); // 45 deg
const ay = Math.sin(rot); // 45 deg
// get the source pixel data
const imageData = ctx.getImageData(0,0,256,256);
const d32 = new Uint32Array(imageData.data.buffer);
// create a destination pixel array
const rotImageData = new Uint32Array(imageData.data.length/4);
// scan each pixel and row adding pixels to rotImageData from the transformed
// x,y coordinate.
for(y = 0; y < 256; y += 1){
  for(x = 0; x < 256; x += 1){
    const ind = (x + y * 256);
    // transform the current pixel to the rotated pixel
    const rx = (x - ox) * ax - (y-oy) * ay + ox;
    const ry = (x - ox) * ay + (y-oy) * ax + oy;
    // use nearest pixel lookup and get index of original image
    const ind1 = ((rx | 0) + (ry | 0) * 256);
    rotImageData[ind] = d32[ind1];
  }
}
// create a second canvas
var c1 = document.createElement("canvas");
c1.width = 256;
c1.height = 256;

var ctx1 = c1.getContext("2d"); 
// put the new image data into the imageData array
d32.set(rotImageData);
// and put that on the new canvas
ctx1.putImageData(imageData,0,0);
// add the canvas to the page
document.body.appendChild(c1);


    
    
  
canvas {border : 2px solid black;}
&lt;canvas id="canvas" width=256 height=256&gt;&lt;/canvas&gt;

【讨论】:

  • 这正是我想要的,我想要 imageData 的原因是因为我在 web worker 中做一些接缝雕刻,而我从 github 得到的示例只处理垂直接缝。希望你的回答和我的“seamcarving”关键字会帮助别人。
  • @Aflred 如果您使用 32 位缓冲区,您可以获得更好的性能,不确定您是否有使用类型数组的经验,所以保持原样,但听起来您知道自己在做什么,所以已经改变了答案以更有效的形式。
  • 我尝试了一个比例为 1.5 的图像,尝试翻转它,它不起作用。jsfiddle.net/cqf2q5su 请用本地图像替换我的图像,画布不接受来自互联网的图像。跨度>
  • @Aflred 抱歉,我不明白您要做什么。像镜子一样翻转?或轮流旋转?扫描线算法将处理任何图像方面,并且可以对图像进行任何形式的转换。你小提琴有很多错误,for循环扫描目标图像的坐标,而不是源图像。如果您更改目标图像尺寸,则需要为该新图像创建一个 imageData 对象,您不能只将数据复制到源 imageData 对象中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-02
  • 2012-01-14
  • 2022-01-22
  • 2013-07-01
  • 2015-05-08
  • 1970-01-01
相关资源
最近更新 更多