MONOGRID / gainmap-js

A Javascript (TypeScript) Port of Adobe Gainmap Technology for storing HDR Images using an SDR Image + a gainmap
https://monogrid.github.io/gainmap-js/
MIT License
82 stars 5 forks source link

encodeJPEGMetadata failed: Object in bad state, mem alloc failed #30

Closed zbydown closed 7 months ago

zbydown commented 7 months ago

image .hdr -> jpg with gainmap 80% of my .hdr file failed with this error, only few works

And for Adobe gainmap sample jpgs (from https://helpx.adobe.com/camera-raw/using/gain-map.html) , or gainmap jpgs exported by Adobe Camera Raw I tried to repack or re-encode them (because Galaxy S24 Ultra's Album / Instagram cannot display them in HDR, but Google Album or Chrome can): extractGainmapFromJPEG -> encodeJPEGMetadata or extractGainmapFromJPEG -> compress both sdr and gainmap -> encodeJPEGMetadata all failed with "Object in bad state, mem alloc failed"

I suspect the issue might be related to the libultrahdr

daniele-pelagatti commented 7 months ago

Yes the problem seems the libultrahdr WASM module which, apparently, cannot allocate its memory for some reason.

Can you give more detailed reproducibility steps?

Where are you executing this functions? are you building an app with the library and executing these functions in your code? are you using our tool at https://gainmap-creator.monogrid.com/ ?

Can you attach an example of an .hdr file which fails encodeJPEGMetadata and the code you execute?

zbydown commented 7 months ago

this is the small one small.hdr.zip and the big one https://drive.google.com/file/d/1xRIhNjbb6CLqXiFaAemn7cfcgJ5FYaml/view?usp=sharing

2 samples

daniele-pelagatti commented 7 months ago

ok, the big one fails in https://gainmap-creator.monogrid.com (which uses the library).

I'm not sure why this happens because we've tested the library (among others) with 8k versions of this image https://polyhaven.com/a/qwantani_puresky which is 289MB, bigger than yours both in file size and resolution

or this one https://polyhaven.com/a/metro_noord , 8k, exr, 387MB, compressed with 0.99 quality, and an output of nearly 20.3MB jpeg

all with no problems :thinking:

I'm going to need to investigate this

zbydown commented 7 months ago

and for jpg gainmap repack failed, my code:

    import { GainMapLoader, HDRJPGLoader, extractGainmapFromJPEG } from '@monogrid/gainmap-js'
    import { compress, encode, findTextureMinMax } from '@monogrid/gainmap-js/encode'
    import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr'

    async function loadImageAndGetDimensions(url) {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.onload = () => {
                resolve({ width: img.width, height: img.height });
            };
            img.onerror = reject;
            img.src = url;
        });
    }

    async function fetchAndDetermineImageDimensions(url) {
        const response = await fetch(url);
        const arrayBuffer = await response.arrayBuffer();
        const originalJpeg = new Uint8Array(arrayBuffer);
        const blob = new Blob([originalJpeg], { type: 'image/jpeg' });
        const newUrl = URL.createObjectURL(blob);

        const dimensions = await loadImageAndGetDimensions(newUrl);

        return dimensions;
    }

    process();

    async function process() {
        const inputUrl = 'textures/gainmap/03.jpg';
        const { width, height } = await fetchAndDetermineImageDimensions(inputUrl);
        const originalJpeg = new Uint8Array(await (await fetch(inputUrl)).arrayBuffer());

        const decodingResult = await extractGainmapFromJPEG(originalJpeg);

        const mimeType = 'image/jpeg';

        const sdr = {
            data: decodingResult.sdr,
            mimeType,
            width,
            height
        };

        const gainMap = {
            data: decodingResult.gainMap,
            mimeType,
            width,
            height
        };

        const jpeg = await encodeJPEGMetadata({
            ...decodingResult.metadata,
            sdr,
            gainMap
        });
    }

failed jpg: 03.zip

in fact 01.jpg and 02.jpg from adobe sample worked, but 03.jpg failed

zbydown commented 7 months ago

https://gainmap-creator.monogrid.com/

smallnew.zip

I think I uploaded wrong small one, this new one does not work in your creator

daniele-pelagatti commented 7 months ago

Alright, I found the problem in the code I used to instance the image in memory (which was copy/pasted from the official libultrahdr repository). It apparently didn't allow for odd sized images (width or height not divisible by two :eyes: )

I don't know why this restriction was there but I can't see any (apparent) reason it was needed.

I've opened pull request #31 on branch feature/odd-image-size-fix

Are you able to test your files using that branch and report? (you may need to run git submodule update you may need to cd libultrahdr-wasm and git checkout b077d0 after checking out the branch, make sure your libultrahdr-was folder contains the "fuzzer" folder, not present before)

The two files you sent now work for me but it would be better to have a complete report before merging, thanks!

zbydown commented 7 months ago

image I can not build libultrahdr-wasm on my mac (any version) previously I used the wasm/js file from your published npm package

daniele-pelagatti commented 7 months ago

libultrahdr-esm.zip try this one, also that error is present in newer emscripten versions but not the one used by the library, I've yet to understand why it happens (something to do with typescript definition generation?) but, for now, the latest supported emscripten version is 3.1.47 (I'll write it in the README)

zbydown commented 7 months ago

The issue with odd-sized images appears to be resolved with new libultrahdr-esm, I think the PR can be merged and this issue can be closed.

However, I've encountered a new issue related to decoding certain gainmap JPEGs. I plan to conduct further investigations on my own and will open a new issue once I have a better understanding of the problem.

Thanks