当图像重新缩放以适合画布时,织物 js 上的裁剪功能无法正常工作
Posted
技术标签:
【中文标题】当图像重新缩放以适合画布时,织物 js 上的裁剪功能无法正常工作【英文标题】:Crop function on fabric js not working properly when image is rescaled to fit canvas 【发布时间】:2021-07-10 14:13:22 【问题描述】:github 仓库链接:Click here
我目前正在使用一个函数来裁剪图像,问题是:当我重新缩放图像以适合画布时,裁剪无法识别该更改。
图像未重新缩放以适合画布的示例:https://drive.google.com/file/d/1YFWz9AQDnjQmvmG0-la2gn9HfpYAT1Ak/view我在视频中所做的只是缩小图像。
图像重新缩放以适合画布时的示例:https://drive.google.com/file/d/1Bny4g-QtX63oIrrvd4G7SNSkp0RoBXNn/view
我的裁剪代码
var lastSelectedPicture = null;
var isInsertingCropRectangle = false;
var crop_rect, isDown, origX, origY, mask, target;
var done = false;
// FIXED BACKGROUND IMAGE
var src = "https://i.imgur.com/nnCUr4g.jpg";
fabric.Image.fromURL(src, function(img)
img.dirty = true;
img.selectable = false;
img.noScaleCache = false
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas),
scaleX: canvas.getWidth() / img.getScaledWidth(),
scaleY: canvas.getHeight() / img.getScaledHeight(),
)
canvas.add(img);
canvas.renderAll();
);
// IMAGEM TO CUT
fabric.Image.fromURL(src, function(img)
img.selectable = true;
img.id = 'target';
img.borderColor = 'green';
img.noScaleCache = false
img.scaleX = canvas.width / img.getScaledWidth();
img.scaleY = canvas.height / img.getScaledHeight();
canvas.add(img);
canvas.renderAll();
)
canvas.on('object:added', function(e)
target = null;
mask = null;
canvas.forEachObject(function(obj)
//alert(obj.get('id'));
var id = obj.get('id');
if (id === 'target')
target = obj;
canvas.setActiveObject(obj);
if (id === 'mask')
//alert(done);
//alert('mask');
mask = obj;
);
);
canvas.on('object:modified', function(e)
e.target.setCoords();
canvas.renderAll();
);
//////////////////////////////////////////////////////////
// MASK
//////////////////////////////////////////////////////////
document.getElementById("mask").addEventListener("click", function()
isInsertingCropRectangle = true;
canvas.discardActiveObject();
lastSelectedPicture.selectable = false;
lastSelectedPicture.setCoords();
lastSelectedPicture.dirty = true;
canvas.renderAll();
canvas.discardActiveObject();
isInsertingCropRectangle = true;
);
//////////////////////////////////////////////////////////
// CROP
//////////////////////////////////////////////////////////
document.getElementById("crop").addEventListener("click", function()
if (target !== null && mask !== null)
// Re-scale mask
var topMask = mask.top
var leftMask = mask.left
target.top = topMask
target.left = leftMask
// Do the crop
target.cropX = leftMask
target.cropY = topMask
canvas.renderAll()
mask = rescaleMask(target, mask);
canvas.renderAll()
mask.setCoords()
canvas.renderAll()
target.width = mask.getScaledWidth()
target.height = mask.getScaledHeight()
target.dirty=true;
canvas.setActiveObject(target);
target.selectable = true;
canvas.bringToFront(target);
target.setCoords()
canvas.remove(mask)
canvas.renderAll();
);
//////////////////////////////////////////////////////////
// RE-SCALE MASK FOR CROPPING
//////////////////////////////////////////////////////////
function rescaleMask(target, mask)
mask.scaleX/=target.scaleX;
mask.scaleY/=target.scaleY;
var targetCenterX = target.width * target.scaleX / 2;
var targetCenterY = target.height * target.scaleY / 2;
var maskOverlapX = mask.left - target.left;
var maskOverlapY = mask.top - target.top;
var centerBasedX = maskOverlapX - targetCenterX;
var centerBasedY = maskOverlapY - targetCenterY;
if( maskOverlapX >= targetCenterX)
centerBasedX = (maskOverlapX - targetCenterX)/target.scaleX;
else
centerBasedX = (-(targetCenterX) + maskOverlapX)/target.scaleX;
if( maskOverlapY >= targetCenterY)
centerBasedY = (maskOverlapY - targetCenterY)/target.scaleY;
else
centerBasedY = (-(targetCenterY) + maskOverlapY)/target.scaleY;
mask.left = centerBasedX;
mask.top = centerBasedY;
mask.originX = 'left';
mask.originY = 'top';
mask.setCoords();
mask.dirty=true;
canvas.renderAll();
return mask;
canvas.on('mouse:down', function(o)
if( isInsertingCropRectangle == true )
if (done)
canvas.renderAll();
return;
isDown = true;
var pointer = canvas.getPointer(o.e);
console.log(pointer);
origX = pointer.x;
origY = pointer.y;
crop_rect = new fabric.Rect(
left: origX,
top: origY,
width: pointer.x - origX,
height: pointer.y - origY,
opacity: .3,
transparentCorners: false,
selectable: true,
id: 'mask',
borderColor: 'blue'
);
canvas.add(crop_rect);
canvas.renderAll();
);
canvas.on('mouse:move', function(o)
if( isInsertingCropRectangle == true )
if (done)
canvas.renderAll();
return;
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x)
crop_rect.set(
left: Math.abs(pointer.x)
);
if (origY > pointer.y)
crop_rect.set(
top: Math.abs(pointer.y)
);
crop_rect.set(
width: Math.abs(origX - pointer.x)
);
crop_rect.set(
height: Math.abs(origY - pointer.y)
);
crop_rect.setCoords();
canvas.renderAll();
else
);
canvas.on('mouse:up', function(o)
if( isInsertingCropRectangle == true )
if (done)
canvas.renderAll();
return;
isDown = false;
crop_rect.set(
selectable: true
);
done = true;
else
);
canvas.on('selection:created', function(event)
selectionChanged(event);
);
canvas.on('selection:updated', function(event)
selectionChanged(event);
);
function selectionChanged(event)
switch(event.target.type)
case 'textbox':
break;
case 'image':
lastSelectedPicture = event.target;
break;
case 'rect':
break;
case 'group':
break;
default:
break;
【问题讨论】:
【参考方案1】:我找到了解决办法
基本上,我所做的是在对象上设置调整大小的图像的 scaleX 和 scaleY,然后获取这些值并将它们划分为cropX 和cropY 部分,如下所示:
target.cropX = leftMask / scaleImage.x
target.cropY = topMask / scaleImage.y
完整代码
var lastSelectedPicture = null;
var isInsertingCropRectangle = false;
var crop_rect, isDown, origX, origY, mask, target;
var done = false;
// IMAGEM DE PLANO DE FUNDO
var src = "https://i.imgur.com/nnCUr4g.jpg";
fabric.Image.fromURL(src, function(img)
img.dirty = true;
img.selectable = false;
img.noScaleCache = false
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas),
scaleX: canvas.getWidth() / img.getScaledWidth(),
scaleY: canvas.getHeight() / img.getScaledHeight(),
)
canvas.add(img);
canvas.renderAll();
);
// IMAGEM A SER RECORTADA
var scaleImage;
fabric.Image.fromURL(src, function(img)
img.selectable = false;
img.lockMovementX = true;
img.lockMovementY = true;
img.id = 'target';
img.borderColor = 'green';
img.scaleX = canvas.width / img.getScaledWidth();
img.scaleY = canvas.height / img.getScaledHeight();
scaleImage =
x: img.scaleX,
y: img.scaleY
;
canvas.add(img);
canvas.renderAll();
)
canvas.on('object:added', function(e)
target = null;
mask = null;
canvas.forEachObject(function(obj)
//alert(obj.get('id'));
var id = obj.get('id');
if (id === 'target')
target = obj;
canvas.setActiveObject(obj);
if (id === 'mask')
//alert(done);
//alert('mask');
mask = obj;
);
);
canvas.on('object:modified', function(e)
e.target.setCoords();
canvas.renderAll();
);
//////////////////////////////////////////////////////////
// MASK
//////////////////////////////////////////////////////////
function maskImage()
isInsertingCropRectangle = true;
canvas.discardActiveObject();
lastSelectedPicture.selectable = false;
lastSelectedPicture.setCoords();
lastSelectedPicture.dirty = true;
canvas.renderAll();
canvas.discardActiveObject();
isInsertingCropRectangle = true;
//////////////////////////////////////////////////////////
// CROP
//////////////////////////////////////////////////////////
function cropImage()
if (target !== null && mask !== null)
console.log("before", target);
console.log("beforemask", mask);
var topMask = mask.top
var leftMask = mask.left
target.top = topMask
target.left = leftMask
// Do the crop
target.cropX = leftMask / scaleImage.x
target.cropY = topMask / scaleImage.y
mask = rescaleMask(target, mask);
canvas.renderAll()
mask.setCoords()
canvas.renderAll()
target.width = mask.getScaledWidth()
target.height = mask.getScaledHeight()
target.dirty=true;
canvas.setActiveObject(target);
target.selectable = true;
target.lockMovementX = false;
target.lockMovementY = false;
canvas.bringToFront(target);
target.setCoords()
canvas.remove(mask)
canvas.renderAll();
//////////////////////////////////////////////////////////
// SET ICON CROP
//////////////////////////////////////////////////////////
function setIconCrop(action, img)
img.src = (action === 'crop') ? './assets/img/tesoura.svg' : './assets/img/crop.svg' ;
let actionCrop = 'mask';
document.getElementById("cropImage").addEventListener("click", function()
if (actionCrop === 'mask')
actionCrop = 'crop';
maskImage();
else if(actionCrop === 'crop')
actionCrop = 'mask';
cropImage();
setIconCrop(actionCrop, this);
);
//////////////////////////////////////////////////////////
// RE-SCALE MASK FOR CROPPING
//////////////////////////////////////////////////////////
function rescaleMask(target, mask)
mask.scaleX/=target.scaleX;
mask.scaleY/=target.scaleY;
var targetCenterX = target.width * target.scaleX / 2;
var targetCenterY = target.height * target.scaleY / 2;
var maskOverlapX = mask.left - target.left;
var maskOverlapY = mask.top - target.top;
var centerBasedX = maskOverlapX - targetCenterX;
var centerBasedY = maskOverlapY - targetCenterY;
if( maskOverlapX >= targetCenterX)
centerBasedX = (maskOverlapX - targetCenterX)/target.scaleX;
else
centerBasedX = (-(targetCenterX) + maskOverlapX)/target.scaleX;
if( maskOverlapY >= targetCenterY)
centerBasedY = (maskOverlapY - targetCenterY)/target.scaleY;
else
centerBasedY = (-(targetCenterY) + maskOverlapY)/target.scaleY;
mask.left = centerBasedX;
mask.top = centerBasedY;
mask.originX = 'left';
mask.originY = 'top';
mask.setCoords();
mask.dirty=true;
canvas.renderAll();
return mask;
canvas.on('mouse:down', function(o)
if( isInsertingCropRectangle == true )
if (done)
canvas.renderAll();
return;
isDown = true;
var pointer = canvas.getPointer(o.e);
console.log(pointer);
origX = pointer.x;
origY = pointer.y;
crop_rect = new fabric.Rect(
left: origX,
top: origY,
width: pointer.x - origX,
height: pointer.y - origY,
opacity: .3,
transparentCorners: false,
selectable: true,
id: 'mask',
borderColor: 'blue'
);
canvas.add(crop_rect);
canvas.renderAll();
);
canvas.on('mouse:move', function(o)
if( isInsertingCropRectangle == true )
if (done)
canvas.renderAll();
return;
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x)
crop_rect.set(
left: Math.abs(pointer.x)
);
if (origY > pointer.y)
crop_rect.set(
top: Math.abs(pointer.y)
);
crop_rect.set(
width: Math.abs(origX - pointer.x)
);
crop_rect.set(
height: Math.abs(origY - pointer.y)
);
crop_rect.setCoords();
canvas.renderAll();
);
canvas.on('mouse:up', function(o)
if( isInsertingCropRectangle == true )
if (done)
canvas.renderAll();
return;
isDown = false;
crop_rect.set(
selectable: true
);
done = true;
console.log(crop_rect);
else
);
canvas.on('selection:created', function(event)
selectionChanged(event);
);
canvas.on('selection:updated', function(event)
selectionChanged(event);
);
function selectionChanged(event)
switch(event.target.type)
case 'textbox':
break;
case 'image':
lastSelectedPicture = event.target;
break;
case 'rect':
break;
case 'group':
break;
default:
break;
【讨论】:
以上是关于当图像重新缩放以适合画布时,织物 js 上的裁剪功能无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章
我们如何在 php 中使用织物 Js 对画布上的图像执行相同的操作(缩放和旋转)?