Правильные преобразования для масштабирования изображения

Я пишу приложение для Android (хотя я думаю, что это общий вопрос), и мне нужно отобразить большое изображение (в ImageView), которое можно прокручивать и масштабировать. Мне удалось заставить прокрутку работать, фиксируя события касания и выполняя матричные преобразования, и теперь я работаю над масштабированием.

Если я просто применяю преобразование масштаба к изображению, оно увеличивается в начале координат, то есть в верхнем левом углу экрана. Я хотел бы увеличить масштаб в центре экрана. Из того, что я прочитал, это означает, что мне нужно преобразование, чтобы сделать начало координат центром экрана. Я думаю, что требуется что-то вроде следующего: предположим, что центр экрана равен (5, 5) для простоты...

-Translate by (-5, -5)
-Scale by the zoom factor
-Translate by (+5, +5)*zoomfactor

К сожалению, это, похоже, не работает - зум, кажется, идет куда угодно, КРОМЕ центра... может ли кто-нибудь помочь мне здесь?

РЕДАКТИРОВАТЬ: это код, который теперь работает

    Matrix zoommatrix = new Matrix();
    float[] centerpoint = {targetimageview.getWidth()/2.0f, targetimageview.getHeight()/2.0f};

    zoommatrix.postScale(zoomfactor, zoomfactor, centerpoint[0], centerpoint[1]);
    zoommatrix.preConcat(targetimageview.getImageMatrix());

    targetimageview.setImageMatrix(zoommatrix);
    targetimageview.invalidate();

person KJ Tsanaktsidis    schedule 29.01.2010    source источник
comment
Вы можете опубликовать свой код преобразования?   -  person AGrunewald    schedule 29.01.2010


Ответы (1)


Проверьте ImageViewTouchBase в приложении Camera исходного кода Android; его метод zoomTo делает следующее:

protected void zoomTo(float scale, float centerX, float centerY) {
    if (scale > mMaxZoom) {
        scale = mMaxZoom;
    }

    float oldScale = getScale();
    float deltaScale = scale / oldScale;

    mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY);
    setImageMatrix(getImageViewMatrix());
    center(true, true);
}

Этот центральный метод, вероятно, вас действительно волнует:

    protected void center(boolean horizontal, boolean vertical) {
    if (mBitmapDisplayed.getBitmap() == null) {
        return;
    }

    Matrix m = getImageViewMatrix();

    RectF rect = new RectF(0, 0,
            mBitmapDisplayed.getBitmap().getWidth(),
            mBitmapDisplayed.getBitmap().getHeight());

    m.mapRect(rect);

    float height = rect.height();
    float width  = rect.width();

    float deltaX = 0, deltaY = 0;

    if (vertical) {
        int viewHeight = getHeight();
        if (height < viewHeight) {
            deltaY = (viewHeight - height) / 2 - rect.top;
        } else if (rect.top > 0) {
            deltaY = -rect.top;
        } else if (rect.bottom < viewHeight) {
            deltaY = getHeight() - rect.bottom;
        }
    }

    if (horizontal) {
        int viewWidth = getWidth();
        if (width < viewWidth) {
            deltaX = (viewWidth - width) / 2 - rect.left;
        } else if (rect.left > 0) {
            deltaX = -rect.left;
        } else if (rect.right < viewWidth) {
            deltaX = viewWidth - rect.right;
        }
    }

    postTranslate(deltaX, deltaY);
    setImageMatrix(getImageViewMatrix());
}
person Yoni Samlan    schedule 29.01.2010
comment
Отлично! Что мне нужно, так это перегрузка postScale(), которая принимает точку, а также масштаб, лол. Теперь код масштабирования выглядит так... Хорошо, он не подходит, я отредактирую свой вопрос, чтобы включить его. Все, что было нужно, это умножить текущую матрицу преобразования на матрицу, сгенерированную четырехаргументной формой scale(). - person KJ Tsanaktsidis; 30.01.2010