Reputation: 818
I crop an image through object method toDataURL (not canvas) with params such as left, top, width and height. It works great, but i don't know what should i do when an angle attribute of image doesn't equal 0? I tried to call setAngle=0 -> setCoords() -> toDataURL() restore angle <-- it works but not so well and i think this workflow is't good.
cropImage: ->
sLeft = @glob.data.selectArea.left
sTop = @glob.data.selectArea.top
sAngle = @glob.data.selectArea.angle
@glob.data.selected.setAngle(0)
@glob.data.selected.setCoords()
@glob.data.cropPicture.setAngle(0)
@glob.data.cropPicture.setCoords()
cropParams = {
width: @glob.data.selectArea.getWidth()
height: @glob.data.selectArea.getHeight()
left: @glob.data.selectArea.getLeft() - @glob.data.cropPicture.getLeft()
top: @glob.data.selectArea.getTop() - @glob.data.cropPicture.getTop()
}
...
croppedDataUrl = @glob.data.cropPicture.toDataURL(cropParams)
fabric.Image.fromURL(croppedDataUrl, (img) =>
img.left = sLeft
img.top = sTop
img.angle = sAngle
@glob.data.canvas.add(img)
...
Upvotes: 0
Views: 1236
Reputation: 1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Fabric.js Practice</title>
<style>
#crop {
display: none;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<button id="crop">Crop</button>
<button id="startCrop" style="border: 1px solid #000000">Mark Crop Area</button>
<br />
<canvas style="visibility: hidden" id="canvas_crop"></canvas>
<script src="https://unpkg.com/[email protected]/dist/fabric.min.js"></script>
<script>
let currentImage;
const canvas = initCnvas();
canvas.preserveObjectStacking = true;
addImage(canvas);
createMaskForCrop(canvas);
crop(canvas);
function initCnvas() {
return new fabric.Canvas("c", {
width: 1200,
height: 600,
strokeWidth: 5,
stroke: "rgba(100,200,200,0.5)",
});
}
function addImage(canvas) {
fabric.Image.fromURL('https://via.placeholder.com/400', (img) => {
canvas.add(img);
canvas.centerObject(img);
canvas.setActiveObject(img);
currentImage = img;
canvas.renderAll();
}, { crossOrigin: 'anonymous' })
}
function createMaskForCrop(canvas) {
document.querySelector("#startCrop").addEventListener("click", function () {
addSelectionRect();
canvas.setActiveObject(selectionRect);
canvas.renderAll();
document.querySelector("#crop").style.display = "block";
});
}
function addSelectionRect() {
selectionRect = new fabric.Rect({
left: currentImage.left,
top: currentImage.top,
width: currentImage.width,
height: currentImage.height,
fill: 'rgb(178, 178, 178, 0.4)',
transparentCorners: false,
cornerColor: 'rgb(178, 178, 178, 0.8)',
strokeWidth: 1,
cornerStrokeColor: 'black',
borderColor: 'black',
borderDashArray: [5, 5],
cornerStyle: 'circle',
cornerSize: 8,
fillRule: 'Croping',
lockMovementX: true,
lockMovementY: true,
scaleX: currentImage.scaleX,
scaleY: currentImage.scaleY,
angle: currentImage.angle
});
canvas.add(selectionRect);
}
function crop(canvas) {
document.querySelector("#crop").addEventListener("click", function (event) {
document.querySelector("button#crop").style.display = "none";
let angle = currentImage.angle;
const group = new fabric.Group([currentImage, selectionRect]);
group.rotate(360 - angle);
group.ungroupOnCanvas();
canvas.renderAll();
let cropX = (selectionRect.left - currentImage.left)/currentImage.scaleX;
let cropY = (selectionRect.top - currentImage.top)/currentImage.scaleY;
let cropWidth = selectionRect.getScaledWidth()/currentImage.scaleX;
let cropHeight = selectionRect.getScaledHeight()/currentImage.scaleY;
currentImage.set({
top: currentImage.top + cropY * currentImage.scaleY,
left: currentImage.left + cropX * currentImage.scaleX,
cropX: cropX,
cropY: cropY,
width: cropWidth,
height: cropHeight
});
canvas.remove(selectionRect);
canvas.remove(group);
canvas.setActiveObject(currentImage);
currentImage.rotate(angle);
canvas.renderAll();
});
}
</script>
</body>
</html>
crop image using fabric js included image angle
Upvotes: 0
Reputation: 818
My solution:
cropImage: ->
# origin image
originWidth = @glob.cropPicture.getWidth()
originHeight = @glob.cropPicture.getHeight()
originLeft = @glob.cropPicture.left
originTop = @glob.cropPicture.top
# coordinates of the center of origin image
ctxLeft = - originWidth / 2 + @glob.cropPicture.strokeWidth
ctxTop = - originHeight / 2 + @glob.cropPicture.strokeWidth
# crop mask
width = @glob.selectArea.getWidth()
height = @glob.selectArea.getHeight()
angle = @glob.selectArea.getAngle()
left = @glob.selectArea.left
top = @glob.selectArea.top
cropLeft = left - originLeft
cropTop = top - originTop
@glob.cropPicture.clipTo = (ctx) =>
ctx.save()
ctx.translate(ctxLeft, ctxTop)
ctx.rect(cropLeft, cropTop, width, height)
ctx.restore()
@glob.cropPicture.angle = 0
@glob.cropPicture.setCoords()
cropData = @glob.cropPicture.toDataURL()
@glob.cropPicture.angle = angle
@glob.cropPicture.setCoords()
fabric.Image.fromURL(cropData, (img1) =>
params = {
width: width
height: height
left: cropLeft
top: cropTop
}
fabric.Image.fromURL(img1.toDataURL(params), (img2) =>
@glob.canvas.add img2
)
)
@glob.canvas.renderAll()
Upvotes: 0