繁体   English   中英

当我使用 context.rotate 时,画布旋转 180 度而不是 90 度

[英]canvas rotates of 180 degrees instead of 90 when I use context.rotate

更新 - 第二部分
我注意到在旋转图像之前执行 ajax 调用时会出现问题。
我这样做:

$.ajax({
    type:'POST',
    beforeSend: function(request) {
        request.setRequestHeader("Authorization", "Bearer {{ app('request')->token }}");
    },
    url: "my-url-to-rotate-image-on-server/90",
    success:function(data) {
        $('#my_id').rotate(90); // the rotate function is the code I wrote below
    },
    error: function(data) { }
});

如果我删除 ajax 调用并只旋转图像,它就可以工作。


我需要将图像旋转 90 度,但图像旋转了 180 度。
这是我在网上找到的代码(一个 jquery 插件),我使用:

var p = this.get(0);
p.angle = 90;

if (p.angle >= 0) {
    var rotation = Math.PI * p.angle / 180;
} else {
    var rotation = Math.PI * (360+p.angle) / 180;
}
var costheta = Math.cos(rotation);
var sintheta = Math.sin(rotation);

var canvas = document.createElement('canvas');
var onLoad = false;
if (!p.oImage) {
    canvas.oImage = new Image();
    canvas.oImage.src = p.src;
    canvas.oImage.width = p.width;
    canvas.oImage.height = p.height;
    onLoad = true;
} else {
    canvas.oImage = p.oImage;
}

canvas.style.width = canvas.width = Math.abs(costheta*canvas.oImage.width) + Math.abs(sintheta*canvas.oImage.height);
canvas.style.height = canvas.height = Math.abs(costheta*canvas.oImage.height) + Math.abs(sintheta*canvas.oImage.width);

var context = canvas.getContext('2d');
context.save();
if (rotation <= Math.PI/2) {
    context.translate(sintheta*canvas.oImage.height,0);
} else if (rotation <= Math.PI) {
    context.translate(canvas.width,-costheta*canvas.oImage.height);
} else if (rotation <= 1.5*Math.PI) {
    context.translate(-costheta*canvas.oImage.width,canvas.height);
} else {
    context.translate(0,-sintheta*canvas.oImage.width);
}
context.rotate(rotation);

if (onLoad) {
    canvas.oImage.onload = function() {
        context.drawImage(canvas.oImage, 0, 0, canvas.oImage.width, canvas.oImage.height);
        context.restore();
    };
} else {
    context.drawImage(canvas.oImage, 0, 0, canvas.oImage.width, canvas.oImage.height);
    context.restore();
}

我得到的是画布尺寸正确旋转(我的意思是,旧宽度变成新高度,反之亦然),但图像旋转了 180 度而不是 90 度。

我不知道如何调试它。

更新
我注意到当图像 src 是 http url 时会发生奇怪的行为。
如果图像 src 是 blob,则代码完美运行。

 window.addEventListener('load', onDocLoaded, false); function onDocLoaded(evt) { let img = document.querySelector('img'); let width = img.naturalWidth, height=img.naturalHeight; let canvas = document.createElement('canvas'); canvas.width = height; canvas.height = width; let ctx = canvas.getContext('2d'); ctx.rotate(Math.PI/2); ctx.translate(0,-height); ctx.drawImage(img,0,0); document.body.appendChild(canvas); }
 body { background-color: #333; }
 <img id='theImage' src='https://i.stack.imgur.com/Zqh6Am.png'/>

使用 cos(0)、sin(0) 而不是北时,0 度指向东,这就是为什么您认为这在实际上正确时不起作用。

当您向东添加 90 度时,它正确地指向南,给人的印象是它旋转了 180 度。

如果您希望 0 度指向北。 我们知道它是 90 度,然后将角度减去 90 度。

你在哪里

 p.angle = 90;

用。。。来代替...

 const POINT_NORTH = -90;
 p.angle = POINT_NORTH + 90;

您从网上获取的代码(应该带有参考/归属)是非常古老的学校(至少 5 岁)。 最重要的是,代码质量很差。

请注意,2d 上下文translatescalerotatetransform是累积的。 如果你调用ctx.rotate(Math.PI/2) (90 deg) 然后再次调用它ctx.rotate(Math.PI/2)你实际上已经旋转了Math.PI (180 deg)。 但是,代码每次都会创建一个新画布,因此这不会导致双重旋转。 为什么会发生这种情况在代码中并不明显。

画布上的旋转是顺时针方向。 0 度是在 3 点钟。

加载并旋转 90 度

分离关注点并使用现代 JS。 加载图像和显示图像应该是单独的功能

首先是一个旋转图像并适合画布的函数

// Rotates image 90 and sets canvas size to fit rotated image
function drawImageRot90(ctx, image) {
    ctx.canvas.style.width = (ctx.canvas.width = image.height) + "px";
    ctx.canvas.style.height = (ctx.canvas.height = image.width) + "px";
    ctx.setTransform(0, 1, -1, 0, ctx.canvas.width, 0);  // overwrite existing transform
    ctx.drawImage(image, 0, 0);
    ctx.setTransform(1, 0, 0, 1, 0, 0);                  // reset default transform
}

然后是加载图像的函数。 该函数返回一个承诺,该承诺将在加载时传递图像。

// Return promise to provide loaded image as described in details AKA `p`
function loadImage(details) {
    return new Promise(loaded => {
        if (!details.oImage) {
            const img = new Image;
            img.src = details.src
            img.addEventListener("load",() => {
                    img.width = details.width;
                    img.height = details.height;
                    loaded(img);
                }, {once: true}
            );
        } else {
            loaded(details.oImage);
        }
    });
}

把它放在一起

loadImage(this.get(0))
    .then((img) => {
        const canvas = document.createElement("canvas");
        drawImageRot90(canvas.getContext("2d"), img);
    })
    

以 90 为步长旋转的功能

function drawImageRot(ang, ctx, image) { // ang must be 0, 90, 180, 270 or will default 180
    if (ang === 90 || ang === 270) {
        ctx.canvas.style.width = (ctx.canvas.width = image.height) + "px";
        ctx.canvas.style.height = (ctx.canvas.height = image.width) + "px";
        if (ang === 90) { ctx.setTransform(0, 1, -1, 0, ctx.canvas.width, 0) } 
        else { ctx.setTransform(0, -1, 1, 0, 0, ctx.canvas.height) }
    } else {
        ctx.canvas.style.width = (ctx.canvas.width = image.width) + "px";
        ctx.canvas.style.height = (ctx.canvas.height = image.height) + "px";
        if (ang === 0) { ctx.setTransform(1, 0, 0, 1, 0, 0) }
        else { ctx.setTransform(-1, 0, 0, -1, ctx.canvas.width, ctx.canvas.height) }
    }
    ctx.drawImage(image, 0, 0);
    ctx.setTransform(1, 0, 0, 1, 0, 0);   // reset default transform
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM