在Ionic 3应用程序上,getBoundingClientRect()的坐标已关闭

时间:2018-09-13 02:09:14

标签: ionic-framework html5-canvas ionic3

我正在编写Ionic 3应用程序以拍摄小照片。

我正在使用Camera Preview插件执行此操作:

camera preview

然后我使用以下方法获取绿色框的坐标:

<div id="mask" style="width:100%;height:100px;border:10px solid rgb(125, 255, 0);" *ngIf="!picture"> </div>

var box = document.getElementById("mask");
var rect = box.getBoundingClientRect();
console.log("MASK: "+rect.left+" "+rect.top+" "+rect.width+" "+rect.height)

然后我使用从包装盒中获得的坐标来裁剪图像以获取图像:

cropped image

我正在使用以下代码裁剪图像:

generateFromImage(img, x, y, w, h, quality: number = 1, callback) {
   var canvas: any = document.createElement("canvas");
   var image = new Image();
   image.src = img;

   image.onload = () => {
     canvas.width = w;
     canvas.height = h;
     var ctx = canvas.getContext("2d");

     ctx.drawImage(image, x+this.offsetX, y+this.offsetY, w*this.scaleX, h*this.scaleY, 0, 0, w, h);

     var dataUrl = canvas.toDataURL('image/jpeg', quality);

     callback(dataUrl)
   }

}

其中x,y,w,h是我从box.getBoundingClientRect()获得的坐标。

如您所见,我不得不引入offsetX,offsetY,scaleX,scaleY来调整坐标,因为它不起作用。

drawImage()参数是sx,sy,sw,sh(源框->来自原始图像的坐标)和x,y,w,h(目标->目标图像的坐标)。我不明白为什么它关闭了。

经过反复试验,我发现以下配置适用于我的iPhone 8:

  • offsetX = 125
  • offsetY = 48
  • scaleX = 1.7
  • scaleY = 1.4

我怀疑Y坐标差与应用程序工具栏有关。我不知道为什么x关闭,为什么在源和目标上使用相同的w和h不能保持宽高比。

我没有在其他设备上进行测试,但它肯定会失败,因为偏移量和比例因子会有所不同。

为什么会这样?为什么我需要固定坐标?

感谢您的帮助!

1 个答案:

答案 0 :(得分:3)

您的主要问题是可能,您没有考虑CSS缩放的问题。

我们在 drawImage 中使用的坐标是相对于图像的自然尺寸(即媒体之一,而不是的)。这意味着您不能直接从渲染的转换矩阵(getBoundingClientRect)到媒体的矩阵。
首先需要确定CSS已应用的比例,以便将屏幕空间坐标转换为媒体空间。

var img_bbox = img.getBoundingClientRect();
// the ratio by which our image has been scaled by CSS
var scale_x = img_bbox.width / img.naturalWidth;
var scale_y = img_bbox.height / img.naturalHeight;

// ...then
ctx.drawImage(img,
  rect.left / scale_x,
  rect.top / scale_y,
  rect.width/ scale_x,
  rect.height / scale_y,
  0,
  0,
  rect.width,
  rect.height
);

现在,您还必须考虑矩形位置和位置之间的差异,因此x实际上就是(rect_bbox.left - img_bbox.left) / scale_x

您还没有清除的一件事是,如果您想在边界内或边界外进行裁切,即边界本身是否应为裁切区域的一部分。

这是一个也包含边框区域的示例。

onload = crop;
function crop() {
   // get the rendered bounding box of our elements
  var r_bbox = rect.getBoundingClientRect();
  var img_bbox = img.getBoundingClientRect();
  // the ratio by which our image has been scaled by CSS
  var scale_x = img_bbox.width / img.naturalWidth;
  var scale_y = img_bbox.height / img.naturalHeight;
  // our output coords

  var output = {
    x: r_bbox.left - img_bbox.left,
    y: r_bbox.top - img_bbox.top,
    w: r_bbox.width,
    h: r_bbox.height
  };
  var ctx = canvas.getContext('2d');
  canvas.width = output.w;
  canvas.height = output.h;
  ctx.drawImage(img,
    // source
    // we need to scale all coords by the CSS scaling
    output.x / scale_x,
    output.y / scale_y,
    output.w / scale_x,
    output.h / scale_y,
    // destination, to rendered space, no scaling
    0,
    0,
    output.w,
    output.h
  );
}
img{
  width: 200px;
  height: 200px;
}
#rect{
  position:absolute;
  left: 42px;
  top: 50px;
  width: 100px;
  height: 50px;
  z-index: 2;
  border: 5px solid rgba(0,255,0,.5);
}

*{
  vertical-align: top;
}
<img id="img" src="https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg">
<div id="rect"></div>
<canvas id="canvas"></canvas>

只有边界区域内的东西

onload = crop;
function crop() {
  // get the rendered bounding box of our elements
  var r_bbox = rect.getBoundingClientRect();
  var img_bbox = img.getBoundingClientRect();
  // the ratio by which our image has been scaled by CSS
  var scale_x = img_bbox.width / img.naturalWidth;
  var scale_y = img_bbox.height / img.naturalHeight;
  // our output coords
  var output = {
    // rect.clientLeft is the size of the left border
    // so add it to 'x'
    x: r_bbox.left - img_bbox.left + rect.clientLeft,
    // same as for 'x'
    y: r_bbox.top - img_bbox.top + rect.clientTop,
    // size of padding box
    w: rect.clientWidth,
    h: rect.clientHeight
  };
  
  var ctx = canvas.getContext('2d');
  canvas.width = output.w;
  canvas.height = output.h;
  ctx.drawImage(img,
    output.x / scale_x,
    output.y / scale_y,
    output.w / scale_x,
    output.h / scale_y,
    0,
    0,
    output.w,
    output.h
  );
}
/* scale our image through CSS */
img{
  width: 200px;
  height: 200px;
}
#rect{
  position:absolute;
  left: 42px;
  top: 50px;
  width: 100px;
  height: 50px;
  z-index: 2;
  border: 5px solid rgba(255,0,0,.5);
  background: rgba(0,255,0,.5);
}

*{
  vertical-align: top;
}
<img id="img" src="https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg">
<div id="rect"></div>
<canvas id="canvas"></canvas>