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матрицю. Це вже ідентичність.
Mark Storer

Відповіді:


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? Я вважаю, що це простий триггер, але чи існує "простіший" спосіб?

Будь ласка, перевірте відповідь нижче, (Вибачте, я не зміг додати код у коментарях)
Sudar Nimalan

якість стає поганою під час застосування цього. будь-яке рішення?
MSaudi

1
змінити canvas.drawBitmap (джерело, матриця, новий Paint ()); з canvas.drawBitmap (джерело, матриця, нова Paint (Paint.ANTI_ALIAS_FLAG));
Судар Німалан

3
Просто коментуючи, що цей процес дуже потребує пам’яті, і його не слід використовувати в поетапних методах.
MLProgrammer-CiM

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 (), матриця, істина);
Марк Моліна,

Для мене це спрацювало ідеально, оскільки я встановлюю параметри для точок зображення. Вам просто потрібно обов’язково використовувати матрицю під час малювання растрового зображення на полотні.
a54studio

6
Ви впевнені, що це ефективно? Якщо RotateBitmap () знаходився в циклі, виконуючи N разів, залежно від роздільної здатності растрового зображення, ви могли б витратити величезну кількість пам'яті, а також усі ці нові розподіли об'єктів Matrix.
Ryhan

Не перевірено, але в документації сказано: "Якщо вихідне растрове зображення незмінне, а запитувана підмножина така ж, як і саме вихідне растрове зображення, тоді вихідне растрове зображення повертається і не створюється нове растрове зображення." Що стосується об'єкта Matrix, це просто перетворення класу координат. Ви можете вільно оптимізувати код для повторення та використовувати той самий об'єкт Matrix у циклах.
Арвіс

До уваги, растрове зображення має бути
змінним

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. Може, хтось знає, чому це не працює? Тепер усі растрові зображення обертаються належним чином, але це не без незначного зниження якості растрових зображень: /

У будь-якому разі, дякую за вашу допомогу!


Попередній код відповіді також працює. з тією ж проблемою якості.
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
Ви відповідаєте на неправильне запитання. Він не хоче обертати подання, лише єдине растрове зображення в ньому.
Mark Storer

Як я вже переконався, метод setFillAfter (bool) не працює, як очікувалося, для Android API рівня 11 та нижче. Отже, розробники не можуть використовувати подію безперервного обертання для об’єктів подання, а також не отримують повернені версії цих переглядів після обертання. Отже, @Mark Storer, Макарсе відповів справді на логічну точку зору, якщо ви встановили тривалість анімації з 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());


однакова проблема для всіх рішень: зниження якості растрових зображень
MSaudi

змінити canvas.drawBitmap (джерело, матриця, новий Paint ()); з canvas.drawBitmap (джерело, матриця, нова Paint (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/…
Chris Rae

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); 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.