I've seen this problem online e.g:
HTML5 canvas drawImage with at an angle
http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/
But I was unsuccessful in applying them to my problem so far.
const TO_RADIANS = Math.PI / 180
export function cropPreview(
image: HTMLImageElement,
canvas: HTMLCanvasElement,
crop: PixelCrop,
scale = 1,
rotate = 0,
) {
const ctx = canvas.getContext('2d')
if (!ctx) {
throw new Error('No 2d context')
}
const scaleX = image.naturalWidth / image.width
const scaleY = image.naturalHeight / image.height
const pixelRatio = window.devicePixelRatio || 1
canvas.width = Math.floor(crop.width * pixelRatio * scaleX)
canvas.height = Math.floor(crop.height * pixelRatio * scaleY)
ctx.scale(pixelRatio, pixelRatio)
ctx.imageSmoothingQuality = 'high'
const cropX = crop.x * scaleX
const cropY = crop.y * scaleY
const cropWidth = crop.width * scaleX
const cropHeight = crop.height * scaleY
const rotateRads = rotate * TO_RADIANS
const centerX = image.width / 2
const centerY = image.height / 2
ctx.save()
ctx.translate(centerX, centerY)
ctx.rotate(rotateRads)
ctx.drawImage(image, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight)
ctx.restore()
}
Here's a live playground with the problem, just choose an image and apply some rotation: CodeSandbox image rotation
What am I doing wrong here? The bottom image should show exactly what is in the crop area even with rotation applied.
Here is your updated function
export async function cropPreview(
image: HTMLImageElement,
canvas: HTMLCanvasElement,
crop: PixelCrop,
scale = 1,
rotate = 0,
) {
const ctx = canvas.getContext('2d')
if (!ctx) {
throw new Error('No 2d context')
}
const scaleX = image.naturalWidth / image.width
const scaleY = image.naturalHeight / image.height
const pixelRatio = window.devicePixelRatio || 1
canvas.width = Math.floor(crop.width * pixelRatio * scaleX)
canvas.height = Math.floor(crop.height * pixelRatio * scaleY)
ctx.scale(pixelRatio, pixelRatio)
ctx.imageSmoothingQuality = 'high'
const cropX = crop.x * scaleX
const cropY = crop.y * scaleY
const cropWidth = crop.width * scaleX
const cropHeight = crop.height * scaleY
const rotateRads = rotate * TO_RADIANS
const centerX = image.width / 2
const centerY = image.height / 2
ctx.save()
// 5) Move the crop origin to the canvas origin (0,0)
ctx.translate(-cropX, -cropY)
// 4) Move the origin to the center of the original position
ctx.translate(centerX, centerY)
// 3) Rotate around the origin
ctx.rotate(rotateRads)
// 2) Scaled the image
ctx.scale(scale, scale)
// 1) Move the center of the image to the origin (0,0)
ctx.translate(-centerX, -centerY)
ctx.drawImage(
image,
0,
0,
image.width,
image.height,
0,
0,
image.width,
image.height,
)
ctx.restore()
}
Instead of trying to figure out how to crop you can simply let the canvas to crop it.
The transfromations are applied in the reverse order as they appear, so what I am doing is
Move the center of the image to the origin (0,0)
Scaled the image
Rotate around the origin
Move the origin to the center of the original position
Move the crop origin to the canvas origin (0,0)
Related
I have a canvas and I want to be able to draw an image in different sizes from "fit" (like CSS "contain") to "fill" (like CSS "cover"). I use drawImage() with different source and destination properties for fit and fill. Both extremes work perfectly as expected, but in between the image proportions are way off, and the image looks flat. I use linear interpolation to calculate the between source and destination properties.
"fit/contain" properties:
ctx.drawImage(
img, // image
0, // source x
0, // source y
img.width, // source width
img.height, // source height
(canvas.width - canvas.height * imageAspect) / 2, // destination x
0, // destination y
canvas.height * imageAspect, // destination width
canvas.height // destination height
)
"fill/cover" Properties:
ctx.drawImage(
img, // image
0, // source x
(image.height - img.width / canvasAspect) / 2, // source y
img.width, // source width
img.width / canvasAspect, // source height
0, // destination x
0, // destination y
canvas.width, // destination width
canvas.height // destination height
)
These are both fine, but linear interpolation of all the values get the wrong proportions of the image. Here's a quick demo that is not working as expected, I animated the interpolation so that you can see the squished effect more clearly:
Code Pen
The desired result would be keeping the image's proportions right in every step between 0 (fit) and 1 (fill). What am I missing here?
EDIT: The easiest solution would be to always take the full source image (not crop it with sX, sY, sWidth, and sHeight) and then draw the destination with negative coordinate values on the canvas when the image is bigger than the canvas. This is working but it is not the desired behavior. Because further on I need to be able to draw only to a certain sub-rectangle in the canvas, where the overlapping ("negative values") would be seen. I don't want to draw outside the rectangle. I am quite sure it is just a small mathematical issue here that needs to be solved.
For me, the solution in your "Edit" is the way to go.
If later on you want to clip the image in a smaller rectangle than the canvas, use the clip() method:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 800;
canvas.height = 150;
let step = 1;
let direction = 1;
// control the clipping rect position with the mouse
const mouse = {x: 400, y: 75};
onmousemove = (evt) => {
const rect = canvas.getBoundingClientRect();
mouse.x = evt.clientX - rect.left;
mouse.y = evt.clientY - rect.top;
};
function getBetweenValue(from, to, stop) {
return from + (to - from) * stop;
}
const image = new Image();
image.src =
"https://w7.pngwing.com/pngs/660/154/png-transparent-perspective-grid-geometry-grid-perspective-grid-geometric-grid-grid.png";
let imageAspect = 0;
let canvasAspect = canvas.width / canvas.height;
let source;
let containDestination;
let coverDestination;
function draw(image) {
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Clip the context in a sub-rectangle
ctx.beginPath();
ctx.rect(mouse.x - 150, mouse.y - 50, 300, 100);
ctx.stroke();
ctx.clip();
// Since our image scales from the middle of the canvas,
// set the context's origin there, that makes our BBox values simpler
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.drawImage(
image,
source.x,
source.y,
source.width,
source.height,
getBetweenValue(containDestination.x, coverDestination.x, step),
getBetweenValue(containDestination.y, coverDestination.y, step),
getBetweenValue(containDestination.width, coverDestination.width, step),
getBetweenValue(containDestination.height, coverDestination.height, step)
);
ctx.restore(); // remove clip & transform
}
image.addEventListener("load", () => {
imageAspect = image.width / image.height;
source = {
x: 0,
y: 0,
width: image.width,
height: image.height
};
containDestination = {
x: -(canvas.height * imageAspect) / 2,
y: -(canvas.height / 2),
width: canvas.height * imageAspect,
height: canvas.height
};
coverDestination = {
x: -image.width / 2,
y: -image.height / 2,
width: image.width,
height: image.height
};
raf();
});
function raf() {
draw(image);
step += .005 * direction;
if (step > 1 || step < 0) {
direction *= -1;
}
window.requestAnimationFrame(raf);
}
canvas {
border:1px solid red;
}
img {
max-width:30em;
height:auto;
}
Use your mouse to move the clipping rectangle<br>
<canvas></canvas><br><br>
Original image proportions:<br>
<img src="https://w7.pngwing.com/pngs/660/154/png-transparent-perspective-grid-geometry-grid-perspective-grid-geometric-grid-grid.png" alt="">
I have an image on a canvas:
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext("2d");
var img = new Image();
img.onload = function(){
ctx.drawImage(img, 0, 0, 200, 350);
}
img.src = "/img.png";
Can an image be rotated around the Y axis? The 2d Canvas API only seems to have a rotate function that rotates around the Z-axis.
You can rotate around whatever axis you want. Using the save-transform-restore method covered in the linked question, we can do something similar by transforming a DOMMatrix object and applying it to the canvas.
Sample:
// Untransformed draw position
const position = {x: 0, y: 0};
// In degrees
const rotation = { x: 0, y: 0, z: 0};
// Rotation relative to here (this is the center of the image)
const rotPt = { x: img.width / 2, y: img.height / 2 };
ctx.save();
ctx.setTransform(new DOMMatrix()
.translateSelf(position.x + rotPt.x, position.y + rotPt.y)
.rotateSelf(rotation.x, rotation.y, rotation.z)
);
ctx.drawImage(img, -rotPt.x, -rotPt.y);
ctx.restore();
This isn't a "true" 3d, of course (the rendering context is "2d" after all). I.e. It's not a texture applied to some polygons. All it's doing is rotating and scaling the image to give the illusion. If you want that kind of functionality, you'll want to look at a WebGL library.
Demo:
I drew a cyan rectangle around the image to show the untransformed position.
Image source from MDN (see snippet for url).
const canvas = document.getElementsByTagName("canvas")[0];
const ctx = canvas.getContext("2d");
const img = new Image();
img.onload = draw;
img.src = "https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage/canvas_drawimage.jpg";
let rotCounter = 0;
let motionCounter = 0;
function draw() {
// Untransformed draw position
const position = {
x: motionCounter % canvas.width,
y: motionCounter % canvas.height
};
// In degrees
const rotation = {
x: rotCounter * 1.2,
y: rotCounter,
z: 0
};
// Rotation relative to here
const rotPt = {
x: img.width / 2,
y: img.height / 2
};
ctx.save();
ctx.setTransform(new DOMMatrix()
.translateSelf(position.x + rotPt.x, position.y + rotPt.y)
.rotateSelf(rotation.x, rotation.y, rotation.z)
);
// Rotate relative to this point
ctx.drawImage(img, -rotPt.x, -rotPt.y);
ctx.restore();
// Position
ctx.strokeStyle = 'cyan';
ctx.strokeRect(position.x, position.y, img.width, img.height);
ctx.strokeStyle = 'black';
rotCounter++;
motionCounter++;
}
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
requestAnimationFrame(render);
}
render();
canvas {
border: 1px solid black;
}
<canvas width=600 height=400></canvas>
Rotate without perceptive
If you only want to rotate around the y Axis without perspective then you can easily do it on the 2D canvas as follows.
Assuming you have loaded the image the following will rotate around the image Y axis and have the y axis align to an arbitrary line.
The arguments for rotateImg(img, axisX, axisY, rotate, centerX, centerY)
img a valid image.
axisX, axisY vector that is the direction of the y axis. To match image set to - axisX = 0, axisY = 1
rotate amount to rotate around image y axis in radians. 0 has image facing screen.
centerX & centerY where to place the center of the image
function rotateImg(img, axisX, axisY, rotate, centerX, centerY) {
const iw = img.naturalWidth;
const ih = img.naturalHeight;
// Normalize axis
const axisLen = Math.hypot(axisX, axisY);
const nAx = axisX / axisLen;
const nAy = axisY / axisLen;
// Get scale along image x to match rotation
const wScale = Math.cos(rotate);
// Set transform to draw content
ctx.setTransform(nAy * wScale, -nAx * wScale, nAx, nAy, centerX, centerY);
// Draw image normally relative to center. In this case half width and height up
// to the left.
ctx.drawImage(img, -iw * 0.5, -ih * 0.5, iw, ih);
// to reset transform use
// ctx.setTransform(1,0,0,1,0,0);
}
Demo
The demo uses a slightly modified version of the above function. If given an optional color as the last argument. It will shade the front face using the color and render the back face as un-shaded with that color.
The demo rotates the image and slowly rotates the direction of the image y axis.
const ctx = canvas.getContext("2d");
var W = canvas.width, H = canvas.height;
const img = new Image;
img.src = "https://i.stack.imgur.com/C7qq2.png?s=256&g=1";
img.addEventListener("load", () => requestAnimationFrame(renderLoop), {once:true});
function rotateImg(img, axisX, axisY, rotate, centerX, centerY, backCol) {
const iw = img.naturalWidth;
const ih = img.naturalHeight;
const axisLen = Math.hypot(axisX, axisY);
const nAx = axisX / axisLen;
const nAy = axisY / axisLen;
const wScale = Math.cos(rotate);
ctx.setTransform(nAy * wScale, -nAx * wScale, nAx, nAy, centerX, centerY);
ctx.globalAlpha = 1;
ctx.drawImage(img, -iw * 0.5, -ih * 0.5, iw, ih);
if (backCol) {
ctx.globalAlpha = wScale < 0 ? 1 : 1 - wScale;
ctx.fillStyle = backCol;
ctx.fillRect(-iw * 0.5, -ih * 0.5, iw, ih);
}
}
function renderLoop(time) {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, W, H);
rotateImg(img, Math.cos(time / 4200), Math.sin(time / 4200), time / 500, W * 0.5, H * 0.5, "#268C");
requestAnimationFrame(renderLoop);
}
canvas {border: 1px solid black; background: #147;}
<canvas id="canvas" width="300" height="300"></canvas>
I have a boundingBox selecting a zone in a image and i would like to scale this boundingBox to my canvas ratio.
I would like to recalculate the ratio of my boundingBox to correctly target a zone of the resized image in the canvas.
Here an example + jsFiddle : ( this is an example, the real project use multiple boundingBox with a big range of images)``
The boundingBox coordinate / width and height are calculated from the image but after the transformation i dont know how to convert the coordinate / ratio.
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext("2d");
//bbox
let [bx, by, bw, bh] = [146, 58, 82, 87]
console.log(bx, by, bw, bh)
function bboxDraw(){
// Draw the bounding box.
ctx.strokeStyle = "#00FFFF";
ctx.lineWidth = 4;
ctx.strokeRect(bx, by, bw, bh);
// Draw the label background.
ctx.fillStyle = "#00FFFF";
}
function scaleToFill(img, callback){
canvas.width = window.innerWidth
canvas.height = window.innerHeight
// get the scale
var scale = Math.max(canvas.width / img.width, canvas.height / img.height);
// get the top left position of the image
var x = (canvas.width / 2) - (img.width / 2) * scale;
var y = (canvas.height / 2) - (img.height / 2) * scale;
ctx.drawImage(img, x, y, img.width * scale, img.height * scale);
bboxDraw()
}
let img = new Image()
try {
img.src = "https://via.placeholder.com/1280x720"
} catch (error) {
console.log("image URL", error);
}
img.onload = function() {
scaleToFill(this)
}
JSFiddle
Any good idea to preserve the ratio after the scale2fill transformation and correctly target the boundingBox area ?
To recalculate BoundingBox coordinates from image after scale to fill transformation in HTML Canvas.
We need to recalculate the width/height/x/y of the boundingBox using the naturalWidth and naturalHeight of the image.
let [bx, by, bw, bh] = [146, 58, 82, 87]
function bboxRatioDraw(img) {
// Use percent to correctly adapt the coordinate to the scaled image
let percentBx = (100 * (bx / img.naturalWidth)), // x %
percentBy = (100 * (by / img.naturalHeight)), // y %
percentBw = (bw * 100) / img.naturalWidth, // width%
percentBh = (bh * 100) / img.naturalHeight; // height%
// then map the values to the current canvas
let finalBx = (percentBx * canvas.width) / 100, // x en pixel
finalBy = (percentBy * canvas.height) / 100, // y en pixel
finalBw = (percentBw * canvas.width) / 100, // width en pixel
finalBh = (percentBh * canvas.height) / 100; // height en pixel
// Draw the bounding box.
ctx.strokeStyle = "green";
ctx.lineWidth = 4;
ctx.strokeRect(finalBx, finalBy, finalBw, finalBh);
// Draw the label background.
ctx.fillStyle = "#00FFFF";
}
Updated JSFiddle
I'm trying to crop an image in a react application. I'm currently using a library called react-image-crop but it seems the cropped image is exactly the same size of crop area on the browser, means if I resize my browser window, the same area of the image comes to be different size. is there any way to retain the resolution of the original image and be still able to crop on the client side? the picture below is the result of cropping of the same area of the picture in different browser sizes.
i'm pretty much using react-image-crop out of the box with following crop parameters
const [crop, setCrop] = useState({unit: '%', width: 100, aspect: 16 / 9 });
Actually i have the same problem, i also use react-image-crop. My current solution is i create a modal with static size in px as a crop windows. so if the window size is smaller, the modal overflow will be activated.
more or less like this:
so scroller will dynamically change based on window size and it doesn't affect the image size.
If there is a real and better solution maybe i'd also like to hear about it :)
in the hook version of the demo, replacing the getResizedCanvas (and moving it inside the react module) fixes the problem
const getResizedCanvas = () => {
const scaleX = imgRef.current.naturalWidth / imgRef.current.width;
const scaleY = imgRef.current.naturalHeight / imgRef.current.height;
const tmpCanvas = document.createElement("canvas");
tmpCanvas.width = Math.ceil(crop.width*scaleX);
tmpCanvas.height = Math.ceil(crop.height*scaleY);
const ctx = tmpCanvas.getContext("2d");
const image = imgRef.current;
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width*scaleX,
crop.height*scaleY,
);
return tmpCanvas;
}
For me, this was what actually fixed (using hook).
Basically i'm calculating canvas size taking into account the window resolution in physical pixels to the resolution in CSS pixels for the current display device.
const canvas = document.createElement('canvas')
const crop = completedCrop
const scaleX = image.naturalWidth / image.width
const scaleY = image.naturalHeight / image.height
const ctx = canvas.getContext('2d')
const pixelRatio = window.devicePixelRatio
canvas.width = scaleX * crop.width * pixelRatio
canvas.height = scaleY * crop.height * pixelRatio
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0)
ctx.imageSmoothingQuality = 'high'
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width * scaleX,
crop.height * scaleY
)
You can also export the canvas blob as png (lossless) rather than jpeg, which will provide you a better image.
canvas.toBlob(
blob => {
const img = URL.createObjectURL(blob)
// do whatever you want...
},
'image/png',
1
)
I had the same issue with the cropper. But then adding scaled height and width to canvas and drawImage method worked for me.
check below screenshots.
Image while cropping:
Image resolution after crop:
const createCropPreview = async (image, crop, fileName) => {
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
const canvas = document.createElement("canvas");
canvas.width = Math.ceil(crop.width * scaleX);
canvas.height = Math.ceil(crop.height * scaleY);
const ctx = canvas.getContext("2d");
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width * scaleX,
crop.height * scaleY
);
return new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob) {
blob.name = fileName;
window.URL.revokeObjectURL(previewUrl);
const obj = window.URL.createObjectURL(blob);
setPreviewUrl(obj);
props.setImg(obj, blob);
}
}, "image/jpeg");
});
};
I have an image that I'm allowing users to rotate 90 degrees in any direction. Every time they rotate, I use canvas to perform the image manipulations and then save the data returned by the canvas.toDataURL("image/png", 1).
The problem is that the image quality decreases every time I rotate the image.
My end goal is to rotate a rectangular image without losing image quality and also saving the new data url.
function rotateAndSave(image: HTMLImageElement, degrees: number): string {
const imageWidth = image.naturalWidth;
const imageHeight = image.naturalHeight;
const startedHorizontalEndedVertical = imageWidth > imageHeight;
const canvasSize = startedHorizontalEndedVertical ? imageWidth : imageHeight;
const canvas = document.createElement("canvas");
canvas.width = canvasSize;
canvas.height = canvasSize;
const ctx = canvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// center and rotate canvas
const translateCanvas = canvasSize / 2;
ctx.translate(translateCanvas, translateCanvas);
ctx.rotate(degrees * Math.PI / 180);
// draw from center
const translateImageX = startedHorizontalEndedVertical ? -translateCanvas : (-imageWidth / 2);
const translateImageY = startedHorizontalEndedVertical ? (-imageHeight / 2) : -translateCanvas;
ctx.drawImage(image, translateImageX, translateImageY);
// I got 'cropPlusExport' from another stackoverflow question.
function cropPlusExport(img, cropX, cropY, cropWidth, cropHeight) {
// create a temporary canvas sized to the cropped size
const canvas1 = document.createElement('canvas');
canvas1.width = cropWidth;
canvas1.height = cropHeight;
const ctx1 = canvas1.getContext('2d');
ctx1.setTransform(1, 0, 0, 1, 0, 0);
ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
// use the extended from of drawImage to draw the
// cropped area to the temp canvas
ctx1.drawImage(img, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
return canvas1.toDataURL("image/png", 1);
}
// Start Cropping
let squareImage = new Image();
squareImage.src = canvas.toDataURL("image/png", 1);
squareImage.onload = () => {
const sx = startedHorizontalEndedVertical ? ((canvasSize - imageHeight) / 2) : 0;
const sy = startedHorizontalEndedVertical ? 0 : ((canvasSize - imageWidth) / 2);
const sw = imageHeight;
const sh = imageWidth;
const data = cropPlusExport(squareImage, sx, sy, sw, sh);
// Update DOM via angular binding...
const dataUrl = data.split(",")[1];
this.imageSource = dataUrl;
squareImage = null;
}
example html
<div class="view">
<img [src]="imageSource" />
</div>
Keep in mind that I am cropping to the natural width and height of the image. So, what's weird is that if I don't crop, then the image quality doesn't change but when I do crop, the image quality changes.
Canvas drawing is lossy, and rotating an image induce hard modifications of the pixels. So indeed, if you start always from the last state, you'll end up adding more and more artifacts to your image.
Simply store the original image somewhere and always start from there instead of using the modified version.
// will fire in a loop
img.onload = e => elem.rotateAndSave(1);
const elem = {
// store a copy of the original image
originalimage: img.cloneNode(),
angle: 0,
rotateAndSave(degrees) {
// always use the stored original image
const image = this.originalimage;
// keep track of current transform
this.angle += degrees;
const imageWidth = image.naturalWidth;
const imageHeight = image.naturalHeight;
const startedHorizontalEndedVertical = imageWidth > imageHeight;
const canvasSize = startedHorizontalEndedVertical ? imageWidth : imageHeight;
const canvas = document.createElement("canvas");
canvas.width = canvasSize;
canvas.height = canvasSize;
const ctx = canvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// center and rotate canvas
const translateCanvas = canvasSize / 2;
ctx.translate(translateCanvas, translateCanvas);
ctx.rotate(this.angle * Math.PI / 180);
// draw from center
const translateImageX = startedHorizontalEndedVertical ? -translateCanvas : (-imageWidth / 2);
const translateImageY = startedHorizontalEndedVertical ? (-imageHeight / 2) : -translateCanvas;
ctx.drawImage(image, translateImageX, translateImageY);
// I got 'cropPlusExport' from another stackoverflow question.
function cropPlusExport(img, cropX, cropY, cropWidth, cropHeight) {
// create a temporary canvas sized to the cropped size
const canvas1 = document.createElement('canvas');
canvas1.width = cropWidth;
canvas1.height = cropHeight;
const ctx1 = canvas1.getContext('2d');
ctx1.setTransform(1, 0, 0, 1, 0, 0);
ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
// use the extended from of drawImage to draw the
// cropped area to the temp canvas
ctx1.drawImage(img, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
return canvas1.toDataURL("image/png", 1);
}
// Start Cropping
let squareImage = new Image();
squareImage.src = canvas.toDataURL("image/png", 1);
squareImage.onload = () => {
const sx = startedHorizontalEndedVertical ? ((canvasSize - imageHeight) / 2) : 0;
const sy = startedHorizontalEndedVertical ? 0 : ((canvasSize - imageWidth) / 2);
const sw = imageHeight;
const sh = imageWidth;
const data = cropPlusExport(squareImage, sx, sy, sw, sh);
// Update DOM via angular binding...
img.src = data;
}
}
};
<img crossorigin src="https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg" id="img">