Как получить растровое изображение из масштабированного представления в Android

#android #bitmap #scale

Вопрос:

У меня есть пользовательское представление с именем MyView с правильно включенным масштабированием! После масштабирования представления с помощью пальцев я хочу получить растровое изображение этого результирующего представления. Для этого я использую метод getBitmap () ниже, но он не работает! это работает только в том случае, если представление не масштабируется (масштабирующий фактор = 1,0 f). Я заменил getWidth (), getHeight () на getWidth () / scaleFactor, getHeight () / scaleFactor, но это тоже не работает!

 //These two methods are inside the MyView class
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();
    canvas.scale(scaleFactor, scaleFactor);

    canvas.drawPath(path, paint);

    canvas.restore();
}

public Bitmap getBitmap(){
    Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    draw(canvas);

    return bitmap;
}
 

Итак, как мне получить растровое изображение из масштабированного представления (масштабирующий фактор != 1.0 f)?

ОБНОВЛЕНИЕ: включить полный проект:

 //myview
public class MyView extends View {
    private Path path;
    private Paint paint;
    private ScaleGestureDetector scaleDetector;
    private float scaleFactor = 1.0f;

    public MyView(Context context) {
        super(context);
        init(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context){
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.GREEN);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        path = new Path();

        //inside window
        path.addRect(300, 300, 600, 600, Path.Direction.CW);

        //outside window
        path.addRect(800, 800, 1000, 1000, Path.Direction.CW);

        //outside window
        path.addRect(1000, 1000, 1200, 1200, Path.Direction.CW);
        scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.scale(scaleFactor, scaleFactor);
        canvas.drawPath(path, paint);
        canvas.restore();
    }

    public Bitmap getBitmap(){
        Bitmap bitmap =
                Bitmap.createBitmap(
                        Math.round(getWidth()*scaleFactor),
                        Math.round(getHeight()*scaleFactor),
                        Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(bitmap);
        draw(canvas);
        return bitmap;
    }

    private class ScaleListener
            extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor *= detector.getScaleFactor();
            // Don't let the object get too small or too large.
            scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 5f));
            invalidate();
            return true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        scaleDetector.onTouchEvent(ev);
        return true;
    }
}
 

Main activity

 public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyView myView = findViewById(R.id.my_view);
        Button button = findViewById(R.id.button);

        button.setOnClickListener(view -> {
            Bitmap bitmap = myView.getBitmap(); //add breakpoint in this line
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
        });
    }
}
 

xml

 <androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.abdo.scaledviewtobitmapquestion.MyView
        android:id="@ id/my_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="Hello World!"
        app:layout_constraintBottom_toTopOf="@id/button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@ id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get Bitmap"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
 

В этом проекте я создаю три прямоугольника, один внутри окна и два снаружи окна,
Перед запуском этого проекта я добавил точку останова в этой строке «Растровое изображение растровое изображение = MyView.getBitmap ();» (Основное действие)
Когда приложение открыто, я уменьшаю масштаб окна до тех пор, пока в нем не появятся все 3 прямоугольника, затем нажимаю кнопку, чтобы увидеть растровое изображение вывода отладчика.

Удивительно! Растровое изображение не включает в себя три прямоугольника, оно просто захватывает прямоугольник, видимый в исходном окне перед масштабированием (scaleFactor = 1).

Ответ №1:

2 части ответа.

  1. Масштабирующий фактор > 1.0 f — это масштабирование, масштабирующий фактор >

Таким образом, расчет должен быть getWidth() * scaleFactor

например, масштабирующий фактор 0,5 f имеет половинный размер

  1. Размер , который вам нужен int , равен, а масштабирующий float фактор равен, поэтому вы не можете получить точную ширину требуемого растрового изображения, хотя для округления с помощью Math.round()

Комментарии:

1. Спасибо вам за ваш ответ! Сейчас он работает, но не так, как я хочу, он просто захватывает исходный видовой экран (перед масштабированием). Я рисую фигуры, некоторые из них находятся за окном, и когда я уменьшаю масштаб, они находятся внутри окна, но снимок экрана их не включает.

2. Это немного зависит от того, какой размер вы видите на своем холсте, так как вы не показываете onMeasure() его, вам трудно помочь.

3. Я соответствующим образом обновил вопрос, включая полный проект.