I'm doing an android app to decompress, decode and display HDR pictures.
These HDR pictures use 2 bytes per component (A,R,G,B) so one pixel is represented by a 8 bytes value that can only fit with the long type.
I'm using android's Bitmap to display picture as they have a constructor allowing to do HDR by using Bitmap.Config.RGBA_F16
:
int width = 1;
int height = 1;
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.RGBA_F16);
Unfortunately I can't find any way to fill a pixel of the Bitmap. I use the recommended formula but it cannot be used in the setPixel(x,y,color) method of Bitmap because color has to be a int:
long color = (A & 0xffff) << 48 | (B & 0xffff) << 32 | (G & 0xffff) << 16 | (R & 0xffff);
image.setPixel(0,0,color); //Argument type error
.
I have also tried with Color (which has a HDR compatible method), Paint and Canvas but no Bitmap method accepts them to set only one pixel.
Thanks for any help!
HDR files can be opened with Adobe Photoshop, ACD Systems Canvas, HDRSoft Photomatix, and probably some other popular photo and graphics tools as well. You might also have luck with the online viewer at OpenHDR.org if you want to open it online, or RenderStuff.com.
When HDR is activated the phone does all the work automatically to capture the image and combine them to produce a wide range of highlights. Given the fact that HDR works by capturing multiple images and combining them together, it works best in static shots with steady hands.
If you need to open an HDR file, such as 16-bit png, and then display it, you can use ImageDecoder.setTargetColorSpace to create bitmap with format Bitmap.Config.RGBA_F16
like so:
File file = new File(...);
ImageDecoder.Source source = ImageDecoder.createSource(file);
Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
decoder.setTargetColorSpace(ColorSpace.Named.EXTENDED_SRGB);
});
If you need to display HDR image that is stored in memory you can use Bitmap.copyPixelsFromBuffer
, as this method allows to set pixels of the bitmap without conversion of color space the way Bitmap.setPixel
does. In this case you need to pack 4 channels represented by Half
values into long for each pixel, then write these long values into a Buffer
and finally copy pixels from the buffer to the bitmap.
LongBuffer buffer = LongBuffer.allocate(width * height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// fill pixels values as needed
float r = (float)y / height;
float g = (float)y / height;
float b = (float)y / height;
float a = 1f;
long rBits = Half.halfToShortBits(Half.toHalf(r));
long gBits = Half.halfToShortBits(Half.toHalf(g));
long bBits = Half.halfToShortBits(Half.toHalf(b));
long aBits = Half.halfToShortBits(Half.toHalf(a));
long color = aBits << 48 | bBits << 32 | gBits << 16 | rBits;
buffer.put(color);
}
}
buffer.rewind();
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGBA_F16);
bitmap.copyPixelsFromBuffer(buffer);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With