如何在HTML画布中缩放imageData?

时间:2010-08-10 11:21:06

标签: html canvas getimagedata

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

5 个答案:

答案 0 :(得分:34)

您可以将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/

答案 1 :(得分:16)

我需要在没有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;
}

我希望至少有一个其他程序员可以将这个复制并粘贴到他们的编辑器中,同时嘀咕着,“但是为了上帝的恩典,我会去。”

答案 2 :(得分:15)

我知道这是一个古老的主题,但由于人们喜欢它可能会发现它有用,我将我的优化添加到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秒。

答案 3 :(得分: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

上的文档

答案 4 :(得分:2)

@ 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;
}