Android: как повернуть растровое изображение в центральной точке

84

Я больше суток искал решение этой проблемы, но ничего не помогает, даже ответы здесь. Документация тоже ничего не объясняет.

Я просто пытаюсь получить вращение в направлении другого объекта. Проблема в том, что растровое изображение вращается не вокруг фиксированной точки, а вокруг растрового изображения (0,0).

Вот код, с которым у меня проблемы:

  Matrix mtx = new Matrix();
  mtx.reset();
  mtx.preTranslate(-centerX, -centerY);
  mtx.setRotate((float)direction, -centerX, -centerY);
  mtx.postTranslate(pivotX, pivotY);
  Bitmap rotatedBMP = Bitmap.createBitmap(bitmap, 0, 0, spriteWidth, spriteHeight, mtx, true);
  this.bitmap = rotatedBMP;

Странная часть заключается в том, что не имеет значения, как я меняю значения в pre/ postTranslate()и аргументы с плавающей запятой setRotation(). Может ли кто-нибудь помочь и подтолкнуть меня в правильном направлении? :)

Стефан
источник
1
Я так понимаю, что приведенный выше код получен после нескольких попыток изменения. Похоже, что mtx.setRotate (dir, x, y) должен делать трюк сам по себе, без всяких пре / постов. Кроме того, вам не нужно сбрасывать только что newотредактированную матрицу. Это уже личность.
Марк Сторер

Ответы:

101

Надеюсь, вам поможет следующая последовательность кода:

Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight, config);
Canvas canvas = new Canvas(targetBitmap);
Matrix matrix = new Matrix();
matrix.setRotate(mRotation,source.getWidth()/2,source.getHeight()/2);
canvas.drawBitmap(source, matrix, new Paint());

Если вы проверите следующий метод из ~frameworks\base\graphics\java\android\graphics\Bitmap.java

public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
        Matrix m, boolean filter)

это объяснило бы, что он делает с вращением и переводом.

Судар Нималан
источник
1
Можете ли вы сделать это с помощью Bitmap.createBitmap, который принимает матрицу? Как вы вычисляете targetWidth и targetHeight? Я полагаю, что это простой триггер, но есть ли более простой способ?
Пожалуйста, проверьте ответ ниже (извините, я не смог добавить код в комментарии)
Судар Нималан
качество ухудшается при применении этого. любое решение?
MSaudi
1
изменить canvas.drawBitmap (источник, матрица, новый Paint ()); с canvas.drawBitmap (источник, матрица, новая краска (Paint.ANTI_ALIAS_FLAG));
Судар Нималан
3
Просто отметим, что этот процесс очень требует памяти и не должен использоваться в пошаговых методах.
MLProgrammer-CiM 02
79

Отредактировано : оптимизированный код.

public static Bitmap RotateBitmap(Bitmap source, float angle)
{
      Matrix matrix = new Matrix();
      matrix.postRotate(angle);
      return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}

Чтобы получить Bitmap из ресурсов:

Bitmap source = BitmapFactory.decodeResource(this.getResources(), R.drawable.your_img);
Арвис
источник
Попробуйте это для поворота растрового изображения с любым w или h: Matrix matrix = new Matrix (); matrix.postRotate (90); bitmapPicture = Bitmap.createBitmap (bitmapPicture, 0, 0, bitmapPicture.getWidth (), bitmapPicture.getHeight (), matrix, true);
Марк Молина
У меня это отлично сработало, поскольку я устанавливаю параметры для точек изображения. Вам просто нужно обязательно использовать матрицу при рисовании растрового изображения на холсте.
a54studio
6
Вы уверены, что это эффективно? Если бы RotateBitmap () был в цикле, выполнявшемся N раз, в зависимости от разрешения растрового изображения вы могли бы впустую тратить огромный объем памяти, а также все эти новые выделения объектов Matrix.
Ryhan
Не тестировалось, но в документации говорится: «Если исходное растровое изображение неизменяемо и запрошенное подмножество совпадает с самим исходным растровым изображением, тогда исходное растровое изображение возвращается, а новое растровое изображение не создается». Что касается объекта Matrix, это просто класс преобразования координат. Вы можете свободно оптимизировать код для повторения и использовать один и тот же объект Matrix в циклах.
Arvis
К вашему сведению, растровое изображение должно быть изменяемым
kip2
25

Я вернулся к этой проблеме сейчас, когда мы дорабатываем игру, и я просто подумал опубликовать то, что сработало для меня.

