Координаты из getBoundingClientRect () отключены в приложении Ionic 3 - PullRequest
0 голосов
/ 13 сентября 2018

Я пишу приложение 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

Я подозреваю, что разница координат Y как-то связана с панелью инструментов приложения. Я понятия не имею, почему x выключен и почему использование одинаковых w и h для источника и получателя не сохраняет соотношение сторон.

Я не тестировал на других устройствах, но он наверняка потерпит неудачу, потому что смещения и коэффициенты масштабирования будут другими.

Почему это происходит? Почему мне нужно исправить координаты?

Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 20 сентября 2018

Ваша главная проблема , вероятно , в том, что вы не учитываете масштабирование CSS.

Координаты, которые мы используем в drawImage , относятся к естественному размеру изображения (т. Е. К одному из носителей, а не к image).Это означает, что вы не можете напрямую перейти от визуализированной матрицы преобразования (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
);

Теперь вам также нужно будет учесть разницу между положением вашего прямоугольника и положением вашего image, поэтому, например, 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>
...