Масштаб матрицы для просмотра изображений Android перевод

#android #matrix #imageview #transformation

#Android #матрица #просмотр изображений #преобразование

Вопрос:

Я пытаюсь вручную поместить изображение внутри imageview по центру и подогнать под экран. Мне нужно сделать это с помощью матрицы (позже я буду динамически изменять преобразование матрицы).

Проблема в том, что я не могу расположить изображение по центру в представлении (масштаб соответствующий). Вот код:

 // Compute the scale to choose (this works)
float scaleX = (float) displayWidth / (float) imageWidth;
float scaleY = (float) displayHeight / (float) imageHeight;
float minScale = Math.min(scaleX, scaleY);

// tx, ty should be the translation to take the image back to the screen center
float tx = Math.max(0, 
        0.5f * ((float) displayWidth - (minScale * imageWidth)));
float ty = Math.max(0, 
        0.5f * ((float) displayHeight - (minScale * imageHeight)));

// Compute the matrix
Matrix m = new Matrix();
m.reset();

// Middle of the image should be the scale pivot
m.postScale(minScale, imageWidth/2, imageHeight/2);

// Translate
m.postTranslate(tx, ty);

imageView.setImageMatrix(m);
  

Приведенный выше код работает, если я не центрирую масштаб по центру изображения (но мне нужно будет сделать это позже, поэтому мне нужно выяснить формулу сейчас).

Я думал, что выполнение следующего исправит проблему, но изображение по-прежнему смещено (в сторону нижнего и правого).

 tx  = 0.5*imageWidth*minScale;
ty  = 0.5*imageHeight*minScale;
  

Некоторые значения, которые у меня есть:
— изображение: 200×133
— дисплей: 800×480
— Минимальный масштаб: 2.4
— конечный верхний левый угол изображения: 100, 67 (должно быть 17, 0)

Комментарии:

1. Здравствуйте, у меня такое же требование. не могли бы вы, пожалуйста, поделиться со мной примером здесь. Это сэкономило бы мое время.

Ответ №1:

Здесь вам поможет удобный метод, который называется Matrix.setRectToRect(RectF, RectF, ScaleToFit).

 Matrix m = imageView.getImageMatrix();
RectF drawableRect = new RectF(0, 0, imageWidth, imageHeight);
RectF viewRect = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());
m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);
imageView.setImageMatrix(m);
  

Это должно настроить матрицу m так, чтобы она имела комбинацию значений масштабирования и перевода, которая необходима для отображения отрисовываемого объекта по центру и его размещения в виджете ImageView.

Комментарии:

1. Спасибо, тем временем я решил проблему с помощью комбинации матриц. 1 за то, что заставил меня обратить внимание на эту полезную функцию.

2. Не хотите поделиться своим решением? У меня есть угловой случай, когда комбинация матриц может оказаться полезной.

3. Изображение @joakime не отображается. Затем, когда я коснусь изображения один раз, оно отобразится, но не по центру и не подогнано к его виду. Я использую TouchImageView (исходный код здесь github.com/gabu/AndroidSDK-RecipeBook/blob/master/Recipe060/src /… )

4. @joakime, чем вы заменяете «ширину изображения» и «Высоту изображения» (строка 2 в вашем комментарии выше)? У меня сейчас точно такая же проблема, но я застрял на этой части. Спасибо за вашу помощь!

5. Будьте осторожны с вышесказанным, в документах getImageMatrix() указано «Не меняйте эту матрицу на месте. Если вы хотите, чтобы к отображаемому объекту была применена другая матрица, обязательно вызовите setImageMatrix()». Однако setImageMatrix() выполняет проверку и не делает представление недействительным, если локальная матрица mMatrix.равна (переданная матрица). Следовательно, я бы рекомендовал: Matrix m = new Matrix(); m.reset(); в данном случае вместо getImageMatrix().

Ответ №2:

Вот как я решил свою проблему, используя матрицы (запрошенные joakime в другом ответе):

 private void setImageTransformation(float tx, float ty, float scale) {
    savedMatrix.reset();
    savedMatrix.postTranslate(-imageWidth / 2f, -imageHeight / 2f);
    savedMatrix.postScale(scale, scale);
    savedMatrix.postTranslate(tx, ty);
    imageView.setImageMatrix(savedMatrix);
}

public void resetImageMatrix() {
    if (!isImageLoaded()) return;

    imageWidth = imageView.getDrawable().getIntrinsicWidth();
    imageHeight = imageView.getDrawable().getIntrinsicHeight();

    float scaleX = (float) displayWidth / (float) imageWidth;
    float scaleY = (float) displayHeight / (float) imageHeight;
    minScale = Math.min(scaleX, scaleY);
    maxScale = 2.5f * minScale;

    initialTranslation.set(
              Math.max(0, 
                minScale * imageWidth / 2f 
                  0.5f * (displayWidth - (minScale * imageWidth))), 
              Math.max(0, 
                minScale * imageHeight / 2f
                  0.5f * (displayHeight - (minScale * imageHeight))));

    currentScale = minScale;
    currentTranslation.set(initialTranslation);
    initialImageRect.set(0, 0, imageWidth, imageHeight);

    setImageTransformation(initialTranslation.x, initialTranslation.y, 
                minScale);
}
  

Я здесь немного жульничаю, потому что щепотка на самом деле не центрирована между пальцами пользователя, что приемлемо в моем случае.

Комментарии:

1. что такое initialTranslation, savedMatrix, displayWidth, displayHeight?

2. initialTranslation и savedMatrix являются просто повторно используемыми Matrix экземплярами. Код не зависит от их состояния, потому что он полностью сбрасывает его перед чтением. displayWidth/Height — это размеры целевого окна, в которое должно быть помещено изображение.

Ответ №3:

Или с помощью

     m.postScale(minScale, minScale); //keep aspect ratio

    float tx = (getWidth() - bitmap1.getWidth()* scale) * 0.5f ;
    float ty = (getHeight() - bitmap1.getHeight()* scale) * 0.5f ;

    matrix.postTranslate(tx, ty );
  

где getWidth — это ширина вашего изображения.
У меня отлично работает

Ответ №4:

Эй, у меня была такая же проблема, и вы были так близки к этому! Это была проблема порядка операций, по крайней мере, для меня. У меня сработало следующее:

 tx = (width - imgWidth) * 0.5f * scale;