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เมทริกซ์ ed ใหม่ เป็นเอกลักษณ์ของมันอยู่แล้ว
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 ที่ใช้ Matrix หรือไม่? คุณคำนวณ targetWidth และ targetHeight อย่างไร? ฉันคิดว่า Trig ง่ายๆ แต่มีวิธีที่ "ง่ายกว่า" หรือไม่?

โปรดตรวจสอบคำตอบด้านล่าง (ขออภัยฉันไม่สามารถเพิ่มรหัสในความคิดเห็นได้)
Sudar Nimalan

คุณภาพไม่ดีในขณะที่ใช้สิ่งนี้ วิธีแก้ปัญหาใด ๆ
MSaudi

1
เปลี่ยน canvas.drawBitmap (แหล่งที่มาเมทริกซ์สีใหม่ ()); ด้วย canvas.drawBitmap (แหล่งที่มาเมทริกซ์สีใหม่ (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

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 (), เมทริกซ์จริง);
Mark Molina

สิ่งนี้ใช้ได้ผลอย่างสมบูรณ์สำหรับฉันในขณะที่ฉันตั้งค่าพารามิเตอร์สำหรับจุดภาพ คุณต้องแน่ใจว่าได้ใช้เมทริกซ์เมื่อวาดบิตแมปลงบนผืนผ้าใบ
a54studio

6
แน่ใจหรือว่ามีประสิทธิภาพ หาก RotateBitmap () อยู่ในลูปที่ดำเนินการ N ครั้งขึ้นอยู่กับความละเอียดของบิตแมปคุณอาจต้องเสียหน่วยความจำจำนวนมหาศาลรวมทั้งการจัดสรรวัตถุ Matrix ใหม่ทั้งหมด
Ryhan

ไม่ได้รับการทดสอบ แต่เอกสารระบุว่า: "หากบิตแมปต้นทางไม่เปลี่ยนรูปและชุดย่อยที่ร้องขอเหมือนกับบิตแมปต้นทางเองบิตแมปต้นทางจะถูกส่งคืนและไม่มีการสร้างบิตแมปใหม่" สำหรับวัตถุ Matrix เป็นเพียงการเปลี่ยนคลาสพิกัด คุณสามารถเพิ่มประสิทธิภาพโค้ดสำหรับการทำซ้ำได้อย่างอิสระและใช้วัตถุ Matrix เดียวกันในลูป
Arvis

FYI บิตแมปต้องไม่แน่นอน
kip2

25

ฉันกลับมาที่ปัญหานี้ตอนนี้เรากำลังสรุปเกมและฉันแค่คิดว่าจะโพสต์สิ่งที่เหมาะกับฉัน

นี่คือวิธีการหมุน Matrix:

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

ดังนั้นมันจึงเป็น prettey ตรงไปตรงมา แต่ผมพบว่ามัน abit แปลกที่ฉันไม่สามารถได้รับมันในการทำงานโดยตามด้วย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 lvl 11 และต่ำกว่า ดังนั้นนักพัฒนาจึงไม่สามารถใช้เหตุการณ์การหมุนเวียนแบบต่อเนื่องกับวัตถุมุมมองและไม่ได้รับมุมมองเหล่านี้ในเวอร์ชันที่หมุนเวียนหลังจากการหมุน ดังนั้น @Mark Storer Macarse ตอบอย่างแท้จริงในมุมมองเชิงตรรกะหากคุณตั้งค่าระยะเวลาการเคลื่อนไหวด้วย 0 หรือบางอย่างที่ใกล้เคียงกับ 0
GökhanBarış 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 (แหล่งที่มาเมทริกซ์สีใหม่ ()); ด้วย canvas.drawBitmap (แหล่งที่มาเมทริกซ์สีใหม่ (Paint.ANTI_ALIAS_FLAG));
Sudar Nimalan

คุณใช้ config อะไรอยู่?
Sudar Nimalan

ฉันโพสต์รหัสด้านล่างเพื่อเป็นคำตอบ ไม่สามารถเขียนลงในความคิดเห็นได้ ขอบคุณมากครับ :)
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
Sudar Nimalan

1
ใช่สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบ ขอบคุณมาก Sudar คุณช่วยฉันได้มากจริงๆ
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); 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.