代码之家  ›  专栏  ›  技术社区  ›  Greg K

用HTML画布创建反射图像?

  •  4
  • Greg K  · 技术社区  · 16 年前

    我有下面的代码,它尝试将垂直镜像图像与透明到背景色的渐变相结合。当组合这两个效果失败时,是否需要在画布上覆盖PNG渐变而不是尝试让画布执行这两个操作?

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
        <style type="text/css">
            body {
                background-color: #eee;
                text-align: center;
                padding-top: 150px;
            }
        </style>
        <script type="text/javascript">
            var img = new Image();
            img.onload = function() {             
                var ctx = document.getElementById("output").getContext("2d");
                // reflect image
                ctx.translate(0, 75);
                ctx.scale(1, -1);
                ctx.drawImage(img, 0, 0, 75, 75);
    
                // add gradient
                var grad = ctx.createLinearGradient(0, 0, 0, 20);
                grad.addColorStop(0, 'transparent');
                grad.addColorStop(1, '#eeeeee');
    
                ctx.fillStyle = grad;
                ctx.fillRect(0, 0, 75, 20);
            };
    
            img.src = "test.jpg";
        </script>
    </head>
    <body>
        <div><img src="test.jpg" height="75" width="75" /></div>
        <canvas id="output" width="75" height="20"></canvas>
    </body>
    </html>
    
    4 回复  |  直到 9 年前
        1
  •  3
  •   Mike Mytkowski    16 年前

    不需要2个画布元素。下面的代码可以工作。在Linux上的Firefox 3.0上测试了它。

    我改变了画布的大小,以便在测试时更好地看到它,我制作了画布200 x 100像素。您需要根据需要调整大小(75x20)。为了测试的目的,我做了100x100像素的覆盖,这样我可以看到一半的图像有一个梯度。

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
    <style type="text/css">
        body {
                background-color: #eee;
                text-align: center;
                padding-top: 150px;
        }
    </style>
    <script type="text/javascript">
        var img = new Image();
        img.onload = function() {
                var ctx = document.getElementById("output").getContext("2d");
                // reflect image
                ctx.translate(0, 100);
                ctx.scale(1, -1);
                ctx.drawImage(img, 0, 0, 200, 100);
    
                // add gradient
                var grad = ctx.createLinearGradient(0, 0, 0, 100);
                grad.addColorStop(0.3, 'rgb(255,255,255)');
                grad.addColorStop(0.7, 'rgba(255,255,255,0)');
    
                ctx.fillStyle = grad;
                ctx.translate(0,0);
                ctx.rect(0, 0, 100, 100);
                ctx.fill();
        };
    
        img.src = "img/avatarW3.png";
    </script>
    

    <canvas id="output" width="200" height="100" style="border:1px solid black;"></canvas>
    

    编辑以解释其中一些:

    我认为你基本上忽略了梯度上的alpha属性。

    grad.addColorStop(0.7, 'rgba(255,255,255,0)');
    

    第四个参数是alpha。此外,由于将画布上下颠倒,渐变当前是上下颠倒绘制的(因此第二个颜色停止点具有透明度,而块在顶部是透明的)。

    如果你想正确地做事,你需要:

    ctx.save();
    ctx.translate(0, 100);
    ctx.scale(1, -1);
    ctx.drawImage(img, 0, 0, 200, 100);
    ctx.restore();
    

    现在可以根据需要绘制透明渐变块。

    另外,对于我来说,ctx.fillrect()命令不起作用。我必须使用ctx.rect()和ctx.fill()。

    希望这有帮助。

        2
  •  2
  •   GitaarLAB    11 年前
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
    <style type="text/css">
        body {
                background-color: #FFF;
                text-align: center;
                padding-top: 100px;
        }
    </style>
    <script type="text/javascript">
        var img = new Image();
        img.onload = function() {
            var c = document.getElementById("output");
            var ctx = c.getContext("2d");
    
            /* Maximum Canvas/Image Size
               i.e supposing image size 640x480 or greater than 399px
            */
            var max = 400;
    
            /* Resizing Image/Drawing */
            var r = img.width/img.height;
            if(r>1)
                ctx.drawImage(img , 0 , 0 , r*max , max);
            else
                ctx.drawImage(img , 0 , 0 , max   , max/r);
            ctx.save(); 
    
            /* Clearing extra spaces */
            ctx.clearRect(0, max, c.width  , c.height);
    
            /* Creating reflection */
            ctx.translate(0, max);
            ctx.scale(1, -1);
            if(r>1)
                ctx.drawImage(img , 0 , -max , r*max , max);
            else
                ctx.drawImage(img , 0 , max/2 , max , max/2 , 0 , -max/2 , max , max/2);
            ctx.restore();
    
            /* Adding gradiant */
            ctx.globalCompositeOperation = 'destination-out';
            var grad = ctx.createLinearGradient(0, Math.floor(c.height-(max/2)) , 0, c.height);
            grad.addColorStop(1, 'rgba(255,255,255,1.0)');
            grad.addColorStop(0, 'rgba(255,255,255,0.8)');
            ctx.fillStyle = grad;
            ctx.fillRect(0, Math.floor(c.height-(max/2)) , max, (max/2));
        };
    
        img.src = "a.jpg";
    </script>
    
    </head>
    <body>
    <canvas id="output" width="400" height="600" ></canvas>
    </body>
    </html>
    
        3
  •  1
  •   jerry    9 年前

    创建反射时不需要重新绘制整个图像。原始反射只显示图像的底部。 这样,您就可以重新绘制图像的较小部分,从而提供更好的性能,而且不需要创建线性渐变来隐藏图像的较低部分(因为您从未绘制过)。

    您可以使用“反射高度”和“不透明度”来播放以获得所需的结果。

    var thumbWidth = 250;
    var REFLECTION_HEIGHT = 50;
    var c = document.getElementById("output");
    var ctx = c.getContext("2d");
    var x = 1;
    var y = 1;
    
    //draw the original image
    ctx.drawImage(img, x, y, thumbWidth, thumbWidth);
    ctx.save();
    //translate to a point from where we want to redraw the new image
    ctx.translate(0, y + thumbWidth + REFLECTION_HEIGHT + 10);
    ctx.scale(1, -1);
    ctx.globalAlpha = 0.25;
    
    //redraw only bottom part of the image
    //g.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
    ctx.drawImage(img, 0, img.height - REFLECTION_HEIGHT, img.width, REFLECTION_HEIGHT, x, y, thumbWidth, REFLECTION_HEIGHT);
    

    这里有一个链接指向 fiddle

        4
  •  0
  •   Greg K    16 年前

    使用第二个画布并不能提供非常令人信服的渐变叠加。为了获得良好的效果,可能需要使用渐变png。

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
        <style type="text/css">
            body {
                background-color: #eee;
                padding-top: 150px;
            }
    
            canvas {
                float: left;
            }
    
            canvas#grad {
                margin-left: -75px;
            }
        </style>
        <script type="text/javascript">
            var img = new Image();
            img.src = "test.jpg";
    
            img.onload = function() {
                var reflect = document.getElementById("reflect").getContext("2d");
                // reflect image
                reflect.translate(0, 75);
                reflect.scale(1, -1);
                reflect.drawImage(img, 0, 0, 75, 75);
    
                // add gradient
                var overlay = document.getElementById("grad").getContext("2d");
                var grad = overlay.createLinearGradient(0, 0, 0, 15);
                grad.addColorStop(0, 'transparent');
                grad.addColorStop(1, '#eeeeee');
    
                overlay.fillStyle = grad;
                overlay.fillRect(0, 0, 75, 15);
            };
        </script>
    </head>
    <body>
        <div>
            <div><img src="test.jpg" height="75" width="75" /></div>
            <canvas id="reflect" width="75" height="15"></canvas>
            <canvas id="grad" width="75" height="15"></canvas>
        </div>
    </body>
    </html>
    
    推荐文章