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 位置。感谢您的回答