35

我的网页中有一个画布;我在这个画布中创建了一个新的图像数据,然后我通过myImgData.data[]数组修改了一些像素。现在我想缩放这个图像并让它更大。我尝试通过缩放上下文,但图像仍然很小。是否有可能做到这一点?谢谢

4

5 回答 5

40

您可以将 imageData 绘制到新画布上,缩放原始画布,然后将新画布绘制到原始画布上。

像这样的东西应该工作:

var imageData = context.getImageData(0, 0, 100, 100);
var newCanvas = $("<canvas>")
    .attr("width", imageData.width)
    .attr("height", imageData.height)[0];

newCanvas.getContext("2d").putImageData(imageData, 0, 0);

context.scale(1.5, 1.5);
context.drawImage(newCanvas, 0, 0);

这是一个功能演示http://jsfiddle.net/Hm2xq/2/

于 2010-08-10T13:26:31.183 回答
17

我需要在没有 putImageData() 导致的插值的情况下做到这一点,所以我通过将图像数据缩放到一个新的、调整大小的 ImageData 对象来做到这一点。我想不出其他任何时候我认为使用 5 个嵌套的 for 循环是个好主意:

function scaleImageData(imageData, scale) {
  var scaled = c.createImageData(imageData.width * scale, imageData.height * scale);

  for(var row = 0; row < imageData.height; row++) {
    for(var col = 0; col < imageData.width; col++) {
      var sourcePixel = [
        imageData.data[(row * imageData.width + col) * 4 + 0],
        imageData.data[(row * imageData.width + col) * 4 + 1],
        imageData.data[(row * imageData.width + col) * 4 + 2],
        imageData.data[(row * imageData.width + col) * 4 + 3]
      ];
      for(var y = 0; y < scale; y++) {
        var destRow = row * scale + y;
        for(var x = 0; x < scale; x++) {
          var destCol = col * scale + x;
          for(var i = 0; i < 4; i++) {
            scaled.data[(destRow * scaled.width + destCol) * 4 + i] =
              sourcePixel[i];
          }
        }
      }
    }
  }

  return scaled;
}

我希望至少有其他程序员可以将其复制并粘贴到他们的编辑器中,同时喃喃自语:“除了上帝的恩典,我去吧。”

于 2012-02-04T05:12:14.153 回答
17

我知道这是一个古老的主题,但由于喜欢的人可能会觉得它很有用,我将我的优化添加到 rodarmor 的代码中:

function scaleImageData(imageData, scale) {
    var scaled = ctx.createImageData(imageData.width * scale, imageData.height * scale);
    var subLine = ctx.createImageData(scale, 1).data
    for (var row = 0; row < imageData.height; row++) {
        for (var col = 0; col < imageData.width; col++) {
            var sourcePixel = imageData.data.subarray(
                (row * imageData.width + col) * 4,
                (row * imageData.width + col) * 4 + 4
            );
            for (var x = 0; x < scale; x++) subLine.set(sourcePixel, x*4)
            for (var y = 0; y < scale; y++) {
                var destRow = row * scale + y;
                var destCol = col * scale;
                scaled.data.set(subLine, (destRow * scaled.width + destCol) * 4)
            }
        }
    }

    return scaled;
}

这段代码使用更少的循环,运行速度大约快 30 倍。例如,在 100*100 区域的 100 倍缩放中,此代码需要 250 毫秒,而其他代码需要 8 秒以上。

于 2013-12-08T10:17:14.957 回答
13

您可以使用 drawImage 方法缩放画布。

context = canvas.getContext('2d');
context.drawImage( canvas, 0, 0, 2*canvas.width, 2*canvas.height );

这会将图像缩放到两倍大小并将其西北部分渲染到画布上。缩放是通过 drawImage 方法的第三个和第四个参数来实现的,它们指定了图像的最终宽度和高度。

请参阅 MDN 上的文档https://developer.mozilla.org/en-US/docs/DOM/CanvasRenderingContext2D#drawImage%28%29

于 2012-12-18T16:06:48.163 回答
1

@Castrohenge 的答案有效,但正如 Muhammad Umer 指出的那样,之后它会弄乱原始画布上的鼠标坐标。如果您想保持执行额外缩放(用于裁剪等)的能力,那么您需要使用第二个画布(用于缩放),然后从第二个画布获取图像数据并将其放入原始画布中。像这样:

function scaleImageData(imageData, scale){
    var newCanvas = $("<canvas>")
      .attr("width", imageData.width)
      .attr("height", imageData.height)[0];

    newCanvas.getContext("2d").putImageData(imageData, 0, 0);

    // Second canvas, for scaling
    var scaleCanvas = $("<canvas>")
      .attr("width", canvas.width)
      .attr("height", canvas.height)[0];

    var scaleCtx = scaleCanvas.getContext("2d");

    scaleCtx.scale(scale, scale);
    scaleCtx.drawImage(newCanvas, 0, 0);

    var scaledImageData =  scaleCtx.getImageData(0, 0, scaleCanvas.width, scaleCanvas.height);

    return scaledImageData;
}
于 2016-11-23T19:41:12.453 回答