Это метод вращения Матрицы:

this.matrix.reset();
this.matrix.setTranslate(this.floatXpos, this.floatYpos);
this.matrix.postRotate((float)this.direction, this.getCenterX(), this.getCenterY()); 

( this.getCenterX()в основном это позиция X растрового изображения + ширина растрового изображения / 2)

И метод рисования растрового изображения (вызываемый через RenderManagerкласс):

canvas.drawBitmap(this.bitmap, this.matrix, null);

Так что это довольно прямолинейно, но мне немного странно, что я не мог заставить его работать, setRotateа затем следовало postTranslate. Может кто знает, почему это не работает? Теперь все растровые изображения вращаются правильно, но не без незначительного снижения качества растровых изображений: /

В любом случае, спасибо за вашу помощь!

Ste
источник
Предыдущий код ответа также работает. с той же проблемой качества.
MSaudi
7

Вы также можете повернуть, ImageViewиспользуя RotateAnimation:

RotateAnimation rotateAnimation = new RotateAnimation(from, to,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setDuration(ANIMATION_DURATION);
rotateAnimation.setFillAfter(true);

imageView.startAnimation(rotateAnimation);
Макарс
источник
4
Вы отвечаете не на тот вопрос. Он не хочет поворачивать представление, только одно растровое изображение внутри него.
Марк Сторер
Как я испытал, метод setFillAfter (bool) не работает так, как ожидалось, в Android API 11 уровня и ниже. Следовательно, разработчики не могут использовать событие непрерывного вращения для объектов представления, а также не могут получить повернутые версии этих представлений после поворота. Итак, @Mark Storer, Macarse ответил правдиво с логической точки зрения, если вы установите продолжительность анимации равной 0 или что-то близкое к 0.
Gökhan Barış Aker
5

Вы можете использовать что-то вроде следующего:


Matrix matrix = new Matrix();
matrix.setRotate(mRotation,source.getWidth()/2,source.getHeight()/2);
RectF rectF = new RectF(0, 0, source.getWidth(), source.getHeight());
matrix.mapRect(rectF);
Bitmap targetBitmap = Bitmap.createBitmap(rectF.width(), rectF.height(), config);
Canvas canvas = new Canvas(targetBitmap);
canvas.drawBitmap(source, matrix, new Paint());

Судар Нималан
источник
одна и та
изменить canvas.drawBitmap (источник, матрица, новый Paint ()); с canvas.drawBitmap (источник, матрица, новая краска (Paint.ANTI_ALIAS_FLAG));
Судар Нималан
какую конфигурацию вы используете?
Судар Нималан
В качестве ответа я разместил приведенный ниже код. не мог написать это в комментарии. Большое спасибо, сэр :)
MSaudi
1

Я использовал эти конфигурации, но проблема с пикселизацией все еще не устранена:

Bitmap bmpOriginal = BitmapFactory.decodeResource(this.getResources(), R.drawable.map_pin);
        Bitmap targetBitmap = Bitmap.createBitmap((bmpOriginal.getWidth()),
                (bmpOriginal.getHeight()), 
                Bitmap.Config.ARGB_8888);
        Paint p = new Paint();
        p.setAntiAlias(true);

        Matrix matrix = new Matrix();       
        matrix.setRotate((float) lock.getDirection(),(float) (bmpOriginal.getWidth()/2),
                (float)(bmpOriginal.getHeight()/2));

        RectF rectF = new RectF(0, 0, bmpOriginal.getWidth(), bmpOriginal.getHeight());
        matrix.mapRect(rectF);

        targetBitmap = Bitmap.createBitmap((int)rectF.width(), (int)rectF.height(), Bitmap.Config.ARGB_8888);


        Canvas tempCanvas = new Canvas(targetBitmap); 
        tempCanvas.drawBitmap(bmpOriginal, matrix, p);
МСауди
источник
1
не могли бы вы попробовать setFilterBitmap, setDither options
Sudar Nimalan
1
Да, это сработало отлично. Большое спасибо, Сударь, ты мне очень помог.
MSaudi
1
Добавление ссылки на ваше собственное продолжение с обновленным кодом: stackoverflow.com/questions/13048953/…
Крис Рэй
0
matrix.reset();
matrix.setTranslate( anchor.x, anchor.y );
matrix.postRotate((float) rotation , 0,0);
matrix.postTranslate(positionOfAnchor.x, positionOfAnchor.x);
c.drawBitmap(bitmap, matrix, null); 
Луи Альмеда
источник