How to provide the `const void* pImage` Array
manticore-projects opened this issue · comments
Apologies for asking a maybe stupid question:
How exactly is const void* pImage
Array supposed to look like? And how to create this array from a Java Image?
From the Python implementation, I can see that a 3 dimensional array is used, however in my understanding a Raster Image has only 2 dimensions?
Any hint or helping hand will be much appreciated, thank you!
This is my current understanding:
/*
num_chans must be 3 or 4. There must be w*3*h or w*4*h bytes pointed to by pImage.
The image row pitch is always w*3 or w*4 bytes.
There is no automatic determination if the image actually uses an alpha channel, so if you call it with 4 you will always get a 32bpp .PNG file.
*/
// read the Demo PNG into an Image
BufferedImage image = ImageIO.read(inputStream);
// Create the w*4*h byte array
final byte[] byteArr = new byte[image.getWidth()*4*image.getHeight()];
for (int y=0; y<image.getHeight(); y++) {
for (int x=0; x<image.getWidth(); x++) {
int argb = image.getRGB(x, y);
final int alpha = 0xff & (argb >> 24);
final int red = 0xff & (argb >> 16);
final int green = 0xff & (argb >> 8);
final int blue = 0xff & (argb >> 0);
byteArr[x * 4 * y]= (byte) red;
byteArr[x * 4 * y + 1]= (byte) green;
byteArr[x * 4 * y + 2]= (byte) blue;
byteArr[x * 4 * y + 3]= (byte) alpha;
}
}
// Convert byte array to Pointer
Pointer pImage = new Memory(byteArr.length);
pImage.write(0, byteArr, 0, byteArr.length);
And pardon my ignorant question: Why declare an unspecific pointer const void* pImage
instead of a pointer to a defined structure, which allows to understand what exactly is expected?
I have successfully wrapped the Encoder and can call it from Java. It produces a valid PNG byte stream.
However, the image is heavily distorted (simply garbage), meaning my understanding how pImage
has to be construed is wrong.
Please help me out here with an explanation. Thanks a lot in advance.
extern "C" {
void fpng_init() {
return fpng::fpng_init();
}
typedef struct {
uint8_t* data;
size_t size;
} ByteArray;
void releaseVectorData(ByteArray data) {
// Release the allocated memory when it's no longer needed
delete[] data.data;
}
ByteArray* fpng_encode_image_to_memory1(const void* pImage, uint32_t w, uint32_t h, uint32_t num_chans, uint32_t flags = 0) {
// Vector frees itself
std::vector<uint8_t> out_buf;
//w=687 h=1012 channels=4 flags=0
printf("w=%d h=%d channels=%d flags=%d\n", w, h, num_chans, flags);
bool result = fpng::fpng_encode_image_to_memory( pImage, w, h, num_chans, out_buf, flags);
printf("size=%d\n", out_buf.size());
ByteArray* data = (ByteArray*)malloc(sizeof(ByteArray));
data->size = out_buf.size();
data->data = (uint8_t*) malloc( out_buf.size() * sizeof(uint8_t));
// copy the uint8_t* array
std::memcpy(data->data, out_buf.data(), out_buf.size());
return data;
}
}
Apologies for the noise.
I finally got it working:
BufferedImage image = ImageIO.read(inputStream);
// Get image dimensions
int width = image.getWidth();
int height = image.getHeight();
// Get the pixel data as an integer array
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
// Create a byte array to store RGBA values
byte[] rgbaArray = new byte[width * height * 4];
// Extract RGBA values from each pixel
for (int i = 0; i < pixels.length; i++) {
int pixel = pixels[i];
rgbaArray[i * 4] = (byte) ((pixel >> 16) & 0xFF); // Red
rgbaArray[i * 4 + 1] = (byte) ((pixel >> 8) & 0xFF); // Green
rgbaArray[i * 4 + 2] = (byte) (pixel & 0xFF); // Blue
rgbaArray[i * 4 + 3] = (byte) ((pixel >> 24) & 0xFF); // Alpha
}
With that Byte Array I can encode a proper PNG in Java, calling FPNG via JNA.