2014-03-05 152 views
4

在html5中,當您使用putImageData()繪製到畫布時,如果您繪製的某些像素是透明(或半透明),那麼如何保持畫布中的舊像素不受影響?putImageData(),如果新像素透明時如何保留舊像素?

例如:

var imgData = context.createImageData(30,30); 
for(var i=0; i<imgData.data.length; i+=4) 
{ 
imgData.data[i]=255; 
imgData.data[i+1]=0; 
imgData.data[i+2]=0; 
imgData.data[i+3]=255; 
if((i/4)%30 > 15)imgData.data[i+3] = 0; 
} 
context.putImageData(imgData,0,0); 

的30×30矩形的右半是透明的。 如果這是繪製在畫布上的東西,右側後面的像素被刪除(或成爲thransparent)。我如何保留它們?

回答

5

您可以使用getImageData創建一個半透明的疊加:

  • 創建一個臨時離屏畫布
  • getImageData從屏幕外的畫布上得到的像素數據
  • 修改像素,你的願望
  • putImageData將像素重新放在屏幕外畫布上
  • 使用drawImage將屏幕外畫布拖到屏幕畫布上

enter image description here

這裏的示例代碼和演示:http://jsfiddle.net/m1erickson/CM7uY/

<!doctype html> 
<html> 
<head> 
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> 
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> 
<style> 
    body{ background-color: ivory; } 
    canvas{border:1px solid red;} 
</style> 
<script> 
$(function(){ 

    var canvas=document.getElementById("canvas"); 
    var context=canvas.getContext("2d"); 

    // draw an image on the canvas 
    var img=new Image(); 
    img.onload=start; 
    img.src="https://dl.dropboxusercontent.com/u/139992952/stack1/landscape1.jpg"; 
    function start(){ 
     canvas.width=img.width; 
     canvas.height=img.height; 
     context.drawImage(img,0,0); 

     // overlay a red gradient 
     drawSemiTransparentOverlay(canvas.width/2,canvas.height) 

    } 

    function drawSemiTransparentOverlay(w,h){ 

     // create a temporary canvas to hold the gradient overlay 
     var canvas2=document.createElement("canvas"); 
     canvas2.width=w; 
     canvas2.height=h 
     var ctx2=canvas2.getContext("2d"); 

     // make gradient using ImageData 
     var imgData = ctx2.getImageData(0,0,w,h); 
     var data=imgData.data; 
     for(var y=0; y<h; y++) { 
      for(var x=0; x<w; x++) { 
       var n=((w*y)+x)*4; 
       data[n]=255; 
       data[n+1]=0; 
       data[n+2]=0; 
       data[n+3]=255; 
       if(x>w/2){ 
        data[n+3]=255*(1-((x-w/2)/(w/2))); 
       } 
      } 
     } 

     // put the modified pixels on the temporary canvas 
     ctx2.putImageData(imgData,0,0); 

     // draw the temporary gradient canvas on the visible canvas 
     context.drawImage(canvas2,0,0); 

    } 


}); // end $(function(){}); 
</script> 
</head> 
<body> 
    <canvas id="canvas" width=200 height=200></canvas> 
</body> 
</html> 

或者,你可以檢查出使用線性漸變更直接地做你的效果。

http://jsfiddle.net/m1erickson/j6wLR/

+0

謝謝,繪圖畫布到另一個使用的drawImage()正是我需要的。 – Mohsin

2

問題

如你所知,你的發言

if((i/4)%30 > 15)imgData.data[i+3] = 0; 

將在圖像的右半部分的像素是透明的,從而使頁面上的任何其他物體後面畫布可以通過畫布在該像素位置看到。但是,您仍然使用context.putImageData覆蓋畫布本身的像素,該像素會替換其以前的所有像素。您添加的透明度不會導致以前的像素透出,因爲putImageData的結果不是畫布中先前像素頂部的第二組像素,而是替換現有像素。

解決方案

我建議你開始你的代碼不能與createImageData將與空白組數據開始,而是與getImageData,這將給你現有的數據副本進行工作。然後,您可以使用條件語句來避免覆蓋要保留的圖像部分。這也將使您的功能更有效率。

var imgData = context.getImageData(30,30); 
for(var i=0; i<imgData.data.length; i+=4) 
{ 
    if((i/4)%30 > 15) continue; 
    imgData.data[i]=255; 
    imgData.data[i+1]=0; 
    imgData.data[i+2]=0; 
    imgData.data[i+3]=255; 
} 
context.putImageData(imgData,0,0); 
+0

謝謝。你是對的,使用getImageData()你可以用老像素做任何你想做的事情,但是你需要有一個公式來混合新像素和舊像素。我嘗試了一個,這很完美,但是很快當我開始在for循環(用於繪圖)中使用它時,當我繪製透明的東西時,我得到了一個奇怪的結果。 – Mohsin

0

我想複製一個CRISP,修改版本的畫布在它自己的頂部。我最終想出了適用的這個解決方案。

https://jsfiddle.net/4Le454ak/1/

複製部分是這個代碼:

var imageData = canvas.toDataURL(0, 0, w, h); 
var tmp = document.createElement('img'); 
tmp.style.display = 'none' 
tmp.src = imageData; 
document.body.appendChild(tmp); 
ctx.drawImage(tmp, 30, 30); 

發生了什麼事:

  • 從畫布上的影像數據複製
  • 圖像數據集到一個看不見的(有儘管如此)
  • 繪製圖像bac ķ到畫布上
  • 你可以刪除或重新使用在該點