#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.0 f — это масштабирование, масштабирующий фактор >
Таким образом, расчет должен быть getWidth() * scaleFactor
например, масштабирующий фактор 0,5 f имеет половинный размер
- Размер , который вам нужен
int
, равен, а масштабирующийfloat
фактор равен, поэтому вы не можете получить точную ширину требуемого растрового изображения, хотя для округления с помощьюMath.round()
Комментарии:
1. Спасибо вам за ваш ответ! Сейчас он работает, но не так, как я хочу, он просто захватывает исходный видовой экран (перед масштабированием). Я рисую фигуры, некоторые из них находятся за окном, и когда я уменьшаю масштаб, они находятся внутри окна, но снимок экрана их не включает.
2. Это немного зависит от того, какой размер вы видите на своем холсте, так как вы не показываете
onMeasure()
его, вам трудно помочь.3. Я соответствующим образом обновил вопрос, включая полный проект.