Canvas - Apply Global Composition on Multiple Images inside One Canvas - javascript

I am working on a task to apply a pattern to multiple parts of shirt. Shirt image cannot be a single image. It is making with small images like left arm, right arm, collar etc...
Now I want to apply a pattern or color to all the parts inside the canvas.
<canvas id="canvas" width=250 height=250 style="margin-left: 100px; background: pink"></canvas>
<script type="text/javascript">
var img1 = new Image, img2 = new Image, cnt = 2, img3 = new Image,
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
// image loading for demo (ignore)
img1.onload = img2.onload = function() {if (!--cnt) go()};
// Left Arm
img1.src = "left_arm.png";
//Right Arm
img3.src = "right_arm.png";
// Pattern Image
img2.src = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQlncafGCzVapWvTID6msFfk7OWtQSCEEnbKSLQhzVk1cPqe9CQ"; //
function go() {
// create a pattern
ctx.fillStyle = ctx.createPattern(img2, "repeat");
// // fill canvas with pattern
ctx.fillRect(0, 0, canvas.width, canvas.height);
// // use blending mode multiply
ctx.globalCompositeOperation = "multiply";
// // draw sofa on top
ctx.drawImage(img1, 0, 0, img1.width*.5, img1.height*.5);
ctx.drawImage(img1, 0, 0, img1.width*.5, img1.height*.5);
}
</script>

Related

How to have multiple globalCompositeOperation

My canvas is 512x256 pixels
Here is what I am trying to achieve :
Print a local image (image 1) on the canvas.
Fill this image with a specific color.
Print another local image(image 2) that should not overlap image 1.
So what I did is :
.drawImage(image1)
Create a rectangle of 512x256 ( ctx.rect(0, 0, 512, 256); )
ctx.globalCompositeOperation = "destination-in";
draw this rectangle ( ctx.fill() ) (with destination-in it should have for effect to fill the first image with the color of the rectangle)
ctx.globalCompositeOperation = "destination-out";
.drawImage(image2) (with destination-out it should make this image under the image 1)
But it doesn't display anything.
I figured it was because we can't have different globalCompositeOperation... But I'm sure it's possible somehow, I found people talking about it and fixing the issue but they're using specific code for their specific task and I simply don't understand. I would love an example for my script :
<script>
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var img1 = new Image();
img1.onload = function () {
ctx.drawImage(img1, 0, 0);
};
ctx.globalCompositeOperation = "destination-in";
ctx.rect(0, 0, 512, 256);
ctx.fillStyle = "green";
ctx.fill()
ctx.globalCompositeOperation = "destination-out";
img2.onload = function () {
ctx.drawImage(img2, 0, 0);
};
img1.src = "C:/Users/... file1.png" // replaced the path for this example
img2.src = "C:/Users/... file2.png";
</script>
And here is my html body :
<body>
<canvas id="canvas" width="512" height="256"></canvas>
</body>

Change color Image in Canvas

I want to change color a Image in canvas
this is the Image
You can see there is a Image transparent I was try using PutImgData but my transparent is changing color
Is there anyway to change color the car and money only ?
I was using this code :
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
image = document.getElementById("testImage");
canvas.height = canvas.width = 100;
ctx.fillStyle = 'red';
ctx.fillRect(10,10,20,10);
ctx.drawImage(image,0,0);
var imgd = ctx.getImageData(0, 0, 45, 45),
pix = imgd.data;
for (var i = 0, n = pix.length; i <n; i += 4) {
if(pix[i+3]==0)
{continue;}
pix.length[i]=r|pix.length[i];
pix.length[i+1]=g|pix.length[i+1];
pix.length[i+2]=b|pix.length[i+2];
pix[i + 3] = 255;
}
ctx.putImageData(imgd, 0, 0);
To mix manually you would have to apply a different formula to mix foreground (new color) and background (image) to preserve anti-aliased pixels (and just in case: the image included in the question is not actually transparent, but I guess you just tried to illustrate transparency using the solid checkerboard background?).
I would suggest a different approach which is CORS safe and much faster (and simpler) -
There are a couple of ways to do this: one is to draw in the color you want, then set composite mode to destination-in and then draw the image, or draw the image, set composite mode to source-in and then draw the color.
Example using the first approach coloring the following image blue:
var img = new Image; img.onload = draw; img.src = "//i.stack.imgur.com/cZ0gC.png";
var ctx = c.getContext("2d");
function draw() {
// draw color
ctx.fillStyle = "#09f";
ctx.fillRect(0, 0, c.width, c.height);
// set composite mode
ctx.globalCompositeOperation = "destination-in";
// draw image
ctx.drawImage(this, 0, 0);
}
<canvas id=c></canvas>
Example using second approach:
var img = new Image; img.onload = draw; img.src = "//i.stack.imgur.com/cZ0gC.png";
var ctx = c.getContext("2d");
function draw() {
// draw image
ctx.drawImage(this, 0, 0);
// set composite mode
ctx.globalCompositeOperation = "source-in";
// draw color
ctx.fillStyle = "#09f";
ctx.fillRect(0, 0, c.width, c.height);
}
<canvas id=c></canvas>
To reset comp. mode back to normal use:
// reset comp. mode
ctx.globalCompositeOperation = "source-over";
As with getImageData(), the drawback with this technique is that your canvas must only hold the content of this image while doing this process. A workaround if the image needs to be colored and mixed with other content is to use an off-screen canvas to do the processing, then draw that canvas back onto the main canvas.

