I'm building a website and I need a user to be able to select an image (a transparent gif with black sign on it) and select a color. I have all the gifs in black with transparent background.
How can I change the color of the gif (the black only) to the color the user chose? I was thinking about using a canvas for this but I'm not sure...
You can use a canvas for this. There is no need to iterate the pixel buffer as many suggests and I would recommend avoiding if possible for two reasons:
CORS restriction may apply if image is loaded from a different origin
Performance
There is a much easier way involving composite modes:
Live demo
/// load image here, then:
function render() {
/// this composite mode clears the canvas as well
ctx.globalCompositeOperation = 'copy';
ctx.drawImage(img, 0, 0);
/// this mode fills in whatever, in the image
ctx.globalCompositeOperation = 'source-in';
/// color to change GIF to:
ctx.fillStyle = '#00c';
/// fill color into non-alpha pixels
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
The copy mode works here as the image is the only thing we want to draw to the canvas. If you need to draw in other details as well then use source-over instead and manually clear the canvas using clearRect().
Tip: You can also draw another image on top instead of a fill color.
Original GIF
Changed to blue color
ctx.fillStyle = '#00c';
Changed to red color
ctx.fillStyle = '#c00';
etc.
Assuming that you want to change the color of the black parts of the image (not the transparent parts) you'll have to use canvas to get the black pixels of the image and draw a new image replacing these pixels with the color your user has chosen.
If you want to replace the transparent parts, simply setting a background color using CSS will do the trick.
Related
I have a canvas <canvas></canvas> that displays a graphic of an unclean window. I need to be able to 'clean' the window with my cursor, displaying another image behind it. Just as this website uses their brushes: http://mudcu.be/sketchpad/ but rather than adding to the page, I need to remove content to display the image behind it.
Here's an example of the before and after 'rubbing out':
http://www.titaniumwebdesigns.com/images/forums/before.png http://www.titaniumwebdesigns.com/images/forums/after.png
See this complete DEMO
globalCompositeOperation is one of the most nice features in canvas api.
To achieve the desired effect, I use multiple canvas layers and globalCompositeOperation.
In this solution we have 3 layers:
Layer 1 - bottom Layer 2 - middle
Layer 3 - top
Middle and Top layers are static and only the middle layer is dynamically cleared using globalCompositeOperation.
middleCtx.globalCompositeOperation = "xor";
With globalCompositeOperation = "xor", the brush is drawn over the layer and clears the portion of canvas where it was drawn.
The final result is:
UPDATE:
To verify if the window is fully cleaned I create a hidden canvas with the same size of the others layers and drawn a black rectangle on it. When dragging the mouse over the canvas the layer 2 (middle) is cleared with a circle with transparent gradient color and now we also draw over the hidden canvas a circle with white color (might be any color different of black).
So on, we just verify the pixels of the hidden canvas and if there is no black pixels, the window is cleaned.
To get the image data we need to use something like:
imageData = context.getImageData(x, y, width, height)
and then get the pixels from the image data:
pixels = imageData.data;
The requestAnimationFrame routine is used for performance reason, because getImageData might be slow. The major change in the code is put the brush action inside an animation frame when dragging the mouse instead of do that action in each mouse move event. This allows the processor to have more time to do the pixel data verification.
Here is the modified fiddle with pixel data verification and an alert when the window is cleaned:
jsFiddle link
If you have a canvas where you have drawn a blurred image into it once, you should be able to create that effect by creating a "brush" image (an image containing a semi-transparent circle, with soft edges), and then draw that image in the canvas at the mouse coordinate using:
canvasContext.globalCompositeOperation = "destination-out";
https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
As soon as you have drawn the blurred image to the canvas, you just need to call the line above once and all drawn images after will use the specified composite operation.
I would like to export my canvas onto a PDF and only render the elements added to the canvas. For example:
I have this canvas, with a background-image set to it.
http://i49.tinypic.com/n7lv.png
This is my result when I render it to PDF (using Bytescout library)
http://i50.tinypic.com/346ud7m.png
This is how I want it to end up as:
http://i50.tinypic.com/2q1s9hv.png
Meaning, I want it to end up with no rounded corners, without the background image. The canvas is done using the fabric framework. My idea is to get all the elements added to the canvas, except background image, then render the PDF from there. Any guidelines? Is that the way to go?
You simply redraw the entire scene, omitting the parts you don't want to write to a PDF.
If you don't feel like keeping track of everything to redraw, then create a second, in-memory canvas (document.createElement('canvas')) and do every drawing operation to that canvas instead of your normal one, then draw that canvas onto your normal one as the user edits instead of drawing directly onto your normal canvas.
The old way:
// First you round the corners permanently by making a clipping region:
ctx.roundedRect(etc)
ctx.clip();
//then a user draws something onto normal canvas, like an image
ctx.drawImage(myImage, 0, 0);
The new way:
// make a hidden canvas:
var hiddenCanvas = document.createElement('canvas');
var hCtx = hiddenCanvas.getContext('2d');
// First you round the corners permanently by making a clipping region:
ctx.roundedRect(etc)
ctx.clip();
//then a user draws something onto HIDDEN canvas, like an image
// This image never gets its corners cut
hCtx.drawImage(myImage, 0, 0);
// Then you draw the hidden canvas onto your normal one:
ctx.drawImage(hiddenCanvas, 0, 0);
When its time to print, you use your hidden canvas, which does not have a background image and does not have clipped corners.
I am trying to draw a sharp thin rectangle using canvas control.I want the canvas background to get loaded with an image and in foreground with some text .
Though i am able to set the color and text they are somehow appearing blurred.Is there a way to fix this issue ?
And i want to apply an image as background image for each canvas rectangle i will draw.These rectangels will appear a in a div control.So wherever there is a canvas rectangle i want its background image to be filled with the image i choose.entire div will not be filled with canvas rectangles but only half of it.Is there a way whether we can have one image for all the canvas rectangles i will draw or do ineed to draw it for every rectangle ?
html:
<div id="divBoard" >
<canvas id="canvasBoard" />
</div>
javascript:
canvas = document.getElementById("canvasBoard");
if (canvas.getContext) {
var context = canvas.getContext("2d");
}
context.fillStyle = "green";
context.fillRect(x, y, width,height);
context.font = "5px tahoma";
context.fillStyle = "black";
context.fillText("cell"+i, x, y + width);
this is the image displayed after executing my code
I have experienced the same issue with fonts not rendering as sharply on a canvas. In my project I did a workaround by placing the font in a separate DIV and overlaying it on the canvas using an appropriate z-index. This approach worked very well for me.
Have you tried adding 0.5 to x and y? The html5 canvas uses antialiasing so if you want "crisp" lines, you need to draw "in between" the pixels.
You will find a good explanation on how this works in mozilla developer reference page for lineWidth
PS. also see this question
Is there a way to use an image as a clipping mask instead of creating a shape like this:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
// Clip a rectangular area
ctx.rect(50,20,200,120);
ctx.stroke();
ctx.clip();
I have tried to context.drawImage('myimg.png') on top of the context and clip but that did not work.
You can only directly clip using a path.
If you have an image that you wish to clip by, you can probably achieve this by drawing your content in another canvas, and then using globalCompositeOperation combined with drawImage (with the mask) to remove the bits you don't want.
You would then then use .drawImage again (possibly with a different globalCompositeOperation) to merge that clipped image with your original content.
See for example http://www.html5canvastutorials.com/advanced/html5-canvas-global-composite-operations-tutorial/
I am writing a colouring game for small children, where I have a black and white image shown on a canvas initially, and as the user moves the drawing tool (mouse) over the canvas, the black and white surface gets over-painted with the colour information from the corresponding coloured image.
In particular, on every mouse move I need to copy a circular area from the coloured image to my canvas. The edge of the circle should be a little blurry to better immitate the qualities of a real drawing tool.
The question is how to accomplish this?
One way I see is to use a clipping region, but this approach does not let me have blurry edges. Or does it?
So I was thinking about using an alpha mask to do that and copy only pixels that correspond to the pixels in the mask that have non zero alpha. Is it feasible?
My suggestion is to have your drawable canvas in front of the coloured image you wish to reveal. (You could use your coloured image as a CSS background image for the canvas.)
Initially have the canvas containing the black and white image with 100% opacity. Then, when you draw, actually erase the contents of the canvas to show the image behind.
Like this:
var pos_x, pos_y, circle_radius; // initialise these appropriately
context.globalCompositeOperation = 'destination-out';
context.fillStyle = "rgba(0,0,0, 1.0)";
// And "draw" a circle (actually erase it to reveal the background image)
context.beginPath();
context.arc(pos_x, pos_y, circle_radius, 0, Math.PI*2);
context.fill();
I would probably use multiple clipping regions with varying alpha (one dab for each) to mimic the effect you are after. Render the low opacity one first (paste using drawImage) and render the rest after that till you reach alpha=1.0.
Have you considered using radial gradients that go from an opaque color to a fully transparent one?
Here is a demo from Mozilla. The circles are drawn the way you need. - https://developer.mozilla.org/samples/canvas-tutorial/4_10_canvas_radialgradient.html