Ваша главная проблема , вероятно , в том, что вы не учитываете масштабирование 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>