Gradient map as opacity in a HTML5 canvas element?

Is there a way to create an opacity map on a canvas element
I am trying to fade a generated image as shown below.
EXAMPLE:
I don't believe there is any way to directly draw an image with a gradiant mask, but you could pre-draw the image to a separate canvas, and use globalCompositeOperation to draw a masking linear gradient, then draw that canvas using drawImage to the main canvas.
Working Example:
var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');
// Draw some background colors.
ctx.fillStyle = "#FF6666";
ctx.fillRect(0, 0, 150, 200);
ctx.fillStyle = "#6666FF";
ctx.fillRect(150, 0, 150, 200);
// Load the image.
img = new Image();
img.onload = function() {
// Create a canvas in memory and draw the image to it.
var icvs = document.createElement('canvas');
icvs.width = img.width;
icvs.height = img.height;
var ictx = icvs.getContext('2d');
ictx.drawImage(img, 0, 0);
// For masking.
ictx.globalCompositeOperation = 'destination-out';
// Draw the masking gradient.
var gradient = ictx.createLinearGradient(0, 0, 0, icvs.height);
gradient.addColorStop(0, "transparent");
gradient.addColorStop(1, "white");
ictx.fillStyle = gradient;
ictx.fillRect(0, 0, icvs.width, icvs.height);
// Draw the separate canvas to the main canvas.
ctx.drawImage(icvs, 25, 25, 250, 150);
};
img.src = '//i.stack.imgur.com/dR8i9.jpg';
<canvas id="cvs" width="300" height="200"></canvas>

How to add a texture to a Konva.Image() object in Konvajs?

I have followed the answer in this post; fill image with texture pattern, and it is working perfectly.
Is there a way to do the same with KonvaJS?
AFAIK, KonvaJS does not yet support the compositing required to create your texture overlay. But a Konva.Image can take a native html5 canvas element as its image source, so just do your overlay on an html5 canvas element and then feed it to Konva: var textureImage = new Konva.Image({ image:myCanvasElement })
Example annotated code and a Demo:
About Microsoft: Requires Edge -- IE doesn't allow compositing
var stage;
// Attributions of code that applies textures using compositing:
// Indirectly from your SO Q&A: http://stackoverflow.com/questions/36097859/add-texture-to-image-object-in-konvajs
// Directly from this SO Q&A: http://stackoverflow.com/questions/28545747/fill-image-with-texture-pattern/28552076#28552076
// image loading for demo (ignore)
var img1 = new Image;
var img2 = new Image;
var cnt = 2;
img1.onload = img2.onload = function() {
if (!--cnt) go()
};
img1.src = "http://i.imgur.com/8WqH9v4.png"; // sofa
img2.src = "http://i.stack.imgur.com/sQlu8.png"; // pattern
//
function createCompositedCanvas(img1, img2) {
// create canvas
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
canvas.width = img1.width;
canvas.height = img1.height;
// create a pattern
ctx.fillStyle = ctx.createPattern(img2, "repeat");
// fill canvas with pattern
ctx.fillRect(0, 0, canvas.width, canvas.height);
// use blending mode multiply
ctx.globalCompositeOperation = "multiply";
// draw sofa on top
ctx.drawImage(img1, 0, 0, img1.width * .5, img1.height * .5);
// change composition mode (blending mode is automatically set to normal)
ctx.globalCompositeOperation = "destination-in";
// draw to cut-out sofa
ctx.drawImage(img1, 0, 0, img1.width * .5, img1.height * .5);
//
document.body.appendChild(canvas);
return (canvas);
}
// end attibuted code
function go() {
// create stage
stage = new Konva.Stage({
container: 'container',
width: img1.width,
height: img1.height
});
var layer = new Konva.Layer();
stage.add(layer);
// create composited canvas
var canvas = createCompositedCanvas(img1, img2);
// use the in-memory canvas as an image source for Konva.Image
var img = new Konva.Image({
x: -200,
y: -50,
image: canvas,
draggable: true
});
layer.add(img);
layer.draw();
}
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
canvas{border:solid 1px red;}
<script src="https://cdn.rawgit.com/konvajs/konva/0.9.0/konva.min.js"></script>
<div id="container"></div>
<h4>Native canvas element used to do compositing</h4>

