Fill image with a repeatable texture - javascript

Would it be possible to fill a png with transparency with a pattern (a repeatable texture)?
Here's a quick example of loading an image onto the canvas, just not sure how to fill it with a pattern, if that isn't possible then would there be a way to extract a path from the png?
<script>
var c = document.getElementById("a");
var ctx = c.getContext("2d");
var test= new Image();
test.src = "images/test.png";
test.onload = function() {
ctx.drawImage(test, 0, 0);
};
</script>
<body>
<canvas id="a"></canvas>
</body>
I've also created a jsfiddle with an actual loaded png
This is the effect I'm looking to achieve
Update
working example based on Simon Sarris' answer
http://jsfiddle.net/sergeh/G8egW/6/

First, draw the image to Canvas.
Then do globalCompositeOperation = 'source-in';
Then draw the pattern. It will only exist where the image was.
http://jsfiddle.net/G8egW/2/
If you had stuff already on the canvas before this time, you'll need to do the above operations on an in-memory canvas and then draw that canvas to your normal canvas. Like this:
http://jsfiddle.net/G8egW/5/
(notice the difference in the grid)

Related

drawing on top of the image using paperjs

I'm using Paper.js to draw lines on canvas.
I want to be able to upload local image to the paperjs canvas and then be able to draw on top of it.
What I did is:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
function make_base()
{
var img = document.createElement("img");
img.src = "http://paperjs.org/tutorials/images/working-with-rasters/mona.jpg";
context.drawImage(img, 100, 100);
}
document.getElementById('imageUpload').addEventListener('click', function(){
make_base();
});
This successfully adds an image to my canvas, but when I draw on canvas, image disappears and the image is on top of the lines, should be behind them.
You can add the image to the paper project as a paperjs Raster item, as such
var raster = new Raster({
source: "http://paperjs.org/tutorials/images/working-with-rasters/mona.jpg",
position: view.center
});
It will be inserted into the project in the current layer. You can then use paperjs functions like sendToBack and bringToFront to manipulate what appears where. I would probably put the raster image on the first Layer then add a new Layer for the drawing to make it easy to keep track of.
If you don't need to change or working with the image, use background-image on canvas tag:
<canvas id="canvas"
style="background-image: url(http://paperjs.org/tutorials/images/working-with-rasters/mona.jpg);"></canvas>

putImageData(), how to keep old pixels if new pixels are transparent?

