I have the following code which tries to combine a vertical mirrored image with a transparent to background color gradient. When combining these two effects it fails, do I n
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.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>
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() command did not work. I had to use ctx.rect() and ctx.fill().
Hope this helps.
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.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>
<!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>