How to apply canvas transformation on multiple images

I'm playing with canvas in HTML5 and Javascript and I have a problem:
I'd like to apply transformations used on the current image to multiple images.
What I did:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
//transformation stuff like:
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, -img.width / 2, -img.height / 2, img.width, img.height);
ctx.beginPath();
ctx.lineTo(42, 42);
ctx.stroke();
ctx.lineTo(42, 24);
ctx.stroke();
...
ctx.rotate(Math.PI / 2);
...
};
img.src = //base64Img;
So I will apply a lot of transformations like draw some lines, crop, zoomIn etc...
How can I apply this to multiple files (more than 200) once (when these transformations are done) ?
Obviously, it will be done in multiples functions like a function to rotate, to draw a line etc.
Thank you for your help.
Put your transformations, path drawings & image drawing into a function with arguments that tell the function how each image will be treated:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house32x32transparent.png";
function start(){
// Note: img coordinates are [centerX,centerY] rather than the usual [left,top]
drawTransformedImage(img,25,50,0,.75);
drawTransformedImage(img,75,50,Math.PI*1/6,1);
drawTransformedImage(img,150,50,Math.PI*2/6,2);
drawTransformedImage(img,225,50,Math.PI*3/6,1);
drawTransformedImage(img,275,50,Math.PI*4/6,.5);
}
function drawTransformedImage(img,cx,cy,radAngle,scale){
// save incoming styling
var lw=ctx.lineWidth;
var ss=ctx.strokeStyle;
// cache often used half-sizes
var iwHalf=img.width/2;
var ihHalf=img.height/2;
ctx.lineWidth=2;
// do the specified transformations
ctx.translate(cx,cy);
ctx.rotate(radAngle);
ctx.scale(scale,scale);
// draw the image
ctx.drawImage(img,-iwHalf,-ihHalf);
// stroke some paths
ctx.beginPath();
ctx.moveTo(-iwHalf,ihHalf);
ctx.lineTo(-iwHalf,-ihHalf);
ctx.strokeStyle='orange';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-iwHalf,-ihHalf);
ctx.lineTo(+iwHalf,-ihHalf);
ctx.strokeStyle='blue';
ctx.stroke();
// clean up: reset transformations and stylings
ctx.setTransform(1,0,0,1,0,0);
ctx.lineWidth=lw;
ctx.strokeStyle=ss;
}
body{ background-color: white; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=150></canvas>
Transforming an Image
Your example does not show a image being transformed, making your question unclear.
The transform is independent of the image, it is used to transform pixel coordinates drawn onto the canvas. It does not affect the image. You can set the transform and then draw the 200 images and they will all have the same transformation applied when their content is rendered to the canvas.
Code example
To transform the image you must create a canvas, set the transform, then render the image onto that canvas. The canvas is now the transformed image.
An example of transforming an image.
var mirrorImage = function (image, vertical, horizontal) {
var imageResult, ctx, vF, hF, posX, posY;
// create new canvas
imageResult = document.createElement("canvas");
// set the pixels size to match the image
imageResult.width = image.width;
imageResult.height = image.height;
// create a drawable surface
ctx = imageResult.getContext("2d");
// create the mirror transformation
hF = horizontal ? -1, 0;
vF = vertical ? -1 : 0;
posX = horizontal ? image.width, 0;
posY = vertical ? image.height : 0;
// Apply the transform to the new image
ctx.setTransform(hF, 0, 0, vF, posX, posY);
// transform the original image by drawing it onto the new
ctx.drawImage(image, 0, 0);
// return the new image.
return imageResult;
}
// create image
var img = new Image();
img.src = "ship.png";
// when loaded transform the image
img.onload = function () {
img = mirrorImage(img, true, true);
// the image has been transformed.
}
To do that to 200 images you have to call mirrorImage (or what ever you are doing) for each image.

Categories