KonvaJS裁剪并调整大小

时间:2018-04-12 13:37:50

标签: konvajs

我使用KonvaJS创建一个简单的图像编辑器。作为图像大小调整功能的基础,我使用了Konva示例中的代码(Knonva JS Image Resize)。但现在我正在努力实施作物功能。单击按钮,我允许用户在舞台上绘制一个矩形。然后,我使用绘制矩形的坐标,宽度和高度在图像上使用内置裁剪功能并裁剪图像。但是当我在裁剪之前调整图像大小时,裁剪区域会显示从原始大小的图像裁剪的部分。

是否有一种简单的,以遗传方式错过的能够从调整大小的图像进行裁剪?或者我是否必须根据图像的调整大小的值计算绘制矩形的位置和大小,然后裁剪该部分并调整大小并重新定位结果?

裁剪图片:

function cropImage(x, y, width, height, activeLayer) {
  var image = activeLayer.get('Image')[0], xDiff = 0, yDiff = 0, newWidth, newHeight, newX, newY;
  // only Crop visible Parts of the Image
  if(x  < activeLayer.getX()) {
      xDiff = activeLayer.getX() - x;
  }
  if(y  < activeLayer.getY()) {
      yDiff = activeLayer.getY() - y;
  }
  if (x + width > activeLayer.getX() + activeLayer.width()) {
      width = width - ((x + width) - (activeLayer.getX() + activeLayer.width()));
  }
  if (y + height > activeLayer.getY() + activeLayer.height()) {
      height = height - ((y + height) - (activeLayer.getY() + activeLayer.height()));
  }
  newHeight = height - yDiff;
  newWidth = width - xDiff;
  newX = (x - activeLayer.getX()) + image.cropX() + xDiff;
  newY = (y - activeLayer.getY()) + image.cropY() + yDiff;

  image.width(newWidth);
  image.height(newHeight);
  activeLayer.width(newWidth);
  activeLayer.height(newHeight);
  activeLayer.setX(newX + activeLayer.getX() - image.cropX());
  activeLayer.setY(newY + activeLayer.getY() - image.cropY());
  image.crop({
    x : newX ,
    y : newY ,
    width : newWidth,
    height : newHeight
  });
  //Reposition anchors so topLeft Anchor is always in 0/0 of the grouplayer
  repositionAnchors(activeLayer);
  activeLayer.draw();
}

2 个答案:

答案 0 :(得分:1)

调整大小时,我会保留数组中宽度和高度的比例,并计算为裁剪绘制的矩形的位置和尺寸:

cropX = ((x  / ratios[id].width) - (activeLayer.getX() / ratios[id].width)) + (image.cropX()) + (xDiff / ratios[id].width);
cropY = ((y  / ratios[id].height)- (activeLayer.getY() / ratios[id].height)) + (image.cropY()) + (yDiff / ratios[id].height);
cropWidth = (width / ratios[id].width)  - (xDiff / ratios[id].width),
cropHeight = (height / ratios[id].height) - (yDiff / ratios[id].height)

答案 1 :(得分:1)

这还不是你问题的准确答案,但我在这里包括,因为它可能为你或同一领域的其他人提供裁剪方式。

全屏运行代码段。

左图是Konva,右图是原始图像。

单击左侧图像以进行选择。左图像仅更改为选择,而右图显示裁剪的位置。重复这个过程,看看作物是如何积累的。

在此示例中,我没有在画布上缩放图像,因此它不是目前您的需求的精确答案,但对于可视化正在发生的事情非常有用。如果人们认为它有用,我可以添加缩放。

// Useful frequently used variables.
var sX = 0, sY = 0, sW = 400, sH = 200; // drawing dimensions 
var iW = 0, iH = 0; // image dimensions
var cropRect = {x: sX, y: sY, width: iW, height: iH}; // scaled rect
var imgRect = $('.imgRect');
var imgPtr = $('#imgPtr');
var scale = 1;
var img = $('#daImg'); 
var src = "https://dummyimage.com/400x200/e85de8/fff&text=SO Rocks!"
$('.container').css({width: sW, height: sH});

// Vars for mouse rect work.
var posStart, posNow, mode = '';

// Set up add a stage & layer
var s1 = new Konva.Stage({container: 'container', width: sW, height: sH});
var l1 = new Konva.Layer({});
s1.add(l1);
var image = new Konva.Image({})  // prepare an image to display the picture.
l1.add(image);

// I use a foreground rect to catch events - this covers the konva image completely - you can wire your events in your own way
var r1 = new Konva.Rect({x: 0, y: 0, width: sW, height: sH, fill: 'gold', opacity: 0 })    
l1.add(r1)

// draw a rectangle to be used as the rubber-band area
var r2 = new Konva.Rect({x: 0, y: 0, width: 0, height: 0, stroke: 'red', dash: [2,2]})    
r2.listening(false); // stop r2 catching our mouse events otherwise if we reverse mouse direction events may not fire
l1.add(r2)

// Mouse movement funcs
function startDrag(posIn){
  posStart = {x: posIn.x, y: posIn.y};
  posNow = {x: posIn.x, y: posIn.y};
}

// update rubber rect position
function updateDrag(posIn){ 
  posNow = {x: posIn.x, y: posIn.y};
  var posRect = reverse(posStart,posNow);
  r2.x(posRect.x1);
  r2.y(posRect.y1);
  r2.width(posRect.x2 - posRect.x1);
  r2.height(posRect.y2 - posRect.y1);
  r2.visible(true);     
  s1.draw(); // redraw any changes.
  
  sayRect(r2);
  showImgRect(r2);   
}

