setTransform和Scale以适合给定图像的Canvas

时间:2019-09-11 20:29:19

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

我在画布上有一张图片。 渲染图像后,我将画布顺时针旋转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。

原始图片- enter image description here

实际结果图片看起来像这样,无法缩放完整图片-

enter image description here

1 个答案:

答案 0 :(得分:2)

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

// 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度为步长旋转,并缩放以适合,填充和自然。 (底部代码段中的演示版本略为冗长)

// 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>