Android: Bir bitmap'i merkez noktasında döndürme


84

Bu soruna bir çözüm bulmak için bir günden fazla arıyordum ama hiçbir şey yardımcı olmuyor, buradaki cevaplar bile. Belgeler de hiçbir şeyi açıklamıyor.

Sadece başka bir nesnenin yönünde bir dönüş elde etmeye çalışıyorum. Sorun, bitmapin sabit bir nokta etrafında değil, bitmapler (0,0) etrafında döndürülmesidir.

İşte sorun yaşadığım kod:

  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;

İşin tuhaf yanı, içindeki pre/ içindeki değerleri postTranslate()ve içindeki float argümanlarını nasıl değiştirdiğim önemli değil setRotation(). Birisi bana yardım edip doğru yöne itebilir mi lütfen? :)


1
Yukarıdaki kodun birkaç denemeden sonra olduğunu anlıyorum. Görünüşe göre mtx.setRotate (dir, x, y), tüm pre / post şeyler olmadan, işi kendi başına yapmalı. Ayrıca, yeni newhazırlanmış bir matrisi sıfırlamanıza gerek yoktur . Zaten kimlik.
Mark Storer

Yanıtlar:


101

Umarım aşağıdaki kod dizisi size yardımcı olur:

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());

Aşağıdaki yöntemi kontrol ederseniz ~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)

bu, rotasyon ve çeviri ile ne yaptığını açıklar.


1
Bunu bir Matrix alan Bitmap.createBitmap ile yapabilir misiniz? TargetWidth ve targetHeight değerlerini nasıl hesaplıyorsunuz? Sanırım basit trigonometri, ama "daha kolay" bir yol var mı?

Lütfen aşağıdaki yanıtı kontrol edin, (Üzgünüm, yorumlara kod ekleyemedim)
Sudar Nimalan

bunu uygularken kalite kötüleşiyor. herhangi bir çözüm ?
MSaudi

1
canvas.drawBitmap'i değiştirin (kaynak, matris, yeni Paint ()); canvas.drawBitmap ile (kaynak, matris, yeni Paint (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

3
Sadece bu işlemin hafızaya çok aç olduğu ve adım yöntemlerinde kullanılmaması gerektiğini söylüyorum.
MLProgrammer-CiM

79

Düzenlendi : optimize edilmiş kod.

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'i kaynaklardan almak için:

Bitmap source = BitmapFactory.decodeResource(this.getResources(), R.drawable.your_img);

Bir bitmap'i herhangi bir w veya h ile döndürmek için bunu deneyin: Matrix matrix = new Matrix (); matrix.postRotate (90); bitmapPicture = Bitmap.createBitmap (bitmapPicture, 0, 0, bitmapPicture.getWidth (), bitmapPicture.getHeight (), matrix, true);
Mark Molina

Görüntü noktalarının parametrelerini ayarlarken bu benim için mükemmel çalıştı. Bitmap'i tuvale çizerken matrisi kullandığınızdan emin olmanız yeterlidir.
a54studio

6
Bunun verimli olduğundan emin misin? RotateBitmap (), N kez çalıştıran bir döngüde olsaydı, bitmap'in çözünürlüğüne bağlı olarak, tüm bu yeni Matrix nesne ayırmalarının yanı sıra muazzam miktarda belleği boşa harcıyor olabilirsiniz.
Ryhan

Test edilmedi, ancak docs şöyle der: "Kaynak bitmap değişmez ise ve istenen alt küme, kaynak bitmapin kendisiyle aynıysa, kaynak bitmap döndürülür ve yeni bitmap oluşturulmaz." Matrix nesnesine gelince, sadece koordinatlar sınıfını dönüştürüyor. Tekrarlama için kodu özgürce optimize edebilir ve aynı Matrix nesnesini döngülerde kullanabilirsiniz.
Arvis

Bilginize, bit eşlemin değiştirilebilir olması gerekiyor
kip2

25

Oyunu bitirdiğimiz için bu soruna geri döndüm ve benim için işe yarayan şeyi göndermeyi düşündüm.

Bu, Matrix'i döndürme yöntemidir:

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

( this.getCenterX()temelde bitmaplerin X konumu + bitmap genişliğidir / 2)

Ve bitmap çizme yöntemi ( RenderManagerSınıf aracılığıyla çağrılır ):

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

Öyleyse, açık sözlü güzel ama onu setRotatetakip ederek çalıştırmamayı biraz tuhaf buluyorum postTranslate. Belki bazıları bunun neden işe yaramadığını biliyordur? Artık tüm bitmapler düzgün bir şekilde dönüyor, ancak bitmap kalitesinde küçük bir düşüş yok:

Her neyse, yardımın için teşekkürler!


Önceki cevap kodu da çalışır. aynı kalite sorunu ile.
MSaudi

7

Ayrıca ImageViewa kullanarak da döndürebilirsiniz 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
Yanlış soruyu cevaplıyorsunuz. Görünümü döndürmek istemiyor, sadece içindeki tek bir bitmap.
Mark Storer

Deneyimlediğim gibi, setFillAfter (bool) yöntemi Android API lvl 11 ve altında olması beklendiği gibi çalışmıyor. Bu nedenle, geliştiriciler, görünüm nesnelerinde sürekli rotasyon olayını kullanamaz veya rotasyondan sonra bu görünümlerin döndürülmüş sürümlerini elde edemezler. Yani @Mark Storer, Macarse animasyon süresini 0 veya 0'a yakın bir değerle ayarlarsanız gerçekten mantıklı bir bakış açısıyla yanıt verdi.
Gökhan Barış Aker

5

Aşağıdaki gibi bir şey kullanabilirsiniz:


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());


tüm çözümler için aynı sorun: bit eşlem kalitesinde düşüş
MSaudi

canvas.drawBitmap'i değiştirin (kaynak, matris, yeni Paint ()); canvas.drawBitmap ile (kaynak, matris, yeni Paint (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

kullandığınız yapılandırma nedir?
Sudar Nimalan

Aşağıdaki kodu cevap olarak gönderdim. yorumda yazamadı. Çok teşekkürler efendim :)
MSaudi


1

Bu konfigürasyonları kullandım ve hala pikselleştirme sorunum var:

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'i deneyebilir misin, setDither options
Sudar Nimalan

1
Evet, bu mükemmel çalıştı. Çok teşekkür ederim Sudar, bana gerçekten çok yardımcı oldun.
MSaudi

1
Güncellenen kodla kendi takip programınıza bağlantı eklemek: 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); 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.