2010-08-10 130 views
26

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

回答

31

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

这很好用。 – mikechambers 2011-01-26 07:17:24

+10

我只想补充说,你可以做到这一点,而无需创建另一个画布作为 ctx.drawImage(ctx.canvas,0,0); 将画布绘制到自身上,并且可以在绘制该图时进行缩放。 – Overcode 2013-05-12 19:01:29

+3

但是这个比例也弄乱了坐标10 x是1.5 * 10。你怎么补偿那个 – 2014-11-07 04:14:13

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

我希望至少一个其他程序员可以复制并粘贴到自己的编辑一边喃喃自语, “除了上帝的恩典,我去吧。”

+0

也可以使用更多质量插值方法,如双线性或样条线。 – 2013-01-11 08:29:58

+3

@KvanTTT完全正确,尽管有时候你想要那些矮胖的像素。 – 2013-09-06 12:08:26

+1

'c'变量指的是什么? – 2016-06-03 09:01:17

11

我知道这是一个老话题,但因为人们喜欢会发现它很有用,我我的优化添加到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秒以上。

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

for,'canvas.width'和'canvas.height',其中是否定义了变量'canvas'? – 2017-05-11 23:26:27