在Canvas

时间:2015-11-06 21:30:35

标签: html5 canvas html5-canvas png

我有两幅画布 - 尺寸相同。 MainCanvas完全填充了背景图像。在SecondaryCanvas上我有一个小图像 - 一个公司徽标,它有一些透明区域(基本上所有白色像素都将其alpha减少到0)。

我想对SecondaryCanvas应用某种斜角或内部阴影,但仅限于存在实际图像的情况。通常情况下,我看到人们会走这条路,但我无法追踪非透明区域的边缘。

我该怎么做?我想到的是,我可以逐像素地扫描整个SecondaryCanvas并检查它的相邻像素是否透明(尝试找到' edge')。 ..并将适当的颜色应用于像素,如果它是......但这似乎非常占用CPU。

1 个答案:

答案 0 :(得分:3)

我知道使用卷积滤波器的速度最快。

从源图像复制到目标。我已为此解决方案添加了一些标记。

该功能(抱歉拼写错误)。

embose (imageDataSource,imageDataDestination,method,emboseImageEdge,perceptualCorrect,edgeOnly)

  • imageDataSource:源图像的像素数据
  • imageDataDestination:目的地的像素数据。必须是不同的 比源或结果不正确。必须大小相同
  • 方法:(字符串)“3像素软”,“3像素”,“1像素”之一// 忘了默认所以如果传递未知方法会崩溃。我相信你 可以修复
  • emboseImageEdge :(布尔值)如果图像边缘的真实像素 将被压印。
  • perceptualCorrect :( Boolean)如果true使用人类感知计算 亮度。运行时稍慢。
  • edgeOnly:(Boolean)如果为true,则仅在透明附近压印像素 边缘。否则,亮度会对所有不透明像素进行浮雕。

如果处理,函数返回true,否则返回false。如果为false,则不会更改像素。

待办事项。 我忘了添加Invert但是很容易做到只是反转val = -val embos数组中的所有val然后将中心值设置为1(必须是一个或看起来不好)。 您还可以通过旋转embos数组中的负/正线来旋转灯光的方向,但这有点复杂。 对于更柔和的浮雕,创建更大的卷积embos数组。设置sizehalfSize以匹配。 EG 3像素浮雕需要7 x 7阵列,size=7halfSize = 3具有相似的值集。 embos数组越大,函数越慢。 对于非常大的图像,这将阻止页面。如果对大图像使用此功能,请将此功能移至Web工作者。

因为它使用卷积滤波器,所以它可以适用于做许多其他滤波器。虽然这个只使用像素亮度,但很容易修改为每个颜色通道滤波器。所以过滤器类型可以适应。高斯模糊,模糊,锐化,边缘检测等等。

请参阅代码示例的底部如何使用它。

希望这可以满足你的需要或者可以适应这样做。任何问题随时都可以问。对不起,评论目前很少,但我的时间很短。很快就会回来修复。

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

// Groover API log dependency replacement 
function log(data){
   // console.log(data); // just suck it up
}

// Groover Bitmaps API dependency replacement
// Extracted from Groover.Bitmaps
var createImage= function(w,h){ // create a image of requier size
    var image = document.createElement("canvas"); 
    image.width = w;
    image.height =h;
    image.ctx = image.getContext("2d");  // tack the context onto the image
    return image;
}    
    

