admin管理员组

文章数量:1289986

I have the following code which tries to bine a vertical mirrored image with a transparent to background color gradient. When bining these two effects it fails, do I need to overlay a PNG gradient over the canvas instead of trying to get the canvas to perform both operations?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    ".dtd">
<html xmlns="">
<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>

I have the following code which tries to bine a vertical mirrored image with a transparent to background color gradient. When bining these two effects it fails, do I need to overlay a PNG gradient over the canvas instead of trying to get the canvas to perform both operations?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3/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>
Share Improve this question asked Nov 7, 2009 at 15:07 Greg KGreg K 11.1k11 gold badges46 silver badges62 bronze badges 2
  • I tested this with 'black' and 'white' color stops before trying transparent. I can apply just the gradient, or just the reflected image but not both. – Greg K Commented Nov 7, 2009 at 15:08
  • If the canvas is supported in your browser, chances are that some CSS3 will be supported too ... you can create reflections (iTunes style) with CSS3 only - no need for JavaScript. s3.amazonaws./nettuts/704_cssReflections/index.html – Greg Commented Jun 3, 2011 at 8:03
Add a ment  | 

4 Answers 4

Reset to default 3

There is no need for 2 canvas elements. The code below works.Tested it on FireFox 3.0 on Linux.

I have changed the canvas sizes so I could see it better while testing, I made the canvas 200 x 100 pixels. You will need to resize back to your needs (75x20). For testing purposes, I've made the overlay 100x100 pixels so I could see half the image with a gradient.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3/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>

Edit to explain some of this:

I think you were basically missing the alpha attribute on the gradient.

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

The fourth parameter is alpha. Also, since you flip the canvas upside down, the gradient is currently drawn upside down (hence the second color stop has the transparency on it, and yet the block is transparent on the top side).

If you wanted to do things correctly, you would need to:

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

And now you can draw your transparent gradient block as you need it.

Also, for me the ctx.fillRect() mand did not work. I had to use ctx.rect() and ctx.fill().

Hope this helps.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3/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>

You don't need to redraw the entire image when creating a reflection. An original reflection simply shows the bottom part of the image. This way you are redrawing a smaller part of the image which provides better performance and also you don't need to create linear gradient to hide the lower part of the image (since you never draw it).

You can play around with REFLECTION_HEIGHT and opacity to get desired results.

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

Here is a link to the fiddle

Using a second canvas doesn't provide a very convincing gradient overlay. May have to go with a gradient PNG for decent results.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3/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>

本文标签: javascriptCreate reflected image with HTML CanvasStack Overflow