In html5, when you draw to a canvas using putImageData(), if some of the pixels you are drawing are transparent (or semi-transparent), how do you keep old pixels in the canvas unaffected?
example:
var imgData = context.createImageData(30,30);
for(var i=0; i<imgData.data.length; i+=4)
{
imgData.data[i]=255;
imgData.data[i+1]=0;
imgData.data[i+2]=0;
imgData.data[i+3]=255;
if((i/4)%30 > 15)imgData.data[i+3] = 0;
}
context.putImageData(imgData,0,0);
The right half of the 30x30 rect is transparent.
If this is drawn over something on the canvas, pixels behind the right half are removed (or become thransparent). How do I keep them?
You can use getImageData to create a semi-transparent overlay:
create a temporary offscreen canvas
getImageData to get the pixel data from the offscreen canvas
modify the pixels as you desire
putImageData the pixels back on the offscreen canvas
use drawImage to draw the offscreen canvas to the onscreen canvas
Here's example code and a Demo: http://jsfiddle.net/m1erickson/CM7uY/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
// draw an image on the canvas
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stack1/landscape1.jpg";
function start(){
canvas.width=img.width;
canvas.height=img.height;
context.drawImage(img,0,0);
// overlay a red gradient
drawSemiTransparentOverlay(canvas.width/2,canvas.height)
}
function drawSemiTransparentOverlay(w,h){
// create a temporary canvas to hold the gradient overlay
var canvas2=document.createElement("canvas");
canvas2.width=w;
canvas2.height=h
var ctx2=canvas2.getContext("2d");
// make gradient using ImageData
var imgData = ctx2.getImageData(0,0,w,h);
var data=imgData.data;
for(var y=0; y<h; y++) {
for(var x=0; x<w; x++) {
var n=((w*y)+x)*4;
data[n]=255;
data[n+1]=0;
data[n+2]=0;
data[n+3]=255;
if(x>w/2){
data[n+3]=255*(1-((x-w/2)/(w/2)));
}
}
}
// put the modified pixels on the temporary canvas
ctx2.putImageData(imgData,0,0);
// draw the temporary gradient canvas on the visible canvas
context.drawImage(canvas2,0,0);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=200 height=200></canvas>
</body>
</html>
Alternatively, you might check out using a linear gradient to do your effect more directly.
http://jsfiddle.net/m1erickson/j6wLR/
Problem
As you know, your statement
if((i/4)%30 > 15)imgData.data[i+3] = 0;
will make pixels on the right half of the image be transparent, so that any other object on the page behind the canvas can be seen through the canvas at that pixel position. However, you are still overwriting the pixel of the canvas itself with context.putImageData, which replaces all of its previous pixels. The transparency that you add will not cause the previous pixels of to show through, because the result of putImageData is not a second set of pixels on top of the previous pixels in the canvas, but rather the replacement of existing pixels.
Solution
I suggest that you begin your code not with createImageData which will begin with a blank set of data, but rather with getImageData which will give you a copy of the existing data to work with. You can then use your conditional statement to avoid overwriting the portion of the image that you wish to preserve. This will also make your function more efficient.
var imgData = context.getImageData(30,30);
for(var i=0; i<imgData.data.length; i+=4)
{
if((i/4)%30 > 15) continue;
imgData.data[i]=255;
imgData.data[i+1]=0;
imgData.data[i+2]=0;
imgData.data[i+3]=255;
}
context.putImageData(imgData,0,0);
Something that tripped me up that may be of use... I had problems with this because I assumed that putImageData() and drawImage() would work in the same way but it seems they don't. putImageData() will overwrite existing pixels with its own transparent data while drawImage() will leave them untouched.
When looking into this I just glanced at the docs for CanvasRenderingContext2D.globalCompositeOperation (should have read more closely), saw that source-over is the default and didn't realise this would not apply to putImageData()
Drawing into a temporary canvas then and using drawImage() to add the temp canvas to the main context was the solution I needed so cheers for that.
I wanted to copy a CRISP, un modified version of the canvas on top of itself. I eventually came up with this solution, which applies.
https://jsfiddle.net/4Le454ak/1/
The copy portion is in this code:
var imageData = canvas.toDataURL(0, 0, w, h);
var tmp = document.createElement('img');
tmp.style.display = 'none'
tmp.src = imageData;
document.body.appendChild(tmp);
ctx.drawImage(tmp, 30, 30);
What's happening:
copy image data from canvas
set image data to a non-displayed <img> (<img> has to be in dom though)
draw that image back onto the canvas
you can delete or reuse the <img> at this point
It is an old question, but I had a similar issue and came up with another solution that fits me better (similar to #popClingwrap's answer, but I'll elaborate a bit more). I have a WebWorker and I want it to copy and paste an svg file multiple times in an existing canvas. If the source of your ImageData is another Canvas, and you want to copy the data to another canvas, there is an easier way than manipulating pixel values in a loop. the ctx.drawImage() function does overlay images respecting transparency and can also take another canvas as source.
So I used Canvg to create a source canvas containing my source image ( For your application this will look different)
const cnv = new OffscreenCanvas(100, 100);
const loadCanvas = async () => {
const v = await Canvg.from(cnv.getContext("2d"), src, preset);
await v.render();
};
For your example this would probably look something like this
var cnv = document.createElement('canvas');
var ctx = cnv.getContext('2d');
cnv.width = 30;
cnv.height = 30;
ctx.putImageData(imgData, 0, 0);
And then you can draw this transparent image on top of an existing image as often as needed with:
ctx.drawImage(cnv, 0, 0);

How overlay image over a cup using html5 canvas

I am new to HTML5 canvas. I have a image of a cup, I am rendered that in canvas.
This is image of cup :
Now I am trying render another image (My photo that is in normal rectangular size) in upload your design area of this image. How can I render this image which looks like that image on cup?
I want to get the final image like this :
I am uses canvas element to upload the image.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:5px solid #c3c3c3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script src="js/test.js" type="text/javascript"></script>
</body>
</html>
JS
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
var x = 0;
var y = 0;
var width = 290;
var height = 297;
imageObj.onload = function() {
context.drawImage(imageObj, x, y);
};
imageObj.src = 'images/cup.jpg';
You want your second image to "warp" and appear as if it's wrapped around the cup.
You cannot warp your second image into a curved image using "out-of-the-box" context 2d
Using html Canvas 2d Context, you can only do quadrilateral skewing. Therefore, after skewing an image each opposing side will always be parallel.
Therefore, you cannot get your image to warp into a curved image using "out-of-the-box" context 2d.
A few workarounds...You can use an offscreen temporary canvas to "warp" your second image into a curve. Then you can draw that curved image on top of the cup image using context.drawImage. Here are 2 alternatives that let you "fake" curvature of an image.
Alternative #1: Texture Mapping
You can use texture mapping to apply perspective curvature to your second image:
http://archive.gamedev.net/archive/reference/articles/article852.html
Alternative #2: Vertically slice and stretch
You can vertically slice your second image to create perspective curvature. You can use the resizing capability of context.drawImage to "stretch" pixels into your curved shape like in this previously Stackoverflow answer: How to make rooftext effect and valley text effect in HTML5 (or Fabric.js)
jsfiddle.net/AbdiasSoftware/e8hZy/

Add image to canvas using paper JS

I used normal javascript to add image to canvas and this is the code
var canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
canvas_image();
function canvas_image(){
can_img = new Image();
can_img.src = 'Chrysanthemum.jpg';
can_img.onload = function(){
context.drawImage(can_img, 100, 100);
}
}
How can i add image to canvas using paperJS library?
Quoting from the paperjs.org tutorial on rasters:
Images need to already be loaded when they are added to a Paper.js project. Working with local images or images hosted on other websites may throw security exceptions on certain browsers.
So you need an image somewhere that is preferably visually hidden:
<img id="mona" class="visuallyhidden" src="mona.jpg" width="320" height="491">
And the PaperScript code could look like this:
// Create a raster item using the image tag with id="mona"
var raster = new Raster('mona');
Then you can reposition, scale or rotate like so:
// Move the raster to the center of the view
raster.position = view.center;
// Scale the raster by 50%
raster.scale(0.5);
// Rotate the raster by 45 degrees:
raster.rotate(45);
And here is a paperjs.org sketch to play with.
First, If you want to work with JavaScript directly look at this tutorial.
Once you understand it, you would have something like this to load image in raster
paper.install(window);
window.onload = function() {
// Setup directly from canvas id:
paper.setup('myCanvas');
var raster = new paper.Raster({source: 'Chrysanthemum.jpg', position: view.center});
}

How do I draw an image loaded from the page in a canvas

I have a html page like this:
<html>
<body>
(1)<canvas id="cs"></canvas>
(2)<img src="/image.png" id="img"/>
</body>
</html>
I would like to know how I could load and display the image (2) in the canvas (1) (with drawImage function).
I tried this but it doesn't work :
var img = $("#img");
ctx.drawImage(img,0,0);
You have to ensure that your image has loaded first. Try wrapping your drawImage call in a ready statment and make certain you are setting up your canvas object first.
$().ready(function(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.drawImage(document.getElementById("img"),0,0);
})
If you haven't already found it here is a nice tutorial: https://developer.mozilla.org/en/Canvas_tutorial/Using_images
Is that all of your code?
You need to set up the canvas first:
var ctx = document.getElementById('cs').getContext('2d');
var img = new Image();
img.src=document.getElementById('img').src;
ctx.drawImage(img,0,0);
Something like that...
Here's an example in jsfiddle: http://jsfiddle.net/vTYqS/
Note that the first picture gets cut off because of the default canvas size. Depending on the image you plan to copy, you may need to resize your canvas like this:
http://jsfiddle.net/vTYqS/1/

Categories

Resources