Подтвердить что ты не робот

Масштабирование и поворот растрового изображения с использованием матрицы в Android

Я пытаюсь масштабировать и вращать в одиночной операции до того, как выстроить окончательное растровое изображение, но 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);

Используется только масштаб, а не вращение.

4b9b3361

Ответ 1

Пожалуйста, проверьте эту ссылку для деталей

http://www.anddev.org/resize_and_rotate_image_-_example-t621.html

Это код

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

Ответ 2

Ответ был дан, но для того, чтобы кто-нибудь читал это, яснее:

1), если вы хотите выполнить ONE-преобразование в вашем растровом изображении, вы можете использовать SET (setRotate, setScale и т.д.).

Но обратите внимание, что любой вызов метода "set" OVERRIDES других преобразований. Это похоже на новую матрицу. То почему вращение OP не работало. Эти вызовы не выполняются по строкам. Это похоже на то, что они планируются во время выполнения графическим процессором при рисовании нового растрового изображения. Как и при разрешении вашей матрицы, GPU повернул ее, но затем создал масштабированную новую, игнорируя предыдущую матрицу.

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

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

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

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

Ответ 3

Canvas содержит стек матрицы, и вы можете использовать его с помощью методов:

Canvas.save()

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

   * Последующие вызовы для перевода, масштабирования, поворота, перекоса, concat или clipRect,    * clipPath будет работать как обычно, но когда балансирующий вызов    * restore(), эти вызовы будут забыты, а настройки, которые    * существовал до восстановления save().    *    * @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();
}

Ответ 4

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

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

Ответ 5

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

Bitmap MyFinalBitmap = Bitmap.createBitmap(CurrentBitmap, 0, 0,CurrentBitmap.getWidth()/2, CurrentBitmap.getHeight()/2,matrix, true);

Ответ 6

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

Есть два способа сделать перевод. Ниже 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)

Ответ 7

Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(rotation);
rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0,loadedImage.getWidth(), loadedImage.getHeight(),rotateMatrix, false);