【问题标题】:setTransform and Scale to fit Canvas for the given imagesetTransform 和 Scale 以适合给定图像的 Canvas
【发布时间】:2020-01-13 17:19:57
【问题描述】:

我在 Canvas 上有一张图片。 渲染图像后,我将画布顺时针旋转 90 度,然后必须缩放以适合画布。

Scaling an image to fit on canvas Resize image and rotate canvas 90 degrees

有很多可用的解决方案,但不幸的是,它们都不适合我

这就是我现在所拥有的。

width = 300; // after rotation
                    height = 400; // after rotation
                    var scale = width / img.height; // how much to scale the image to fit

                    console.log(scale);
                    canvas.width = width;
                    canvas.height = height;
                    ctx.setTransform(
                         0, scale, // x axis down the screen
                        -scale, 0, // y axis across the screen from right to left
                        width,    // x origin is on the right side of the canvas
                        0         // y origin is at the top
                    );
                    ctx.drawImage(img, 0, 0);
                    ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default

目前,画布旋转正常,但图像无法根据画布宽度和高度正确调整或缩放。 原始图像很大,我想将其缩放以适合画布上的 300x400。

原图 -

实际结果图像如下所示,未缩放完整图像 -

【问题讨论】:

    标签: javascript canvas html5-canvas image-resizing drawimage


    【解决方案1】:

    要使图像适合显示区域,请使用最小比例来适应高度或适应宽度。

    // size of canvas
    const width = 100; 
    const height = 298;
    
    // image is assumed loaded and ready to be drawn
    
    // Get min scale to fit
    var scale = Math.min(width / image.width , height / image.height);
    
    // you can also scale to fill using max
    // var scale = Math.max(width / image.width , height / image.height);
    
    canvas.width = width;
    canvas.height = height;
    
    // // draw image from top left corner
    ctx.setTransform(scale, 0, 0, scale, 0, 0);
    ctx.drawImage(image, 0, 0);
    ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
    

    更新

    重新评论

    由于您遇到问题,但我仍然不确定您要对图像做什么,这里有一个通用功能,可以以 90 度的步长旋转图像,并缩放以适应、填充和自然。 (底部 sn-p 中的演示版本略显冗长)

    // img image to draw
    // rot 1 unit = 90 deg. scaleType fit or fill
    function drawRotatedImage(img, rot = 1, scaleType = "fit") {
      const w = img.naturalWidth;
      const h = img.naturalHeight;
    
      // direction of xAxis
      var xAxisX = Math.cos(rot * Math.PI / 2);
      var xAxisY = Math.sin(rot * Math.PI / 2);
    
      // modified transform image width and height to match the xAxis
      const tw = Math.abs(w * xAxisX - h * xAxisY);
      const th = Math.abs(w * xAxisY + h * xAxisX);
    
      var scale = 1; 
      if (scaleType === "fit") {
        scale = Math.min(canvas.width / tw, canvas.height / th);
      } else if (scaleType === "fill") {
        scale = Math.max(canvas.width / tw, canvas.height / th);
      }
    
      xAxisX *= scale;
      xAxisY *= scale;
    
      // Rotate scale to match scaleType . Center on canvas
      ctx.setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, canvas.width / 2, canvas.height / 2);
    
      // Image drawn offset so center is at canvas center
      ctx.drawImage(img, -w / 2, -h / 2, w, h);
    }
    

    并确保以下是使用您的图像经过测试的运行示例。

    const canWidth = 300;
    const canHeight = 400;
    const rot = 1;           
    const scaleType = "fit"; 
    const PI90 = Math.PI / 2;
    
    function drawRotatedImage(img, rot, scale) {
      ctx.setTransform(1, 0, 0, 1, 0, 0); 
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    
      const w = img.naturalWidth, h = img.naturalHeight;
      var xAX = Math.cos(rot *= PI90 ), xAY = Math.sin(rot);
      const tw = Math.abs(w * xAX - h * xAY);
      const th = Math.abs(w * xAY + h * xAX);
      scale = Math[scale === "fit" ? "min" : "max" ](canvas.width / tw, canvas.height / th);
      xAX *= scale;
      xAY *= scale;
      ctx.setTransform(xAX, xAY, -xAY, xAX, canvas.width / 2, canvas.height / 2);
      ctx.drawImage(img, -w / 2, -h / 2, w, h);
    }
    
    
    
    
    
    
    
    
    
    // Stuff for demo and test. unrelated to answer.
    
    
    const ctx = canvas.getContext("2d");  
    // size canvas
    canvas.width = canWidth;
    canvas.height = canHeight;
    const img = new Image;
    const tests = [[0,"fit"], [1,"fit"], [2,"fit"], [3,"fit"],[0,"fill"], [1,"fill"], [2,"fill"], [3,"fill"]];
    
    tests.clicker = 0;
    img.src = "https://i.stack.imgur.com/SQmuv.jpg";
    img.addEventListener("load", () => {
      info.textContent = ((rot % 4) * 90) + "deg CW scaled to " + scaleType.toUpperCase() + " click canvas to rotate and switch scales";
      drawRotatedImage(img, rot, scaleType)
    });
    
    
    canvas.addEventListener("click",() => {
      const test = tests[tests.clicker++ % tests.length];
      info.textContent = ((test[0] % 4) * 90) + "deg CW scaled to " + test[1].toUpperCase();
      drawRotatedImage(img, ...test)
    });
    body {
       font-family: "arial black";
    }
    canvas {
      border: 1px solid black;
      position: absolute;
      top: 30px;
      left: 10px;    
    }
    #info {
      position: absolute;
      top: 2px;
      left: 10px;
    }
    <canvas id="canvas"></canvas>
    
    <div id="info"></div>

    【讨论】:

    • 我必须先顺时针旋转图像,所以上面提到的 setTransform 不起作用。我的示例中的那个可以正确旋转图像。使用最小比例或最大比例似乎也不起作用。它仍然剪切图像。我想要的宽度是 300,高度是 400
    • 这些是一些非常有用的sn-ps,将来会帮助更多的人。它解决了我的问题。图像现在正在缩放并适合画布。谢谢
    • 我需要多一点帮助,如何提高缩放后的图像质量以适应上述过程?目前我的 880KB 图像减少到 501Kb。它现在显示模糊。尝试jsfiddle.net/9g9Nv/442jsfiddle.net/9g9Nv/96
    • above 2 jsfiddle 提高了质量,但不确定如何使其与我们上面的 90 度旋转解决方案一起工作?基本上我想使用其中一个 jsfiddle 并将图像顺时针转换为 90 度。
    • 您能否指导我如何将画布顺时针旋转 90 度进入这个 jsfiddle。 jsfiddle.net/9g9Nv/442 这提高了图像质量但无法计算我们的旋转。
    猜你喜欢
    • 2012-02-16
    • 2013-05-19
    • 2019-06-12
    • 2014-10-27
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    相关资源
    最近更新 更多