Javascript 在不使用CanvasRenderingContext2D.rotate()的情况下旋转图像

Javascript 在不使用CanvasRenderingContext2D.rotate()的情况下旋转图像,javascript,html,canvas,graphics,trigonometry,Javascript,Html,Canvas,Graphics,Trigonometry,我希望使用Javascript旋转绘制到画布上的图像,但不使用上下文的rotate方法(或任何JS库)。原因是,这表明我在另一种语言中遇到了一个问题,而我无法使用这些语言 我已经创建了一个初稿(如下),但我的实现有两个问题:复制位图的逐像素旋转速度非常慢,并且会在像素之间留下间隙 是否有更快的方法将位图数据放置在不会留下间隙的角度?如果你有任何问题,请告诉我。多谢各位 const c1=document.getElementById(“c1”); const c2=document.getEl

我希望使用Javascript旋转绘制到画布上的图像,但不使用上下文的
rotate
方法(或任何JS库)。原因是,这表明我在另一种语言中遇到了一个问题,而我无法使用这些语言

我已经创建了一个初稿(如下),但我的实现有两个问题:复制位图的逐像素旋转速度非常慢,并且会在像素之间留下间隙

是否有更快的方法将位图数据放置在不会留下间隙的角度?如果你有任何问题,请告诉我。多谢各位

const c1=document.getElementById(“c1”);
const c2=document.getElementById(“c2”);
常量滑块=document.getElementById('slider');
const removeAllChildNodes=(父节点)=>
{
while(父母,第一个孩子){
parent.removeChild(parent.firstChild);
}
}
常量rotatedBoundingBox=(宽度、高度、旋转)=>
{
设rot_w=Math.abs(宽度*Math.cos(旋转))+Math.abs(高度*Math.sin(旋转));
设rot_h=Math.abs(宽度*Math.sin(旋转))+Math.abs(高度*Math.cos(旋转));
返回{宽度:rot_w,高度:rot_h};
}
常量渲染=(旋转)=>{
const canvas=document.createElement(“canvas”);
const canvas2=document.createElement(“canvas”);
const ctx=canvas.getContext(“2d”);
const ctx2=canvas2.getContext(“2d”);
让txt=“你好,世界”;
ctx.font='20px无衬线';
让metrics=ctx.measureText(txt);
canvas.width=metrics.width;
canvas.height=metrics.actualBoundingBoxAscent+metrics.actualBoundingBoxDescent;
ctx.fillStyle=“#636674”;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.font='20px无衬线';
ctx.textAlign=“中心”;
ctx.fillStyle=“#ffaefa”;
ctx.fillText(txt,canvas.width/2,canvas.height);
const{width,height}=rotatedBoundingBox(canvas.width,canvas.height,rotation);
画布2.宽度=宽度;
画布2.高度=高度;
cos=数学cos(-rotation);
sin=数学sin(-rotation);
cx=画布宽度/2;
cy=画布高度/2;
对于(x=0;x{
document.getElementById('currentDegree').innerHTML=e.target.value;
const rad=parseInt(e.target.value)*Math.PI/180;
渲染(rad);
})
document.getElementById('currentDegree').innerHTML=slider.value;
渲染(parseInt(slider.value)*Math.PI/180)
画布
{
边框:1px实心rgba(0,0,0,0.2);
}
主要的
{
显示器:flex;
}
.包含
{
显示:内联块;
}

旋转:0°;
扫描线2D图像渲染。 要删除渲染中的孔,请扫描要渲染到的每个像素,并计算该像素在该图像上的位置

有一个轻微的成本,因为您最终扫描的像素没有内容,但可以解决,如果您使用

简单例子 下面的示例创建一个图像,获取图像的像素,并创建一个缓冲区来保存渲染的像素

它不是每个通道读写像素,而是创建缓冲区的
uint32阵列
视图,以便在一次操作中读取和写入所有4个像素通道

因为图像是均匀的,所以可以优化扫描线,以便每行只需计算一次完整变换

扫描线函数有6个参数
ox
oy
旋转原点,
ang
以弧度为单位的旋转,
scale
渲染图像的比例,
r32
UINT32图像数据的阵列视图包含要绘制的图像<代码>w32
UINT32图像数据的阵列视图,以保存结果渲染

它的性能相当不错,示例中每次更新渲染大约160000像素

const ctx=canvas.getContext(“2d”);
常数W=ctx.canvas.width,H=ctx.canvas.height;
createTestImage();
const pxWrite=ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height);
const w32=新的uint32阵列(pxWrite.data.buffer);/*8位版本不需要*/
const pxRead=ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height);
const r32=新的uint32阵列(pxRead.data.buffer);/*8位版本不需要*/
函数rotate(){
常数ang=angSlider.value*(Math.PI/180);
常量刻度=刻度滑动值/100;
/*对于8位,用下面的注释行替换下一行*/
扫描线(W/2、H/2、ang、比例、r32、w32);
//扫描线8bit(W/2、H/2、ang、刻度、pxRead.data、pxWrite.data);
ctx.putImageData(pxWrite,0,0);
}
功能扫描线(ox、oy、ang、scale、r32、w32){
常数xAx=数学cos(ang)/比例;
常数xAy=数学sin(ang)/标度;
w32.填充(0);
变量rx,ry,idxW,x=0,y=0;
while(y=0&&rx=0&&ry