Масштабирование и поворот растрового изображения с использованием матрицы в Android - PullRequest
30 голосов
/ 04 января 2012

Я пытаюсь масштабировать и вращать за одну операцию перед созданием окончательного растрового изображения, но preRotate, postConcat, похоже, не работает.

Bitmap bmp = ... original image ...

Matrix m = new Matrix()
m.setScale(x, y);
m.preRotate(degrees, (float) width / 2, (float) height / 2);

Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);

Применяется только масштаб, а не вращение.

Ответы [ 8 ]

38 голосов
/ 21 ноября 2012

Ответ был дан, но чтобы было понятнее любому, кто читает это:

1) если вы хотите выполнить ОДНО преобразование в своем растровом изображении, вы МОЖЕТЕ использовать SET (setRotate, setScale и т. Д.).

Но учтите, что любой вызов метода "set" ОБЗОРЫ других преобразований. Это как новая матрица. Вот почему вращение OP не работает. Эти звонки не выполняются построчно. Это похоже на то, что они запланированы для выполнения во время выполнения графическим процессором, когда создается новое растровое изображение. Это как при разрешении вашей матрицы, графический процессор поворачивал ее, но затем создавал масштабированную новую, игнорируя предыдущую матрицу.

2) если вы хотите выполнить более одного преобразования, вы ДОЛЖНЫ использовать методы «pre» или «post».

А в чем разница, например, между postRotate и preRotate? Ну, этот математический материал не моя сила, но я знаю, что графические карты выполняют эти преобразования, используя матричное умножение. Кажется, это намного эффективнее. И, насколько я помню из школы, при умножении матриц порядок важен. A X B! = B X A. Итак, масштабируйте матрицу, а затем вращайте ее, отличную от вращения, а затем масштабируйте ее.

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

Ну, в тех редких случаях, когда вы выполняете действительно сложные матричные операции, и результаты не соответствуют вашим ожиданиям, или производительность ужасна, и вам нужно глубоко понимать эти методы, чтобы исправить ваш код, ну, тогда документация по Android не может в любом случае очень поможет. Вместо этого, хорошая книга по линейной алгебре станет вашим лучшим другом. ;)

36 голосов
/ 04 января 2012

Это код

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);
    }
}
1 голос
/ 17 декабря 2018
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(rotation);
rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0,loadedImage.getWidth(), loadedImage.getHeight(),rotateMatrix, false);
1 голос
/ 15 июня 2016

Canvas содержит матричный стек, и вы можете использовать его с методами:

Canvas.save ()

Doc: / ** * Сохраняет текущую матрицу и клип в частный стек,*

* Последующие вызовы translate, scale, rotate, skew, concat или clipRect, * clipPath будут работать как обычно, но когда выполняется балансировочный вызов * restore (), эти вызовы будут забыты, а настройки* существовавший до восстановления ().* * @return Значение, которое необходимо передать в restoreToCount () для баланса этого сохранения () * /

Canvas.restore ()

Doc: / ** * Этот вызов уравновешивает предыдущий вызовsave (), и используется для удаления всех * изменений в состоянии матрицы / клипа с момента последнего вызова сохранения.* Ошибка вызывать restore () больше раз, чем была вызвана save ().* /

пример: пользовательский вид (Android), который выглядит как вращающаяся ручка (например, потенциометр)

@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 голосов
/ 10 апреля 2019

Использование матрицы для масштабирования области исходного растрового изображения до 50% и сжатия растрового изображения до его размера Сжатие растрового изображения до определенного размера в Android

0 голосов
/ 20 июля 2018

Все предыдущие ответы предполагают, что это изменение в растровом изображении вносится в представление.Однако в моем случае я делал изменения, которые нужно сохранить.Думаю, я бы ответил на это в тех же лодках.

Есть два способа сделать перевод.Ниже dx - перевод по оси X, а dy - перевод по оси Y.Другие переменные должны быть понятны.

1 - Перевод в изображении (без вращения)

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

2 - Сложная матрица

 matrix.postTranslate(dx, dy)

 val newBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)

 val canvas = Canvas(newBitmap)
 canvas.drawBitmap(originalBitmap, matrix, null)
0 голосов
/ 24 марта 2014

Если вы столкнулись с проблемой OutOfMemory с ответами выше, чем использовать ниже:

Bitmap MyFinalBitmap = Bitmap.createBitmap(CurrentBitmap, 0, 0,CurrentBitmap.getWidth()/2, CurrentBitmap.getHeight()/2,matrix, true);
0 голосов
/ 04 января 2012

Обратитесь к следующему коду, похоже, работает.В вашем коде вы определяете матрицу как m, но ссылаетесь на нее как matrix

public class FourthActivity extends Activity {
private static final int WIDTH = 50;
private static final int HEIGHT = 50;
private static final int STRIDE = 64;  

private static int[] createColors() {
    int[] colors = new int[STRIDE * HEIGHT];
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            int r = x * 255 / (WIDTH - 1);
            int g = y * 255 / (HEIGHT - 1);
            int b = 255 - Math.min(r, g);
            int a = Math.max(r, g);
            colors[y * STRIDE + x] = (a << 24) | (r << 16) | (g << 8) | b;
        }
    }
    return colors;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main2);
    final ImageView view1 = (ImageView) findViewById(R.id.imageView1);

    int[] colors = createColors();
    final Bitmap bmp1 = Bitmap.createBitmap(colors, 0, STRIDE, WIDTH, HEIGHT,
    Bitmap.Config.ARGB_8888);
    view1.setImageBitmap(bmp1);
    Button button = (Button) findViewById(R.id.button1);
    button.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {   
            Matrix matrix = new Matrix();
            matrix.setScale(2, 2);
            matrix.preRotate(45, (float) WIDTH / 2, (float) HEIGHT / 2);

            Bitmap bmp2 = Bitmap.createBitmap(bmp1, 0, 0, 
      bmp1.getWidth(), bmp1.getHeight(), matrix, true);
            ImageView view2 = (ImageView) findViewById(R.id.imageView2);
            view2.setImageBitmap(bmp2);
        }
    });
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...