// start the rubber rect drawing on mouse down.
r1.on('mousedown', function(e){ 
  mode = 'drawing';
  startDrag({x: e.evt.layerX, y: e.evt.layerY})
  })

// update the rubber rect on mouse move - note use of 'mode' var to avoid drawing after mouse released.
r1.on('mousemove', function(e){ 
    if (mode === 'drawing'){
      updateDrag({x: e.evt.layerX, y: e.evt.layerY})
    }
  showImgPtr(e.evt.layerX, e.evt.layerY);
  sayPos(e.evt.layerX, e.evt.layerY);  
})

// When user releases the mouse we note the size and modify the clip rect.
r1.on('mouseup', function(e){ 
    mode = '';
    r2.visible(false);

	// leave a rect to show the target
    imgRect.hide();
    var imgRect2 = imgRect.clone();
    imgRect2
        .appendTo('#container2')
        .addClass('deleteMe')
        .show();
  
    setCrop(r2);
    sayInfo(img, image);

})

// Draw a rect on the original image to show location and size. Just using some simple jquery to manipulate a div.
function showImgRect(r){
  imgRect.css({
    left: r.x() + cropRect.x,
    top: r.y() + cropRect.y,
    width: r.width() * 1,
    height: r.height() * 1
  })
imgRect.show();  
}

// show a mouse pointer on the original image so we get a sense of what is going on
function showImgPtr(x, y){
  imgPtr.css({  left: cropRect.x + x, top: cropRect.y + y})
}

// Set the new crop rect, taking account of previous crops
function setCrop(r){
  
  image.cropX(r.x() + cropRect.x);
  image.cropY(r.y()  + cropRect.y);
  image.cropWidth(r.width() * scale);
  image.cropHeight(r.height() * scale);
  
  image.width(r.width());
  image.height(r.height());
  l1.draw();
      
  cropRect = {x: cropRect.x + r.x(), y: cropRect.y + r.y(), width: r.width(), height: r.height()};
}


// This event listener is fired when the image is loaded - could be a few secs delay for a big image
// so this is effectively an async technique.
img.on('load', function() {
  // note the dimensions
  iW = img.width();
  iH = img.height();

  // set the konva image details
  image.x(sX);
  image.y(sY);
  image.width(iW);
  image.height(iH);
  image.image(img[0]);

  sayInfo(img, image);
  
  l1.draw(); // redraw the layer to see what happened
});

// This innocent looking line intiates the image load and ultimately fires the event above.
img.prop('src', src);

/*
From here down is utility stuff
*/


// Say something useful
function sayInfo(img, image){
  $('#imgInfo').html("HTML Image size " + img.width() + " x " + img.height());
  $('#imageInfo').html("Konva.image " + image.x() + ", " + image.y() + " - " + image.width() + " x " + image.height());
  var info = $('#info');
}
function sayRect(r){
  var rectInfo = $('#rectInfo');
  rectInfo.html("Clip rect on canvas " + r.x() + ", " + r.y() + " - " + r.width() + " x " + r.height());
}

function sayPos(x, y){
  var posInfo = $('#posInfo');
  posInfo.html("Pos on stage " + x + ", " + y);
}



// This is just to reverse co-ords if user drags left / up
function reverse(r1, r2){
  var r1x = r1.x, r1y = r1.y, r2x = r2.x,  r2y = r2.y, d;
  if (r1x > r2x ){
    d = Math.abs(r1x - r2x);
    r1x = r2x; r2x = r1x + d;
  }
  if (r1y > r2y ){
    d = Math.abs(r1y - r2y);
    r1y = r2y; r2y = r1y + d;
  }
    return ({x1: r1x, y1: r1y, x2: r2x, y2: r2y}); // return the corrected rect.     
}


// reset function
function reset(){
  sX = 0; sY = 0; sW = 400; sH = 300; // drawing dimensions 
  iW = 0; iH = 0; // image dimensions
  iW = img.width();
  iH = img.height();
  cropRect = {x: sX, y: sY, width: iW, height: iH}; // scaled rect
  scale = 1;
  if (image){
    console.log('iH=' +iH);
    
    image.x(sX);
    image.y(sY);
    image.width(iW);
    image.height(iH);
    image.cropX(sX);
    image.cropY(sY);
    image.cropWidth(iW);
    image.cropHeight(iH);
  }
  $('.deleteMe').remove();
  $('.imgRect').hide();
  l1.draw();
}
$('#reset').on('click', function(){reset()});
p
{
  padding: 5px;
  
}
.container {
  position: relative;
  display: inline-block; 
  width: 500px; 
  height: 400px; 
  background-color: transparent; 
  overflow: hidden; 
  border: 1px solid silver;
}
.imgRect {
  position: absolute; 
  border: 1px dotted red;
  background-color: Aqua;
  opacity: 0.3;
}
#imgPtr {
  position: absolute; 
  background-color: red;
  width: 1px;
  height: 1px;
  border-radius: 50%;
  border: 2px solid red;
}
a {
  color: red;
  cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<p>
  <span id='text'>How crop rect relates to original image. First image is the Konva stage, second is the original image. Use click and drag to draw successive rects on the Konva image.</span> <a id='reset'>Reset</a> 
</p>
<p>
  <span id='imgInfo'></span><br />
  <span id='imageInfo'></span>
  <span id='rectInfo'>Rect info </span><br/>
  <span id='posInfo'>Pos on stage </span><br/>
  <span id='scaleInfo'>Scale 1:1 </span>

</p>

<div id='container' class='container'></div>
<div id='container2' class='container'>
  <img id='daImg' />
  <div class='imgRect'></div>  
  <div id='imgPtr'></div>  
</div>