Scale & rotate Bitmap using Matrix in Android

前端 未结 8 1683
名媛妹妹
名媛妹妹 2020-12-12 19:26

I\'m trying to scale and rotate in single operation before creting the final bitmap but the preRotate, postConcat doesn\'t seem to work.

Bitmap bmp = ... ori         


        
相关标签:
8条回答
  • 2020-12-12 19:51

    If you face the issue of OutOfMemory with above answers, than use below:

    Bitmap MyFinalBitmap = Bitmap.createBitmap(CurrentBitmap, 0, 0,CurrentBitmap.getWidth()/2, CurrentBitmap.getHeight()/2,matrix, true);
    
    0 讨论(0)
  • 2020-12-12 19:52

    This is the code

    public class Bitmaptest extends Activity {
        @Override
        public void onCreate(Bundle icicle) {
            super.onCreate(icicle);
            LinearLayout linLayout = new LinearLayout(this);
    
            // load the origial BitMap (500 x 500 px)
            Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
                   R.drawable.android);
    
            int width = bitmapOrg.getWidth();
            int height = bitmapOrg.getHeight();
            int newWidth = 200;
            int newHeight = 200;
    
            // calculate the scale - in this case = 0.4f
            float scaleWidth = ((float) newWidth) / width;
            float scaleHeight = ((float) newHeight) / height;
    
            // createa matrix for the manipulation
            Matrix matrix = new Matrix();
            // resize the bit map
            matrix.postScale(scaleWidth, scaleHeight);
            // rotate the Bitmap
            matrix.postRotate(45);
    
            // recreate the new Bitmap
            Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
                              newWidth, newHeight, matrix, true);
    
            // make a Drawable from Bitmap to allow to set the BitMap
            // to the ImageView, ImageButton or what ever
            BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
    
            ImageView imageView = new ImageView(this);
    
            // set the Drawable on the ImageView
            imageView.setImageDrawable(bmd);
    
            // center the Image
            imageView.setScaleType(ScaleType.CENTER);
    
            // add ImageView to the Layout
            linLayout.addView(imageView,
                    new LinearLayout.LayoutParams(
                          LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT
                    )
            );
    
            // set LinearLayout as ContentView
            setContentView(linLayout);
        }
    }
    
    0 讨论(0)
  • 2020-12-12 19:56

    Canvas holds a matrix stack und you can use it with the methods:

    Canvas.save()

    Doc: /** * Saves the current matrix and clip onto a private stack. *

    * Subsequent calls to translate,scale,rotate,skew,concat or clipRect, * clipPath will all operate as usual, but when the balancing call to * restore() is made, those calls will be forgotten, and the settings that * existed before the save() will be reinstated. * * @return The value to pass to restoreToCount() to balance this save() */

    Canvas.restore()

    Doc: /** * This call balances a previous call to save(), and is used to remove all * modifications to the matrix/clip state since the last save call. It is * an error to call restore() more times than save() was called. */

    example: A custom View(Android) which looks like a rotary knob(e.g. potentiometer)

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewX = getWidth();     //views width
        viewY = getHeight();    //views height
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); //a must call for every custom view
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        double tempAngel = 3.6 * barValue;
        int deltaX = bitmap.getWidth() / 2;
        int deltaY = bitmap.getHeight() / 2;
        ...
        canvas.save();
        canvas.translate(viewX / 2, viewY / 2);             //translate drawing point to center
        canvas.rotate((float) tempAngel);                   //rotate matrix
        canvas.save();                                      //save matrix. your drawing point is still at (viewX / 2, viewY / 2)
        canvas.translate(deltaX * -1, deltaY * -1);         //translate drawing  point a bit up and left to draw the bitmap in the middle
        canvas.drawBitmap(bitmap, 0,0, bitmapPaint);   // draw bitmap to the tranlated point at 0,0
        canvas.restore();     //must calls...
        canvas.restore();
    }
    
    0 讨论(0)
  • 2020-12-12 19:57

    Use matrix to scale area of original bitmap to 50% and compress bitmap until it's size < 200k Compress bitmap to a specific byte size in Android

    0 讨论(0)
  • 2020-12-12 20:03

    All of the previous answer assume that this change to the bitmap is being made in a view. However in my case I was making the change to be saved out. Figured I would answer it for those in a similar boat.

    There are two ways to do translation. Below dx is the translation in the X axis, and dy is the translation in the Y axis. The other variables should be self explanatory.

    1 - Translation within the image (without rotation)

    val newBitmap = Bitmap.createBitmap(originalBitmap, dx, dy, newWidth, newHeight, matrix, false)
    

    2 - Complex matrix

     matrix.postTranslate(dx, dy)
    
     val newBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)
    
     val canvas = Canvas(newBitmap)
     canvas.drawBitmap(originalBitmap, matrix, null)
    
    0 讨论(0)
  • 2020-12-12 20:07

    The answer was given, but to make things more clear to anyone reading this:

    1) if you wish to perform ONE transformation in your bitmap, you CAN use SET (setRotate, setScale etc).

    But note that any call to a "set" method OVERRIDES other transformations. It's like a new matrix. That's why OP's rotation was not working. These calls are not performed line by line. It's like they are scheduled to be done at runtime by the GPU when the new bitmap is being drawn. It's like when resolving your matrix, GPU rotated it, but then, created a scaled new one, ignoring previous matrix.

    2) if you wish to perform more then one transformation, then you MUST use "pre" or "post" methods.

    And what is the difference between a postRotate and a preRotate, for example? Well, this matrix math stuff is not my strength, but what I know is that the graphic cards make these transformations using matrix multiplication. It seems to be way more efficient. And as far as I remember from school, when multiplicating matrices the order IS important. A X B != B X A. So, scale a matrix and then rotate it is different from rotate and then scale it.

    BUUUUT, as far as the final result in the screen is the same, we high level programmers usually do not need to know these differences. The GPU does.

    Well, in that rare cases when you are performing really complicated matrix operations, and results are not what you expected or the performance is terrible and you need to deeply understand these methods to fix your code, well, then android documentation can not be of much help anyway. Instead, a good Linear Algebra book would be your best friend. ;)

    0 讨论(0)
提交回复
热议问题