hi I want to rotate my PNG with this code below :
async function rotateImage(imageBase64, rotation) {
var img = new Image();
img.src = imageBase64;
return new Promise(resolve => {
img.onload = () => {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.fillStyle = "rgba(255,255,255,.6)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(rotation * (Math.PI / 180));
ctx.drawImage(img, -img.width / 2, -img.height / 2);
ctx.restore();
resolve(canvas.toDataURL("image/jpeg"))
};
})
this is my image before rotate :
before rotate
and this is my image after rotate:
after rotate
after rotate background corners of image is black how to transparent?
NOTE: I use this PNG for marker of google map.
I read this posts :
Canvas fillStyle none in HTML5
Transparency context.fill style in canvas html5
How to change the opacity (alpha, transparency) of an element in a canvas element after it has been drawn?
thanks for helping.
Related
I'm trying to merge webcam video and canvas drawing and save to an image file. It works but video image covers canvas draving. I tried to swap places context.drawImage but still same. Any ideas? :)
canvas.addEventListener("click", async function () {
var context = canvas.getContext("2d");
context.drawImage(video, 0, 0, canvas.width / 1.5, canvas.height / 1.5);
context.drawImage(canvas, 0, 0, canvas.width, canvas.height);
var dataURL = canvas.toDataURL("image/png");
$.ajax({
type: "POST",
url: "./upload.php",
data: {
dataURL: dataURL
}
});
});
Currently what you code does is to draw the canvas over itself, with the video already painted on it.
You can draw behind the existing content by using the globalCompositeOperation = "destination-over".
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.font = "16px sans-serif";
ctx.textAlign = "center";
const img = new Image(); // a video is the same
img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
img.decode().then(() => {
canvas.onclick = (evt) => {
ctx.globalCompositeOperation = "destination-over";
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// reset to default
ctx.globalCompositeOperation = "source-over";
};
ctx.fillText("click on the canvas", canvas.width / 2, canvas.height / 3);
ctx.fillText("to draw the image", canvas.width / 2, canvas.height / 3 + 20);
ctx.fillText("behind this text", canvas.width / 2, canvas.height / 3 + 40);
});
canvas { outline: 1px solid }
<canvas></canvas>
I have the following html file which draws an image on the canvas.
<canvas id="canvas"width="800"height="800"></canvas>
<script>
var canvas = document.getElementById('canvas')
let ctx = canvas.getContext('2d')
let img = new Image()
img.src = 'https://clipartspub.com/images/circle-clipart-blue-1.jpg'
img.onload = function(){
ctx.drawImage(img,300,300,300,300)
}
</script>
It works fine, however I would like to instead draw a cropped version of this image, for example, the bottom right quarter of the image. Is this possible?
You have to use the below implementation of drawImage to achieve that
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
Check the docs here
var canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let img = new Image();
img.src = "https://clipartspub.com/images/circle-clipart-blue-1.jpg";
img.onload = function () {
const width = img.width;
const height = img.height;
ctx.drawImage(
img, // Source image
width / 2, // Start at this x of image
height / 2, // Start at this y of image
width / 2, // Till this width of image
height / 2, // Till this height of image
0, // Start at this x of canvas
0, // Start at this y of image
300, // Till this width of canvas
300 // // Till this height of canvas
);
};
<canvas id="canvas"width="800"height="800"></canvas>
You can also use canvas.width and canvas.height in the canvas values used above for a better scaled result.
There are numerous examples out there showing how to draw things onto a canvas, however, my problem is slightly different - I want to load a photo into memory, draw a shape onto exact coordinates over the photo, THEN draw/scale the photo onto a canvas. Not sure where to start with this. Are there any relevant libraries out there I can use with ionic that will allow you to do this?
Edit 1 ~ I now have this mostly working:
private properties:
#ViewChild('mainCanvas') canvasEl: ElementRef;
private _CANVAS: any;
private _CONTEXT: any;
ionViewDidEnter():
this._CANVAS = this.canvasEl.nativeElement;
this._CONTEXT = this._CANVAS.getContext('2d');
updateCanvas():
var img = new Image();
const ctx = this._CONTEXT;
const canvas = this._CANVAS;
ctx.clearRect(0, 0, this._CANVAS.width, this._CANVAS.height);
ctx.fillStyle = "#ff0000";
img.onload = (() => {
img.width = img.width;
img.height = img.height;
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
ctx.lineWidth = 8;
ctx.strokeStyle = "#FF0000";
ctx.strokeRect(100, 100, 400, 400);
ctx.scale(0.5, 0.5); // this does nothing
});
img.src = (<any>window).Ionic.WebView.convertFileSrc(path);
This draws the photo then the rectangle onto the canvas, however, the resulting image is too large to fit onto the screen, so I need to scale the canvas after all drawing is complete. I tried this with ctx.scale but the canvas remains the same size regardless of which values I specify.
You cannot draw straight onto a photo, but what you can do is create an offscreen canvas that is the same size as the photo, draw the photo to it, and then draw your shapes on top.
The result can then be drawn to your main canvas e.g.
// Empty image for example purposes
const img = new Image(100, 100);
// Creating a canvas for example purposes
const mainCanvas = document.createElement('canvas');
const mainCtx = mainCanvas.getContext('2d');
// Create an offscreen buffer
const bufferCanvas = document.createElement('canvas');
const bufferCtx = bufferCanvas.getContext('2d');
// Scale the buffer canvas to match our image
bufferCanvas.width = img.width;
bufferCanvas.height = img.height;
if (bufferCtx && mainCtx) {
// Draw image to canvas
bufferCtx.drawImage(img, 0, 0);
// Draw a rectangle in the center
bufferCtx.fillRect(img.width / 2 - 5, img.height / 2 - 5, 10, 10);
// Draw the buffer to the main canvas
mainCtx.drawImage(bufferCanvas, 0, 0);
}
How can I achieve a blur behind a transparent box (fillStyle = 'rgba(255, 255, 255, 0.2)') in JavaScript canvas? Here's what I've got so far:
var canvas = document.getElementById('draw');
var c = canvas.getContext('2d');
function main() {
c.fillStyle = '#222';
c.fillRect(0, 0, canvas.width, canvas.height);
c.fillStyle = '#000';
c.fillRect(32, 32, 64, 64);
c.fillStyle = 'rgba(255, 255, 255, 0.2)';
c.filter = 'blur(5px)';
c.fillRect(16, 16, 128, 24);
}
But what happens, is instead of blurring the background behind the rectangle, is the rectangle itself is blurred, kind of obviously.
In the final script, I will probably use paths instead of rects.
Context2D filters will be applied only on your new drawings, so to also blur the background, you would actually have to redraw the part of the background you want to be blurred.
Fortunately, canvas can drawImage itself.
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 10
};
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
canvas.width = img.width / 2;
canvas.height = img.height / 2;
// first pass draw everything
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
// next drawings will be blurred
ctx.filter = 'blur('+ blurredRect.spread +'px)';
// draw the canvas over itself, cropping to our required rect
ctx.drawImage(canvas,
blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height,
blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height
);
// draw the coloring (white-ish) layer, without blur
ctx.filter = 'none'; // remove filter
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.fillRect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
}
<canvas id="canvas"></canvas>
But, canvas blur filter is a bit different than CSS one in that it will make the spreading stay inside the drawn area. This means that in our case, we have a 5px border around our rectangle that is less blurred than the center.
To workaround, we can take the whole thing in a different order and play with globalCompositeOperation property*:
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 10
};
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
var spread = blurredRect.spread,
ratio = 0.5,
// make our blurred rect spreads
x = blurredRect.x - spread,
y = blurredRect.y - spread,
w = blurredRect.width + (spread * 2),
h = blurredRect.height + (spread * 2);
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
// this time we will first draw the blurred rect
ctx.filter = 'blur('+ spread +'px)';
// this time we draw from the img directly
ctx.drawImage(img,
x / ratio, y / ratio, w / ratio, h / ratio,
x, y, w, h
);
// now we will want to crop the resulting blurred image to the required one, so we get a clear-cut
ctx.filter = 'none'; // remove filter
// with this mode, previous drawings will be kept where new drawings are made
ctx.globalCompositeOperation = 'destination-in';
ctx.fillStyle = '#000'; // make it opaque
ctx.rect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
ctx.fill(); // clear-cut done
// reuse our rect to make the white-ish overlay
ctx.fillStyle = 'rgba(255,255,255,0.2)';
// reset gCO to its default
ctx.globalCompositeOperation = 'source-over';
ctx.fill();
// now we will draw behind the our blurred rect
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
// reset to defaults
ctx.globalCompositeOperation = 'source-over';
}
<canvas id="canvas"></canvas>
But this approach requires that we keep access to the whole background as a drawable thing, in the example above that was just an image, but in real life, this might mean you'd have to do this operation on a second offscreen canvas.
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 2
};
var ctx = canvas.getContext('2d');
// create an off-screen canvas
var bCanvas = canvas.cloneNode();
var bCtx = bCanvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
var spread = blurredRect.spread;
canvas.width = bCanvas.width = img.width / 2;
canvas.height = bCanvas.height = img.height / 2;
// now we have a composed background
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.font = '40px Impact';
ctx.fillStyle = 'white';
ctx.fillText('..SO BLUR ME..', 120, 282);
// make our clear-cut on the offscreen canvas
bCtx.filter = 'blur(' + spread +'px)';
bCtx.drawImage(canvas,
blurredRect.x - spread, blurredRect.y - spread, blurredRect.width + spread * 2, blurredRect.height + spread * 2,
blurredRect.x - spread, blurredRect.y - spread, blurredRect.width + spread * 2, blurredRect.height + spread * 2
);
// clear-cut
bCtx.filter = 'none';
bCtx.globalCompositeOperation = 'destination-in';
bCtx.beginPath();
bCtx.rect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
bCtx.fillStyle = '#000';
bCtx.fill();
// white-ish layer
bCtx.globalCompositeOperation = 'source-over';
bCtx.fillStyle = 'rgba(255,255,255,0.2)';
bCtx.fillRect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
// now just redraw on the visible canvas
ctx.drawImage(bCanvas, 0,0);
}
<canvas id="canvas"></canvas>
*One may say that instead of an offscreen canvas and gCO we could have used ctx.clip(), but since you said it might a more complex Path than a rect, I will not advise to do so. Indeed, while it would require less code, and maybe use less memory, clipping is just bad with antialiasing, and since you are doing blurring, that will just look plain ugly.
I am working on animation optimisation and i wanted to try out canvas to see how it performs but i am not experienced well in canvas and i dont know how to prepare concept of this kind of animation.
this is the gif that shows how animation should rotate like:
this is my current code of js:
var cvs = document.getElementById('coin-spin'),
ctx = cvs.getContext('2d'),
w = cvs.width = 400,
h = cvs.height = 400,
cx = w / 2,
cy = h / 2,
a = 0;
var img = new Image();
var loop = function() {
// BG
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, w, h);
// draw image
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(Math.PI / 180 * a);
ctx.translate(-cx, -cy);
ctx.drawImage(img, cx - (img.width / 2), cy - (img.height / 2));
ctx.restore();
// axis
ctx.strokeStyle = '#000';
ctx.beginPath();
ctx.moveTo(cx, 0);
ctx.lineTo(cx, h);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, cy);
ctx.lineTo(w, cy);
ctx.stroke();
//mod angle
a++;
window.requestAnimationFrame(loop);
};
img.onload = function() {
loop();
};
img.src = 'https://image.ibb.co/gqkeXx/coin.png';
and the working demo on fiddle.
Could someone show how to add to the code so the image would rotate horizontally like on the gif?
EDIT ----
I added the spin, as it was also something to do, but still struggling on how to rotate it.
To get around the problem of rotating the object along two axes (faking one by mapping width to a sine wave), you can use an offscreen canvas to render the coin rotating around one axis, then render that canvas applying the second rotation ;
//make an offscreen canvas for rendering the coin rotating around one axis
var offscreenCanvas = document.createElement('canvas');
var cvs = document.getElementById('coin-spin'),
ctx = cvs.getContext('2d'),
w = cvs.width = 400,
h = cvs.height = 400,
cx = w / 2,
cy = h / 2,
a = 0;
var img = new Image();
var frameCount = 0;
var loop = function() {
frameCount++;
// BG
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, w, h);
offscreenContext.fillStyle = '#ccc';
offscreenContext.fillRect(0, 0, w, h);
//determine how wide to render the offscreen canvas so we can fake
//rotation around the second axis
var imgRenderWidth = offscreenCanvas.width * Math.sin(frameCount/10.0)
//render the coin rotating around one axis to the offscreen canvas
offscreenContext.save();
offscreenContext.translate(img.width/2, img.height/2);
offscreenContext.rotate(Math.PI / 180 * a);
offscreenContext.translate((0-img.width)/2, (0-img.height)/2);
offscreenContext.drawImage(img, 0,0);
offscreenContext.restore();
// draw offscreen canvas to the screen with our precalculated width
ctx.save();
ctx.drawImage(offscreenCanvas, cx - (imgRenderWidth / 2), cy - (offscreenCanvas.height / 2), imgRenderWidth, offscreenCanvas.height);
ctx.restore();
// axis
ctx.strokeStyle = '#000';
ctx.beginPath();
ctx.moveTo(cx, 0);
ctx.lineTo(cx, h);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, cy);
ctx.lineTo(w, cy);
ctx.stroke();
//mod angle
a++;
window.requestAnimationFrame(loop);
};
//once the image has loaded, we know what size our offscreen canvas needs to be
img.onload = function() {
offscreenCanvas.width = img.width;
offscreenCanvas.height = img.height;
loop();
};
img.src = 'https://image.ibb.co/gqkeXx/coin.png';
//prepare the offscreen context so we can render to it later
var offscreenContext = offscreenCanvas.getContext('2d');
https://jsfiddle.net/ay3h5vuo/