function embose(imageDataSource,imageDataDestination, method, emboseImageEdge, perceptualCorrect,edgeOnly){
    "use strict";
    var dataS = imageDataSource.data;
    var dataD = imageDataDestination.data;
    var w = imageDataSource.width;
    var h = imageDataSource.height;
    if(dataS.length !== dataD.length){
        return false; // failed due to size mismatch
    }
    var embos,size,halfSize;
    var lMethod = method.toLowerCase(); // some JS engines flag reasignment of
                                        // arguments as unoptimised as this 
                                        // is computationally intensive create a
                                        // new var for lowercase

    if(lMethod === "2 pixel soft" ){
        embos = [  
            -0.25   ,  -0.5 ,  -1,  -1 , 0.5,
            -0.5   ,  -1 ,  -1,  1 , 1,
            -1   ,  -1 ,  1, 1 , 1,
            -1   ,  -1 , 1, 1 , 0.5,
            -0.5   ,  1, 1, 0.5 , 0.25 
        ];
        size = 5;
        halfSize = 2;
    }else
    if(lMethod === "2 pixel" ){
        embos = [  
            -1   ,  -1 ,  -1,  -1 , 1,
            -1   ,  -1 ,  -1,  1 , 1,
            -1   ,  -1 ,  1, 1 , 1,
            -1   ,  -1 , 1, 1 , 1,
            -1   ,  1, 1, 1 , 1 
        ];
        size = 5;
        halfSize = 2;
    }else
    if(lMethod === "1 pixel" ){
        embos = [  
            -1 , -1,  -1,
            -1,  1, 1,
            1 , 1,  1 
        ];
        size = 3;
        halfSize = 1;
    }
var deb = 0
    var x,y,l,pl,g,b,a,ind,scx,scy,cx,cy,cInd,nearEdge,pc;
    pc = perceptualCorrect; // just for readability
    for(y = 0; y < h; y++){
        for(x = 0; x < w; x++){
            ind = y*4*w+x*4;
            l = 0;
            nearEdge = false;
            if(dataS[ind+3] !== 0){ // ignor transparent pixels
                for (cy=0; cy<size; cy++) {
                    for (cx=0; cx<size; cx++) {
                        scy = y + cy - halfSize;
                        scx = x + cx - halfSize;
                        if (scy >= 0 && scy < h && scx >= 0 && scx < w) {
                            cInd = (scy*w+scx)*4;
                            if(dataS[cInd+3] === 0){
                                nearEdge = true;
                            }
                            l += pc?(embos[cy*size+cx] * 
                                        ((Math.pow(dataS[cInd++]*0.2126,2)+
                                         Math.pow(dataS[cInd++]*0.7152,2)+
                                         Math.pow(dataS[cInd++]*0.0722,2)
                                        )/3)):
                                    (embos[cy*size+cx] * 
                                        ((dataS[cInd++]+
                                         dataS[cInd++]+
                                         dataS[cInd++]
                                        )/3));
                                      
                        }else
                        if(emboseImageEdge){
                            nearEdge = true;
                        }
                    }
                }
                        
                if((nearEdge && edgeOnly) || ! edgeOnly){
                    if(pc){
                        pl = Math.sqrt((Math.pow(dataS[ind]*0.2126,2) + Math.pow(dataS[ind+1]*0.7152,2) + Math.pow(dataS[ind+2]*0.0722,2))/3);
                        l = Math.sqrt(Math.max(0,l));

                        if(pl > 0){
                            pl = l/pl;
                            dataD[ind] = Math.sqrt(dataS[ind]*dataS[ind++]*pl);
                            dataD[ind] = Math.sqrt(dataS[ind]*dataS[ind++]*pl);
                            dataD[ind] = Math.sqrt(dataS[ind]*dataS[ind++]*pl);
                            dataD[ind] = dataS[ind]; // alpha not effected
                        }else{ // black pixel 
                            dataD[ind++] = 0;
                            dataD[ind++] = 0;
                            dataD[ind++] = 0;
                            dataD[ind] = dataS[ind];
                        }
                    }else{
                        l = Math.max(0,l);
                        pl = (dataS[ind]+dataS[ind+1]+dataS[ind+2])/3;
                        if(pl > 0){
                            pl = l/pl;
                            dataD[ind] = dataS[ind++]*pl;
                            dataD[ind] = dataS[ind++]*pl;
                            dataD[ind] = dataS[ind++]*pl;
                            dataD[ind] = dataS[ind]; // alpha not effected
                            
                        }else{ // black pixel 
                            dataD[ind++] = 0;
                            dataD[ind++] = 0;
                            dataD[ind++] = 0;
                            dataD[ind] = dataS[ind];
                        }
                    }
                }else{  // if not edge then just copy image pixel to dest
                    dataD[ind] = dataS[ind++];
                    dataD[ind] = dataS[ind++];
                    dataD[ind] = dataS[ind++];
                    dataD[ind] = dataS[ind];
                }
            }else{  // set transparent pixel to zero
                dataD[ind+3] = 0;
            }
        }
 
    }
    // all done
    return true; // return success
}
var img = createImage(128,128);
img.ctx.font = "32px arial black";
img.ctx.textAlign = "center";
img.ctx.textBaseline = "middle";
img.ctx.lineCap = "round";
img.ctx.lineJoin = "round";
img.ctx.lineWidth = 4
img.ctx.strokeStyle = "#3AD";
img.ctx.fillStyle = "#334";
img.ctx.strokeText("LOGO!",64,64);
img.ctx.fillText("LOGO!",64,64);
ctx.drawImage(img,0,0);
var img1 = createImage(128,128);
var imgData = img.ctx.getImageData(0,0,128,128);
var imgData1 = img1.ctx.getImageData(0,0,128,128);
if(embose(imgData,imgData1,"2 pixel soft",false, true, false)){
    img1.ctx.putImageData(imgData1,0,0);
    log("ONe")
    ctx.drawImage(img1,128,0);
}
img.ctx.fillStyle = "#DA3";  // make is look better for the sell ;)
img.ctx.fillText("LOGO!",64,64);  
var imgData = img.ctx.getImageData(0,0,128,128);
var img1 = createImage(128,128);
var imgData1 = img1.ctx.getImageData(0,0,128,128);
if(embose(imgData,imgData1,"2 pixel",false, true, true)){
    img1.ctx.putImageData(imgData1,0,0);
    ctx.drawImage(img1,0,128);
}

var img1 = createImage(128,128);
var imgData1 = img1.ctx.getImageData(0,0,128,128);
if(embose(imgData,imgData1,"1 pixel",false, false, false)){
    img1.ctx.putImageData(imgData1,0,0);
    ctx.drawImage(img1,128,128);
}
    
.canC {
    width:256px;
    height:256px;
}
<canvas class="canC" id="canV" width=256 height=256></canvas>