代码之家  ›  专栏  ›  技术社区  ›  Masiar

如何在HTML画布中缩放图像数据?

  •  30
  • Masiar  · 技术社区  · 14 年前

    我的网页中有一个画布;我在画布中创建一个新的图像数据,然后通过myimgdata.data[]数组修改一些像素。现在我想放大这个图像。我尝试缩放上下文,但图像仍然很小。可以这样做吗? 谢谢

    5 回复  |  直到 8 年前
        1
  •  34
  •   Castrohenge    14 年前

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

        2
  •  16
  •   Casey Rodarmor    13 年前

    我需要在不使用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;
    }
    

    我希望至少还有一个程序员可以在他们的编辑器中复制并粘贴这个,同时低声说:“我在那里,但为了上帝的恩典。”

        3
  •  15
  •   user3079576    11 年前

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

    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秒以上。

        4
  •  13
  •   Sixtease    12 年前

    可以使用DrawImage方法缩放画布。

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

    这将使图像的大小增加一倍,并将其西北部分呈现到画布上。通过DrawImage方法的第三个和第四个参数实现缩放,该参数指定图像的最终宽度和高度。

    在MSN中查看文档 https://developer.mozilla.org/en-US/docs/DOM/CanvasRenderingContext2D#drawImage%28%29

        5
  •  2
  •   Chris Holmes    8 年前

    @卡斯特罗亨格的回答是可行的,但正如穆罕默德·乌默尔指出的那样,之后它会把原来画布上的鼠标坐标弄乱。如果要保持执行其他缩放(用于裁剪等)的能力,则需要使用第二个画布(用于缩放),然后从第二个画布获取图像数据并将其放入原始画布。像这样:

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