What is the native way to use canvas.drawBitmap to draw directly on Canvas?
I'm using the method below to try to copy the bitmap directly to Canvas, but the result is not good. Help me!
private void copyBitmapToCanvas(Bitmap bitmap) {
if (flagLog) Log.d(LOG_NAME, "Copying bitmap to canvas");
if (bitmap == null || bitmap.isRecycled()) {
if (flagLog) Log.d(LOG_NAME, "Bitmap is null or recycled");
return;
}
try {
this.canvas.Clear(); // Limpa o Canvas atual
android.graphics.Canvas c = new android.graphics.Canvas(this.bitmap);
this.view.draw(c);
this.view.invalidate(); // Notifica que a view deve ser redesenhada
if (flagLog) Log.d(LOG_NAME, "Bitmap copy successful!");
} catch (Exception e) {
if (flagLog) Log.e(LOG_NAME, "Error copying bitmap to canvas", e);
}
}
Rest of code:
package com.bosonshiggs.extendedcanvas.helpers;
import com.google.appinventor.components.runtime.Canvas;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Paint;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.Stack;
//import java.awt.Point;
import android.util.Log;
public class FloodFillHandler {
private android.view.View view;
private int width, height;
Bitmap bitmap;
Canvas canvas;
private Stack<Bitmap> undoStack = new Stack<>();
private Stack<Bitmap> redoStack = new Stack<>();
private String LOG_NAME = "ExtendedCanvas";
private boolean flagLog = false;
public void setCanvas(Canvas canvas) {
Log.d(LOG_NAME, "Setting canvas");
this.view = canvas.getView();
this.width = canvas.Width();
this.height = canvas.Height();
this.canvas = canvas;
//recycleBitmap(this.bitmap);
this.bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
private void recycleBitmap(Bitmap bitmap) {
if (this.bitmap != null && !this.bitmap.isRecycled()) {
this.bitmap.recycle();
}
}
public void clearMemory() {
if (flagLog) Log.d(LOG_NAME, "Clearing memory");
clearStack(undoStack);
clearStack(redoStack);
recycleBitmap(this.bitmap); // Só recicle this.bitmap se você for recriá-lo depois
this.bitmap = null; // Defina como null após a reciclagem
this.canvas.Clear();
}
private void clearStack(Stack<Bitmap> stack) {
if (flagLog) Log.d(LOG_NAME, "Clearing stack");
while (!stack.isEmpty()) {
Bitmap bitmap = stack.pop();
if (bitmap != null) {
bitmap.recycle(); // Libera os recursos associados ao bitmap
}
}
}
private void copiesCurrentState() {
try {
updateDimensions(); // Garante que as dimensões estejam atualizadas
if (this.bitmap == null || this.bitmap.getWidth() != this.width || this.bitmap.getHeight() != this.height) {
recycleBitmap(this.bitmap);
this.bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888);
}
// Redesenha a view no bitmap existente
android.graphics.Canvas androidCanvas = new android.graphics.Canvas(this.bitmap);
this.view.draw(androidCanvas);
if (flagLog) Log.d(LOG_NAME, "State copied successfully!");
} catch (Exception e) {
if (flagLog) Log.e(LOG_NAME, "Error copying state", e);
}
}
private void updateDimensions() {
this.width = this.view.getWidth();
this.height = this.view.getHeight();
}
private Bitmap createBitmap(int width, int height) {
Bitmap currentBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
android.graphics.Canvas c = new android.graphics.Canvas(currentBitmap);
this.view.layout(0, 0, width, height);
this.view.draw(c);
return currentBitmap;
}
public void saveCurrentState() {
if (flagLog) Log.d(LOG_NAME, "Saving current state");
copiesCurrentState();
Bitmap currentState = Bitmap.createBitmap(this.bitmap);
undoStack.push(currentState);
clearStack(redoStack);
if (flagLog) Log.d(LOG_NAME, "Canvas state saved");
}
private void copyBitmapToCanvas(Bitmap bitmap) {
if (flagLog) Log.d(LOG_NAME, "Copying bitmap to canvas");
if (bitmap == null || bitmap.isRecycled()) {
if (flagLog) Log.d(LOG_NAME, "Bitmap is null or recycled");
return;
}
try {
this.canvas.Clear(); // Limpa o Canvas atual
android.graphics.Canvas c = new android.graphics.Canvas(this.bitmap);
this.view.draw(c);
this.view.invalidate(); // Notifica que a view deve ser redesenhada
if (flagLog) Log.d(LOG_NAME, "Bitmap copy successful!");
} catch (Exception e) {
if (flagLog) Log.e(LOG_NAME, "Error copying bitmap to canvas", e);
}
}
public void undo() {
if (flagLog) Log.d(LOG_NAME, "Performing undo");
if (!undoStack.isEmpty()) {
this.canvas.Clear();
Bitmap previousState = undoStack.pop();
if (previousState == null || previousState.isRecycled()) {
//Log.d(LOG_NAME, "Previous state is null or recycled");
return;
}
// Recicle o bitmap atual após empurrá-lo para redoStack
redoStack.push(Bitmap.createBitmap(this.bitmap));
recycleBitmap(this.bitmap);
this.bitmap = previousState;
copyBitmapToCanvas(previousState);
}
this.view.invalidate();
}
public void redo() {
Log.d(LOG_NAME, "Performing redo");
if (!redoStack.isEmpty()) {
this.canvas.Clear();
Bitmap nextState = redoStack.pop();
if (nextState == null || nextState.isRecycled()) {
if (flagLog) Log.d(LOG_NAME, "Next state is null or recycled");
return;
}
// Recicle o bitmap atual após empurrá-lo para undoStack
undoStack.push(Bitmap.createBitmap(this.bitmap));
recycleBitmap(this.bitmap);
this.bitmap = nextState;
copyBitmapToCanvas(nextState);
}
this.view.invalidate();
}
//The other non-relevant methods have been hidden
}
Note: My idea is to replace the pixel-by-pixel copy of my post with something more efficient.