2022-10-02 23:06:56 +02:00
|
|
|
package android.graphics;
|
|
|
|
|
|
2025-02-10 18:04:19 +01:00
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.OutputStream;
|
2024-12-22 10:20:50 +01:00
|
|
|
import java.nio.Buffer;
|
|
|
|
|
|
2024-12-21 10:28:33 +01:00
|
|
|
import android.util.DisplayMetrics;
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
/*
|
|
|
|
|
* Bitmap is implemented as GdkTexture or GtkSnapshot. It can only be one of the two at a time.
|
|
|
|
|
* The methods getTexture() and getSnapshot() automatically convert between the two as needed.
|
|
|
|
|
*/
|
2022-10-02 23:06:56 +02:00
|
|
|
public final class Bitmap {
|
2023-06-22 11:45:46 +02:00
|
|
|
|
|
|
|
|
public enum Config {
|
2024-12-22 10:20:50 +01:00
|
|
|
RGB_565(2, -1, /*ANDROID_BITMAP_FORMAT_RGB_565*/4),
|
|
|
|
|
ARGB_8888(4, /*GDK_MEMORY_R8G8B8A8*/5, /**ANDROID_BITMAP_FORMAT_RGBA_8888*/1),
|
|
|
|
|
ARGB_4444(2, -1, /*ANDROID_BITMAP_FORMAT_RGBA_4444*/7),
|
|
|
|
|
ALPHA_8(1, /*GDK_MEMORY_A8*/ 24, /*ANDROID_BITMAP_FORMAT_A_8*/8);
|
|
|
|
|
|
|
|
|
|
private int bytes_per_pixel;
|
|
|
|
|
private int gdk_memory_format;
|
|
|
|
|
int android_memory_format; // used by native function AndroidBitmap_getInfo()
|
|
|
|
|
|
|
|
|
|
private Config(int bytes_per_pixel, int gdk_memory_format, int android_memory_format) {
|
|
|
|
|
this.bytes_per_pixel = bytes_per_pixel;
|
|
|
|
|
this.gdk_memory_format = gdk_memory_format;
|
|
|
|
|
this.android_memory_format = android_memory_format;
|
|
|
|
|
}
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2025-02-10 18:04:19 +01:00
|
|
|
public enum CompressFormat {
|
|
|
|
|
JPEG,
|
|
|
|
|
PNG,
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
private int width;
|
|
|
|
|
private int height;
|
2024-12-22 10:20:50 +01:00
|
|
|
private int stride;
|
2024-12-19 20:20:40 +01:00
|
|
|
private long texture;
|
|
|
|
|
private long snapshot;
|
2024-12-21 10:28:33 +01:00
|
|
|
private Config config = Config.ARGB_8888;
|
2024-12-22 10:20:50 +01:00
|
|
|
private boolean hasAlpha = true;
|
|
|
|
|
long bytes = 0; // used by native function AndroidBitmap_lockPixels()
|
2025-02-10 18:02:22 +01:00
|
|
|
private boolean recycled = false;
|
2023-06-22 11:45:46 +02:00
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
Bitmap(long texture) {
|
2024-12-22 10:20:50 +01:00
|
|
|
this(native_get_width(texture), native_get_height(texture), Config.ARGB_8888);
|
2024-12-19 20:20:40 +01:00
|
|
|
this.texture = texture;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-21 10:28:33 +01:00
|
|
|
private Bitmap(int width, int height, Config config) {
|
|
|
|
|
this.config = config;
|
2024-12-19 20:20:40 +01:00
|
|
|
this.width = width;
|
|
|
|
|
this.height = height;
|
2024-12-22 10:20:50 +01:00
|
|
|
int stride = width * config.bytes_per_pixel;
|
|
|
|
|
this.stride = (stride + 3) & ~3; // 4-byte alignment
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap createBitmap(int width, int height, Config config) {
|
2024-12-21 10:28:33 +01:00
|
|
|
return new Bitmap(width, height, config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap createBitmap(DisplayMetrics metrics, int width, int height, Config config) {
|
|
|
|
|
return new Bitmap(width, height, config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap createBitmap(DisplayMetrics metrics, int width, int height, Config config, boolean hasAlpha, ColorSpace colorSpace) {
|
2024-12-22 10:20:50 +01:00
|
|
|
Bitmap bitmap = new Bitmap(width, height, config);
|
|
|
|
|
bitmap.hasAlpha = hasAlpha;
|
|
|
|
|
return bitmap;
|
2024-12-21 10:28:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap createBitmap(Bitmap src, int x, int y, int width, int height) {
|
|
|
|
|
Bitmap dest = new Bitmap(width, height, src.getConfig());
|
|
|
|
|
new Canvas(dest).drawBitmap(src, new Rect(x, y, x + width, y + height), new Rect(0, 0, width, height), null);
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap createBitmap(Bitmap src, int x, int y, int width, int height, Matrix matrix, boolean filter) {
|
|
|
|
|
Bitmap dest = new Bitmap(width, height, src.getConfig());
|
|
|
|
|
Canvas canvas = new Canvas(dest);
|
|
|
|
|
canvas.concat(matrix);
|
|
|
|
|
canvas.drawBitmap(src, new Rect(x, y, x + width, y + height), new Rect(0, 0, width, height), null);
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap createBitmap(Bitmap src) {
|
|
|
|
|
return new Bitmap(native_ref_texture(src.getTexture()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) {
|
|
|
|
|
Bitmap dest = new Bitmap(dstWidth, dstHeight, src.getConfig());
|
|
|
|
|
new Canvas(dest).drawBitmap(src, new Rect(0, 0, src.getWidth(), src.getHeight()), new Rect(0, 0, dstWidth, dstHeight), null);
|
|
|
|
|
return dest;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
public int getWidth() {
|
|
|
|
|
return width;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
public int getHeight() {
|
|
|
|
|
return height;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-21 10:28:33 +01:00
|
|
|
public Config getConfig() {
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
public synchronized long getTexture() {
|
|
|
|
|
if (texture == 0) {
|
2024-12-22 12:22:30 +01:00
|
|
|
texture = native_create_texture(snapshot, width, height, stride, config.gdk_memory_format);
|
2024-12-19 20:20:40 +01:00
|
|
|
snapshot = 0;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
2024-12-19 20:20:40 +01:00
|
|
|
return texture;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
synchronized long getSnapshot() {
|
|
|
|
|
if (snapshot == 0) {
|
|
|
|
|
snapshot = native_create_snapshot(texture);
|
|
|
|
|
texture = 0;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
2024-12-19 20:20:40 +01:00
|
|
|
return snapshot;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
public void eraseColor(int color) {
|
2025-02-10 18:02:22 +01:00
|
|
|
native_recycle(texture, snapshot);
|
2024-12-19 20:20:40 +01:00
|
|
|
snapshot = native_erase_color(color, width, height);
|
|
|
|
|
texture = 0;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
public void recycle() {
|
|
|
|
|
native_recycle(texture, snapshot);
|
|
|
|
|
texture = 0;
|
|
|
|
|
snapshot = 0;
|
2025-02-10 18:02:22 +01:00
|
|
|
recycled = true;
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 10:20:50 +01:00
|
|
|
public int getRowBytes() {
|
|
|
|
|
return stride;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
public int getAllocationByteCount() {
|
2024-12-22 10:20:50 +01:00
|
|
|
return height * getRowBytes();
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void prepareToDraw() {
|
2024-12-19 20:20:40 +01:00
|
|
|
getTexture();
|
2023-06-22 11:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-21 10:28:33 +01:00
|
|
|
public void setDensity(int density) {}
|
|
|
|
|
|
|
|
|
|
public int getScaledWidth(int density) {
|
|
|
|
|
return width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getScaledHeight(int density) {
|
|
|
|
|
return height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isRecycled() {
|
2025-02-10 18:02:22 +01:00
|
|
|
return recycled;
|
2024-12-21 10:28:33 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 10:20:50 +01:00
|
|
|
public void setHasAlpha(boolean hasAlpha) {
|
|
|
|
|
this.hasAlpha = hasAlpha;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean hasAlpha() {
|
|
|
|
|
return hasAlpha;
|
|
|
|
|
}
|
2024-12-21 10:28:33 +01:00
|
|
|
|
2024-12-22 10:20:50 +01:00
|
|
|
public Bitmap copy(Bitmap.Config config, boolean isMutable) {
|
2024-12-21 10:28:33 +01:00
|
|
|
Bitmap bitmap = new Bitmap(width, height, config);
|
|
|
|
|
bitmap.texture = native_ref_texture(getTexture());
|
|
|
|
|
return bitmap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height) {
|
|
|
|
|
native_get_pixels(getTexture(), pixels, offset, stride, x, y, width, height);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-22 10:20:50 +01:00
|
|
|
public void copyPixelsToBuffer(Buffer buffer) {
|
|
|
|
|
if (config.gdk_memory_format == -1) {
|
|
|
|
|
System.out.println("copyPixelsToBuffer: format " + config.name() + " not implemented");
|
|
|
|
|
System.exit(1);
|
|
|
|
|
}
|
|
|
|
|
native_copy_to_buffer(getTexture(), buffer, config.gdk_memory_format, getRowBytes());
|
|
|
|
|
buffer.position(buffer.position() + getAllocationByteCount());
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-11 18:01:43 +01:00
|
|
|
public int getByteCount() {
|
|
|
|
|
return getAllocationByteCount();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-26 22:27:43 +01:00
|
|
|
public boolean isMutable() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-10 18:04:19 +01:00
|
|
|
public boolean compress(Bitmap.CompressFormat format, int quality, OutputStream stream) throws IOException {
|
|
|
|
|
if (format == CompressFormat.PNG) {
|
|
|
|
|
stream.write(native_save_to_png(getTexture()));
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
stream.write(("fixme Bitmap.compress " + format.name()).getBytes());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-26 21:47:08 +02:00
|
|
|
@SuppressWarnings("deprecation")
|
2024-12-19 20:20:40 +01:00
|
|
|
@Override
|
2024-07-26 21:47:08 +02:00
|
|
|
protected void finalize() throws Throwable {
|
|
|
|
|
try {
|
2024-12-19 20:20:40 +01:00
|
|
|
recycle();
|
2024-07-26 21:47:08 +02:00
|
|
|
} finally {
|
2024-12-19 20:20:40 +01:00
|
|
|
super.finalize();
|
2024-06-15 00:04:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-19 20:20:40 +01:00
|
|
|
private static native long native_create_snapshot(long texture);
|
2024-12-22 12:22:30 +01:00
|
|
|
private static native long native_create_texture(long snapshot, int width, int height, int stride, int format);
|
2024-12-19 20:20:40 +01:00
|
|
|
private static native int native_get_width(long texture);
|
|
|
|
|
private static native int native_get_height(long texture);
|
|
|
|
|
private static native long native_erase_color(int color, int width, int height);
|
|
|
|
|
private static native void native_recycle(long texture, long snapshot);
|
2024-12-21 10:28:33 +01:00
|
|
|
private static native long native_ref_texture(long texture);
|
|
|
|
|
private static native void native_get_pixels(long texture, int[] pixels, int offset, int stride, int x, int y, int width, int height);
|
2024-12-22 10:20:50 +01:00
|
|
|
private static native void native_copy_to_buffer(long texture, Buffer buffer, int memory_format, int stride);
|
2025-02-10 18:04:19 +01:00
|
|
|
private static native byte[] native_save_to_png(long texture);
|
2022-10-02 23:06:56 +02:00
|
|
|
}
|