Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display HDR picture in Android?

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!

like image 287
Nicolas Avatar asked Apr 01 '19 15:04

Nicolas


People also ask

How do I view HDR photos?

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.

How does HDR work on Android?

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.


1 Answers

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);

like image 175
fdermishin Avatar answered Oct 10 '22 19:10

fdermishin