javascript - 使用偏移原点在 Canvas 中缩放图像

标签 javascript html canvas image-scaling

这几天我一直在为这个问题苦苦挣扎。我的问题基于您可以在此处找到的代码 - http://codepen.io/theOneWhoKnocks/pen/VLExPX .在示例中,您将看到 3 张图像,第一张从 [0,0] 原点缩放,第二张从 Canvas 中心缩放,第三张我想从偏移图像的中心缩放。

基本上我希望图像按比例放大或缩小,但保持在 Angular 色虹膜的中心。您将在下方找到控制第三张图片渲染的代码片段。

function renderOffset(){
  var dims = getScaledDims();

  paintBG(ctx3);
  ctx3.drawImage(loadedImg, offsetX, offsetY, dims.width, dims.height);
  drawCenterAxis(ctx3);
}

经过多次谷歌搜索和浏览论坛后,我认为我需要使用 transformMatrix,但到目前为止我尝试过的任何东西都没有奏效。我期待着您的任何想法或建议,感谢您抽出宝贵时间。


进一步说明

我正在创建一个图像编辑器。对于我在此展示的特定用例,用户已将图像向左移动 108 像素并向上移动 8 像素。

var offsetX = -108;
var offsetY = 8;

当用户缩放偏移图像时,我希望它在可视 Canvas 区域的中心缩放(红色十字准线,或者在本例中为字符虹膜)。


更新

我已经更新了 codepen 链接以指向最终代码。以下是添加列表:

  • 添加了接受的答案中提到的一些代码。
  • 添加了拖动图像的功能。
  • 为偏移添加了视觉跟踪器。

最佳答案

诀窍是了解比例改变多个变量的方式。首先,它改变了 Canvas 上可见的源图像的数量。接下来,这与所需的缩放中心点相结合会影响我们应该从图像中的哪个位置开始绘制。

比例为 1.0 时,显示的源图像的像素数等于 dst Canvas 的像素数。也就是说,如果 Canvas 是 150x150,我们可以看到 150x150 的输入像素。但是,如果比例为 2.0,那么我们希望绘制两倍大小的东西。这意味着我们只希望在 dst Canvas 的 150x150 像素上显示 src 图像的 75x75 像素。同样,如果我们希望以 0.5 的比例绘制,我们应该期望看到 300x300 像素的 src 图像显示在 150x150 的 dst Canvas 中。也许您现在可以看到比例和 Canvas 大小之间的关系。

考虑到这一点,我们可以着手确定我们希望看到多少 src 图像。这很简单:

var srcWidth = canvas.width / scale;
var srcHeight = canvas.height / scale;

既然我们知道了将显示多少图像,我们就可以着手确定应该从图像中的什么位置开始绘制了。由于我们有一个指定的缩放中心点,我们知道这个点应该始终保持在 Canvas 的中心。

如果我们从等式中删除缩放比例,并使用之前的数字,我们可以看到我们想要显示 src 图像的 150x150 像素,并且我们需要开始在中心左侧上方 75 像素处绘制 -观点。这样做会绘制 150x150 像素的源图像,并将我们的中心点放在 Canvas 的中间。

如果我们随后重新考虑缩放,我们知道我们并不总是要绘制 src 图像的 150x150 像素,这意味着我们不能盲目地从中心点左侧和上方 75 像素开始 - 我们将不得不缩放这 75 像素。由于这 75 个像素等于我们将要显示的图像部分的宽度和高度的一半,我们可以通过将 srcWidth 和 srcHeight 除以 2 来计算开始绘制图像的点,并且然后从中心点减去这个值。

这样做会得到以下表达式:

ctx.drawImage(image, imgCenterX-(srcWidth/2), imgCenterY-(srcHeight/2), srcWidth, srcHeight, 0,0, canvas.width, canvas.height);

当我将这两者放在一个功能示例中时,我最终得到了这个:

"use strict";

var imgOriginX = 182, imgOriginY = 66;

function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
    var targetCanvas = byId('canvas3');
    var srcImage = byId('img1');

    drawImageScaled(targetCanvas, srcImage, imgOriginX, imgOriginY)
    drawCrosshair( byId('canvas3') );

    byId('scaleSlider').addEventListener('input', onScaleSliderChange, false);
}

/*
    code for scaling an image about an arbitrary point
*/

// canvas - target canvas element
// image - target canvas element
// imgCenterX - x coord of point of scaling centre-point (unit: pixels)
// imgCenterY - y coord of point of scaling centre-point (unit: pixels)
// scale - 1.0 = 100%
function drawImageScaled(canvas, image, imgCenterX, imgCenterY, scale)
{
    if (scale === undefined)
        scale = 1.0;

    var ctx = canvas.getContext('2d');
    ctx.clearRect(0,0,canvas.width,canvas.height);

    var srcWidth = canvas.width / scale;
    var srcHeight = canvas.height / scale;
    ctx.drawImage(image, imgCenterX-(srcWidth/2), imgCenterY-(srcHeight/2), srcWidth, srcHeight, 0,0, canvas.width, canvas.height);
}

function drawCrosshair(canvas)
{
    var ctx = canvas.getContext('2d');
    var width, height;
    width = canvas.width;
    height = canvas.height;
        ctx.save();
    ctx.beginPath();
        ctx.moveTo(width/2, 0);
        ctx.lineTo(width/2, height);
        ctx.moveTo(0, height/2);
        ctx.lineTo(width, height/2);
    ctx.closePath();
    ctx.strokeStyle = "red";
    ctx.stroke();
    ctx.restore();
}

function onScaleSliderChange(evt)
{
    var curValue = this.value;
    var scale = curValue / 100;
    var tgt, src;

    tgt = byId('canvas3');
    src = byId('img1');
    drawImageScaled(tgt, src, imgOriginX, imgOriginY, scale);
    drawCrosshair(tgt);
}
input[type=range]
{
    width: 18px;
    height: 122px;
    -webkit-appearance: slider-vertical;
}
canvas
{
    border: solid 1px #888;
}

img{ display:none;}
<img id='img1' src='/image/aFbEw.png'/>
<hr>
<canvas id='canvas3' width=150 height=150>Canvas not supported. :(</canvas>
<input id='scaleSlider' type="range" class="scale-slider js-scaleSlider" min="0" max="200" value="100" orient="vertical"/>

关于javascript - 使用偏移原点在 Canvas 中缩放图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31633355/

相关文章:

javascript - 扩展图像网格问题

javascript - 如何在 Canvas 中缩放 alpha 值?

javascript - 使用 node.destroy() 时如何删除 konva 形状/图像

javascript - 为什么使用 Javascript if 语句替换类名不起作用?

javascript - 从 Razor 输出 JavaScript

java - 传递参数 - 使用 Javascript 将 Python 转换为 HTML

javascript - d3 selection.attributes.key.nodevalue 不返回当前的 DOM 值

javascript - HTML5 Canvas 距离和移动对象

javascript - node.js connect-auth 应用程序?示例(用户注册/用户/ session 管理)

javascript - 如何移动 Canvas 元素?