2010-08-10 129 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