android 在缩放和平移后从扩展图像视图中获取实际图像坐标
android get actual image coordinates from an extended imageview after zoom and pan
在用户在图像上的 canvas 上绘制矩形后,我正在尝试检索图像的真实坐标。为此,我使用了 LayerDrawable,将位图图像作为底层。不幸的是,我的解决方案仅在比例因子为 1(未执行缩放)时有效。如果用户使用当前解决方案稍微缩放和平移,我会接近坐标,但有些不对劲并且它们不准确。因为我无法 post 此处的全部代码,所以我已将其上传到 pastebin (link). I also do a little bit of preprocessing and scale the image exactly so it fits the available size of my extended ImageView. For that i use a ViewTreeObserver and on the predraw method I find out exactly how much space i have available and scale the image to that size, so it fits the bigger dimension and the aspect ratio is kept. The code for it is here (link)。
最重要的部分是:
private void fixCoordinates(){
//get utmost left,right,top,bottom corners from both begin and end coordinate
float left = Math.min(beginCoordinate.x, endCoordinate.x);
float top = Math.min(beginCoordinate.y, endCoordinate.y);
float right = Math.max(beginCoordinate.x, endCoordinate.x);
float bottom = Math.max(beginCoordinate.y, endCoordinate.y);
//reassign them to proper begin and end
PointF b = new PointF(left,top);
PointF e = new PointF(right,bottom);
//m[5] and m[2] denote offsets (empty spaces) when they are positive
if(m[2] > 0){
b.x = b.x - m[2];
e.x = e.x - m[2];
}
if(m[5] > 0){
b.y = b.y - m[5];
e.y = e.y - m[5];
}
//safety
if(b.x < 0){
b.x = 0;
}
if(b.y < 0){
b.y = 0;
}
if(e.x > layers[0].getIntrinsicWidth()){
e.x = layers[0].getIntrinsicWidth();
}
if(e.y > layers[0].getIntrinsicHeight()){
e.y = layers[0].getIntrinsicHeight();
}
//we only have one scale factor, because in the preprocessing we rescale and fit the image
setBeginCoordinate(b);
setEndCoordinate(e);
}
在 MotionEvent 之后,我使用此函数将开始坐标设置为最大顶部和左侧,将结束坐标设置为底部和右侧。
到原始图像的实际映射在这里完成:
private PointF mapBeginCoordinates(PointF beginCoordinate, PointF endCoordinate){
float left = Math.min(beginCoordinate.x, endCoordinate.x);
float top = Math.min(beginCoordinate.y, endCoordinate.y);
double wAr = UtilFunctions.getAspectRatio(getOriginalWidth(), layers[0].getIntrinsicWidth());
double hAr = UtilFunctions.getAspectRatio(getOriginalHeight(), layers[0].getIntrinsicHeight());
left = (float)((double)left/wAr);
top = (float)((double)top/hAr);
float[] imageMatrix = new float[9];
getImageMatrix().getValues(imageMatrix);
float scaleFactorX = imageMatrix[Matrix.MSCALE_X];
float scaleFactorY = imageMatrix[Matrix.MSCALE_Y];
float fixedTransX = 1;
float fixedTransY = 1;
//m[5] height m[2] width
if(m[2] < 0){
fixedTransX = (m[2]*scaleFactorX);
}
if(m[5] < 0){
fixedTransY = (m[5]*scaleFactorY);
}
left = left/scaleFactorX + Math.abs(fixedTransX);
top = top/scaleFactorY + Math.abs(fixedTransY);
return new PointF(left,top);
}
结束坐标的代码相同。 pastebin 中的代码有点乱,因为我已经尝试了 2 天的许多不同的东西来让它工作,但有些东西让我望而却步。我将不胜感激任何帮助。
我设法通过使用 Mike Ortiz TouchImageView
解决了我的问题
我用来将坐标映射到原始位图的代码是这样的:
private PointF mapBeginCoordinates(PointF beginCoordinate, PointF endCoordinate) {
//TODO we only have one aspect ratio for the current picture, so we should remove redundancy
float left = Math.min(beginCoordinate.x, endCoordinate.x);
float top = Math.min(beginCoordinate.y, endCoordinate.y);
double wAr = UtilFunctions.getAspectRatio(originalWidth, layers[0].getIntrinsicWidth());
double hAr = UtilFunctions.getAspectRatio(originalHeight, layers[0].getIntrinsicHeight());
if(!isZoomed()) {
left = (float) (left / wAr);
top = (float) (top / hAr);
}
if(isZoomed()) {
PointF b = transformCoordTouchToBitmap(left,top,true);
left = (float) (b.x / wAr);
top = (float) (b.y / hAr);
}
return new PointF(left,top);
}
我仍然使用上面的 fixcoordinates 代码来准备我的 left/top - right/bottom 位置。感谢您的回答
在用户在图像上的 canvas 上绘制矩形后,我正在尝试检索图像的真实坐标。为此,我使用了 LayerDrawable,将位图图像作为底层。不幸的是,我的解决方案仅在比例因子为 1(未执行缩放)时有效。如果用户使用当前解决方案稍微缩放和平移,我会接近坐标,但有些不对劲并且它们不准确。因为我无法 post 此处的全部代码,所以我已将其上传到 pastebin (link). I also do a little bit of preprocessing and scale the image exactly so it fits the available size of my extended ImageView. For that i use a ViewTreeObserver and on the predraw method I find out exactly how much space i have available and scale the image to that size, so it fits the bigger dimension and the aspect ratio is kept. The code for it is here (link)。
最重要的部分是:
private void fixCoordinates(){
//get utmost left,right,top,bottom corners from both begin and end coordinate
float left = Math.min(beginCoordinate.x, endCoordinate.x);
float top = Math.min(beginCoordinate.y, endCoordinate.y);
float right = Math.max(beginCoordinate.x, endCoordinate.x);
float bottom = Math.max(beginCoordinate.y, endCoordinate.y);
//reassign them to proper begin and end
PointF b = new PointF(left,top);
PointF e = new PointF(right,bottom);
//m[5] and m[2] denote offsets (empty spaces) when they are positive
if(m[2] > 0){
b.x = b.x - m[2];
e.x = e.x - m[2];
}
if(m[5] > 0){
b.y = b.y - m[5];
e.y = e.y - m[5];
}
//safety
if(b.x < 0){
b.x = 0;
}
if(b.y < 0){
b.y = 0;
}
if(e.x > layers[0].getIntrinsicWidth()){
e.x = layers[0].getIntrinsicWidth();
}
if(e.y > layers[0].getIntrinsicHeight()){
e.y = layers[0].getIntrinsicHeight();
}
//we only have one scale factor, because in the preprocessing we rescale and fit the image
setBeginCoordinate(b);
setEndCoordinate(e);
}
在 MotionEvent 之后,我使用此函数将开始坐标设置为最大顶部和左侧,将结束坐标设置为底部和右侧。
到原始图像的实际映射在这里完成:
private PointF mapBeginCoordinates(PointF beginCoordinate, PointF endCoordinate){
float left = Math.min(beginCoordinate.x, endCoordinate.x);
float top = Math.min(beginCoordinate.y, endCoordinate.y);
double wAr = UtilFunctions.getAspectRatio(getOriginalWidth(), layers[0].getIntrinsicWidth());
double hAr = UtilFunctions.getAspectRatio(getOriginalHeight(), layers[0].getIntrinsicHeight());
left = (float)((double)left/wAr);
top = (float)((double)top/hAr);
float[] imageMatrix = new float[9];
getImageMatrix().getValues(imageMatrix);
float scaleFactorX = imageMatrix[Matrix.MSCALE_X];
float scaleFactorY = imageMatrix[Matrix.MSCALE_Y];
float fixedTransX = 1;
float fixedTransY = 1;
//m[5] height m[2] width
if(m[2] < 0){
fixedTransX = (m[2]*scaleFactorX);
}
if(m[5] < 0){
fixedTransY = (m[5]*scaleFactorY);
}
left = left/scaleFactorX + Math.abs(fixedTransX);
top = top/scaleFactorY + Math.abs(fixedTransY);
return new PointF(left,top);
}
结束坐标的代码相同。 pastebin 中的代码有点乱,因为我已经尝试了 2 天的许多不同的东西来让它工作,但有些东西让我望而却步。我将不胜感激任何帮助。
我设法通过使用 Mike Ortiz TouchImageView
解决了我的问题我用来将坐标映射到原始位图的代码是这样的:
private PointF mapBeginCoordinates(PointF beginCoordinate, PointF endCoordinate) {
//TODO we only have one aspect ratio for the current picture, so we should remove redundancy
float left = Math.min(beginCoordinate.x, endCoordinate.x);
float top = Math.min(beginCoordinate.y, endCoordinate.y);
double wAr = UtilFunctions.getAspectRatio(originalWidth, layers[0].getIntrinsicWidth());
double hAr = UtilFunctions.getAspectRatio(originalHeight, layers[0].getIntrinsicHeight());
if(!isZoomed()) {
left = (float) (left / wAr);
top = (float) (top / hAr);
}
if(isZoomed()) {
PointF b = transformCoordTouchToBitmap(left,top,true);
left = (float) (b.x / wAr);
top = (float) (b.y / hAr);
}
return new PointF(left,top);
}
我仍然使用上面的 fixcoordinates 代码来准备我的 left/top - right/bottom 位置。感谢您的回答