简体   繁体   English

我的图像在旋转时不会占据画布的整个宽度

[英]My Image doesn't take the full width of the canvas when rotated

So I was playing around the canvas and I tried rotating images loaded from my device hard disk as seen below:所以我在画布上玩,我尝试旋转从我的设备硬盘加载的图像,如下所示:

class imageEdits {
    constructor(canvas, imageSrc, canvasWidth, canvasHeight) {
        this.canvas = canvas;
        this.ctx = this.canvas.getContext("2d");
        this.image = new Image();
        this.image.src = imageSrc;
        this.cWidth = canvasWidth;
        this.cHeight = canvasHeight;
    }

    rotateImage = deg => {
        this.ctx.save();

        function degToRad(deg) {
            return (1 / 57.3) * deg;
        }

        let imageHeight = this.image.naturalHeight,
            imageWidth = this.image.naturalWidth;

        if (deg !== 0 && deg !== 180) {
            imageHeight = this.image.naturalWidth;
            imageWidth = this.image.naturalHeight;
        } else {
            (imageHeight = this.image.naturalHeight),
                (imageWidth = this.image.naturalWidth);
        }
        const {
            canvasStyle: { height, width, scale, aspectRatio },
        } = this.computeAspectRatio(imageHeight, imageWidth);
        console.log({ height, width, scale, aspectRatio });
        const halfWidth = width / 2;
        const halfHeight = height / 2;
        this.ctx.translate(halfWidth, halfHeight);

        this.ctx.rotate(degToRad(deg));
        this.canvas.style.transform = `scale3d(${scale}, ${scale}, 1)`;
        this.canvas.style.backgroundColor = "rgb(0,0,0)";
        this.canvas.style.transformOrigin = `top left`;
        console.log({ width, height });
        this.ctx.drawImage(this.image, -halfWidth, -halfHeight, width, height);

        this.ctx.restore();
    };

    computeAspectRatio = (imageHeight, imageWidth) => {
        const height = imageHeight;
        const width = imageWidth;

        (scale = 1), (canvasStyle = {});

        this.canvas.width = width;
        this.canvas.height = height;

        const scaleX = this.cWidth / width;
        const scaleY = this.cHeight / height;

        if (scaleX > scaleY) scale = scaleY;
        else scale = scaleX;

        canvasStyle = { height, width, scale };

        return { canvasStyle };
    };
}

The problem with the code is that when I rotate the image to the inverse of its aspect ratio which is 90degree of 180degree the image gets centered and doesn't take the full width or height as the case may be of the canvas.代码的问题是,当我将图像旋转到其纵横比的倒数(即 180 度的 90 度)时,图像会居中,并且不会采用画布的全宽或全高。

here is a jsfiddle of the working code这是工作代码的jsfiddle

And this is what my expected output should look like这就是我预期的输出应该是什么样子

But instead this is what I get但相反,这就是我得到的

Please does anyone see what I am doing wrong?请问有人看到我做错了什么吗? Thanks in advance :)提前致谢 :)

In general a rotation around the center is done by translating the context to the mid-point of the canvas, rotating the context and finally drawing the image at the negative half of it's width horizontally and negative half of it's height vertically.一般来说,围绕中心的旋转是通过将上下文转换到画布的中点来完成的,旋转上下文,最后在水平宽度的负一半和垂直高度的负一半处绘制图像。

What makes things a bit harder in your case is that the image should always fill the entire canvas, while maintaining it's correct aspect ratio.在您的情况下,让事情变得有点困难的是,图像应始终填满整个画布,同时保持正确的纵横比。 To do this we would need to know the exact width & height of the image - or more precisely it's bounding box - at a given angle.为此,我们需要知道图像在给定角度的确切宽度和高度 - 或者更准确地说它是边界框。 Luckily we just have to deal with four angles, so it's just a matter of swapping the width & height at 90° and 270° - as you already did.幸运的是,我们只需要处理四个角度,所以只需在 90° 和 270° 处交换宽度和高度 - 正如您已经做过的那样。

Now that we know the image's dimensions we need to compute the scale along both axes and see which one of those doesn't exceed the canvas width & height after multiplication.现在我们知道了图像的尺寸,我们需要计算沿两个轴的比例,并查看乘法后哪一个不超过画布宽度和高度。

This scale is then used to scale the context - not the css scale you used to size the canvas itself.然后使用此比例来缩放上下文 - 而不是用于调整画布本身大小的 css 比例。

Here's an example based on your code (just click on 'Run code snippet'):这是基于您的代码的示例(只需单击“运行代码片段”):

 const canvas = document.getElementById("edit-canvas"); const ctx = canvas.getContext("2d"); const canvasWidth = 320; const canvasHeight = 200; let deg = 0; let image; canvas.width = canvasWidth; canvas.height = canvasHeight; function degToRad(deg) { return (1 / 57.3) * deg; } function draw() { let scale, imageHeight, imageWidth, scaleX, scaleY; if (deg != 0 && deg != 180) { imageHeight = image.width; imageWidth = image.height; } else { imageHeight = image.height; imageWidth = image.width; } scaleX = canvasWidth / imageWidth; scaleY = canvasHeight / imageHeight; if (imageWidth * scaleX <= canvasWidth && imageHeight * scaleX <= canvasHeight) { scale = scaleX; } else { scale = scaleY; } ctx.save(); ctx.clearRect(0, 0, canvasWidth, canvasHeight); ctx.translate(canvasWidth / 2, canvasHeight / 2); ctx.rotate(degToRad(deg)); ctx.scale(scale, scale); ctx.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height); ctx.restore(); } image = new Image(); image.onload = draw; image.src = "https://picsum.photos/id/1079/300/200"; document.getElementById("rotate").addEventListener("click", () => { deg += 90; if (deg == 360) deg = 0; draw(); });
 <div class="canvas-container"> <input type="button" id="rotate" style="padding: 10px; font-size: 16px; position: absolute" value="Rotate" /> <canvas id="edit-canvas" style="border: 1px solid #000; margin-left: 10px;background-color: #c1f0c1;"></canvas> </div>

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

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