How to save a Canvas with canvas to blob without black background? - javascript

I am trying to save a chart from charts.js but its save with a black background and donĀ“t know how to change that background to transparent or white.
I am using Canvas to blob and FileSaver
This is my script
$("#download").click(function() {
var canvas = document.getElementById("canvas");
canvas.toBlob(function(blob) {
saveAs(blob, "grafica.png");
});
});

If you don't want to mess with the chart's canvas itself, you can use an offscreen canvas and draw the background there.
const canvasWithBackground = document.createElement('canvas');
canvasWithBackground.width = canvas.width;
canvasWithBackground.height = canvas.height;
const ctx = canvasWithBackground.getContext('2d')!;
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(canvas, 0, 0);
canvasWithBackground.toBlob(function(blob) {
saveAs(blob, "grafica.png");
});

I'm not familiar with the library but have you tried actually giving it a white background? Something like the following? It might be using black a default when no color is encountered at a particular pixel.
$("#download").click(function() {
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
canvas.toBlob(function(blob) {
saveAs(blob, "grafica.png");
});
});

i just draw a white backgroung before draw the chart on the script and solve the black background problem :)
var backgroundColor = 'white';
Chart.plugins.register({
beforeDraw: function(c) {
var ctx = c.chart.ctx;
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, c.chart.width, c.chart.height);
}
});

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>

Render video with HTML Canvas in red and black&white colors

I need to render a video with HTML Canvas in red color. Code Below (if doesn't work, try here codepen code). This code add red layer, but I need in first place - desaturate, after reduce brightness and only then add red layer. I tried work with pixels (problems with perfomance), ctx.filter doesnt work either.
const URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
const video = document.createElement('video');
navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
}).then((stream) => {
video.src = URL.createObjectURL(stream);
});
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
const loop = () => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'rgba(255, 0, 0, .45)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(loop);
};
loop();
<canvas id="canvas" width="400" height="400"></canvas>
You can use multiply blending mode to knock out the other colors channels. Since you only define red the other channels with be multiplied with 0, leaving them "empty".
Just remember to reset composite mode to "source-over" before drawing the next video frame.
var img = new Image(); img.onload = draw; img.src = "//i.imgur.com/Kzz84cr.png";
function draw() {
c.width = this.width; c.height = this.height;
var ctx = c.getContext("2d");
// main loop
ctx.drawImage(this, 0, 0); // draw video frame
ctx.globalCompositeOperation = "multiply"; // change blending mode
ctx.fillStyle = "red"; // draw red on top
ctx.fillRect(0, 0, c.width, c.height);
ctx.globalCompositeOperation = "source-over"; // "reset"
// rinse, repeat
}
<canvas id=c></canvas>

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.

Canvas getImageData and putImageData load image partially

Here is my code. I am uploading a image and using like this :
> var canvas = document.createElement('canvas');
> var context = canvas.getContext('2d');
> context.drawImage(image, 0, 0);
This works fine but if I copy the imagedata like below to another canvas. It loads image partially.
var canvas = document.getElementById('myCanvas');
var context1 = canvas.getContext('2d');
context1.putImageData(context.getImageData(0, 0, image.width, image.height), 0, 0);
I tried same approach by creating two canvas and this code which worked fine but without image.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 300, 300);
var d = document.getElementById("myCanvas1");
var btx = d.getContext('2d');
var imgData = ctx.getImageData(0, 0, 300, 300);
btx.putImageData(imgData, 0, 0);
If i create two canvas it works fine but not like the above where I am using in memory canvas.
My HTML file has this :
<canvas id="myCanvas" width="960" height="960"></canvas>
<canvas id="myCanvas1" width="960" height="960"></canvas>
When you create canvases, you need to set their width manually. Default canvas size is 300x150. From here HTMLCanvasElement.
Something like this:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0);
To copy one canvas to another use drawImage rather than getImageData, setImageData That way you will use the GPU to move the pixels rather than the CPU. You also have the option to resize, crop, and apply a variety of FXs.
// create a copy of canvasSource
// returns the newly created canvas.
function copyCanvas(canvasSource){
var canvasCopy = document.createElement("canvas");
canvasCopy.width = canvasSource.width;
canvasCopy.height = canvasSource.height;
canvasCopy.getContext("2d").drawImage(canvasSource, 0, 0);
return canvasCopy;
}

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>

Categories