Skip to content

add support for encoding/decoding ultrahdr images#7198

Merged
urban-warrior merged 1 commit into
ImageMagick:mainfrom
ittiam-systems:uhdr
Mar 29, 2024
Merged

add support for encoding/decoding ultrahdr images#7198
urban-warrior merged 1 commit into
ImageMagick:mainfrom
ittiam-systems:uhdr

Conversation

@aayushsoni111

@aayushsoni111 aayushsoni111 commented Mar 26, 2024

Copy link
Copy Markdown
Contributor

Steps to build imagemagick with ultrahdr:

git clone https://github.com/google/libultrahdr.git && cd libultrahdr && mkdir build && cd build
cmake -G "Unix Makefiles" ../
make
git clone https://github.com/ImageMagick/ImageMagick.git && cd ImageMagick && mkdir build && cd build
mkdir uhdr
cp ../../libuhdr.a  ../../../ultrahdr_api.h ./uhdr && cd .. && automake && autoconf && autoheader
cd build && ../configure --enable-delegate-build=yes --with-uhdr && make

Change-Id: Id745d838ffc950d2a8ca158462271b9596d482c6

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practices as demonstrated in the repository.

Description

Steps to build imagemagick with ultrahdr:
git clone https://github.com/google/libultrahdr.git
cd libultrahdr && mkdir build && cd build
cmake -G "Unix Makefiles" ../
make
git clone https://github.com/ImageMagick/ImageMagick.git
cd ImageMagick && mkdir build && cd build
mkdir uhdr
cp ../../libuhdr.a  ../../../ultrahdr_api.h ./uhdr
cd .. && automake && autoconf && autoheader
cd build && ../configure --enable-delegate-build=yes --with-uhdr
make

Change-Id: Id745d838ffc950d2a8ca158462271b9596d482c6
@gregbenz

Copy link
Copy Markdown
Contributor

@aayushsoni111 could you provide guidance on an example ImageMagick command which could be used to take an SDR (JPG perhaps) and an HDR source image (10-bit AVIF perhaps) and encode them into a gain map JPG?

@gregbenz

Copy link
Copy Markdown
Contributor

@aayushsoni111 In the above build instructions at cd .. && automake && autoconf && autoheader, I'm seeing "error: 'configure.ac' is required"

At the last step cd build && ../configure --enable-delegate-build=yes --with-uhdr make, I'm seeing:

configure: WARNING: you should use --build, --host, --target
configure: WARNING: unrecognized options: --with-uhdr
checking build system type... Invalid configuration 'make': machine 'make-unknown' not recognized
configure: error: /bin/sh ../config/config.sub make failed

Any suggestions on what needs to be done here?

@urban-warrior urban-warrior merged commit 4b85373 into ImageMagick:main Mar 29, 2024
@urban-warrior

Copy link
Copy Markdown
Member

Thank you for your contribution. We had set aside this weekend to work on integrating the Ultra HDR delegate library. However, it seems that won't be necessary anymore. Instead, we'll focus on thoroughly testing your patch to ensure its robustness and security.

@arifdikic

Copy link
Copy Markdown

Thanks All, there's still bit of work to do , team will note the open items here.

@ram-mohan

ram-mohan commented Mar 29, 2024

Copy link
Copy Markdown
Contributor

@gregbenz
For Decode,
-> these will combine primary sdr and gain map to an hdr intent image. Output transfer function needs to be chosen

./utilities/magick -define uhdr:output-transfer-function=hlg mountains_uhdr_base.jpg out.heic
./utilities/magick -define uhdr:output-transfer-function=pq mountains_uhdr_base.jpg out.heic
./utilities/magick -define uhdr:output-transfer-function=linear mountains_uhdr_base.jpg out.heic

-> this will select only the primary sdr image to be written to heic

./utilities/magick -define uhdr:output-transfer-function=srgb mountains_uhdr_base.jpg out.heic

For Encode,

utilities/magick -define uhdr:hdr-color-transfer=hlg -define uhdr:hdr-color-gamut=bt2100 -define uhdr:sdr-color-gamut=bt709 mountains_8.miff mountains_16.miff mountains_uhdr.jpg

@ram-mohan

Copy link
Copy Markdown
Contributor

@gregbenz Basing on the error you are seeing, I think the some relative dir paths got mangled up.

@ram-mohan

Copy link
Copy Markdown
Contributor

@urban-warrior while testing uhdr.c, during to transcode to heic.c, I noticed a crash that was happening due to a problem in function WriteHEICImageRRGGBBAA, heic.c. If alpha channel is present, I noticed an out of bound access.

@harishdm

Copy link
Copy Markdown

@urban-warrior
Thank you for merging this pull request. Please let us know if you run into any issues and need some updates in these files.

https://docs.google.com/document/d/15dF92ofGfSerekwN-fAcGxYpwBkq9aCzhJZxmXoN4dE/edit?usp=sharing has some notes on the libultrahdr integration in ImageMagick.

This document has a list of todo tasks and also details on what is tested so far.
Can you please take a look?
Thanks.

@gregbenz

Copy link
Copy Markdown
Contributor

@ram-mohan Any idea what might be missing? I added a couple of line breaks to the build commands at the top of this page. Below is the code I used in MacOS Terminal with comments on results and the working directory at each stage.

Every step until the last one produces what seems like a reasonable response (as far as I can tell). Do you see any place where the path seems incorrect?

git clone https://github.com/google/libultrahdr.git # pulls libultrahdr, pwd = ROOT

cd libultrahdr && mkdir build && cd build # pwd => ROOT/libultrahdr/build

cmake -G "Unix Makefiles" ../ # creates content in build, same pwd (ROOT/libultrahdr/build)

make # at this point, I see creation of libultrahdr/build/ultrahdr_app, same pwd (ROOT/libultrahdr/build)

======
git clone https://github.com/ImageMagick/ImageMagick.git # creates as libultrahdr/build/ImageMagick, same pwd (ROOT/libultrahdr/build)

cd ImageMagick && mkdir build && cd build # pwd => ROOT/libultrahdr/build/ImageMagick/build

mkdir uhdr # same pwd (ROOT/libultrahdr/build/ImageMagick/build)

cp ../../libuhdr.a ../../../ultrahdr_api.h ./uhdr # same pwd (ROOT/libultrahdr/build/ImageMagick/build)

cd .. && automake && autoconf && autoheader # creates ROOT/libultrahdr/build/ImageMagick/autom4te.cache folder, creates ROOT/libultrahdr/build/ImageMagick/configure~, pwd => ROOT/libultrahdr/build/ImageMagick

cd build && ../configure --enable-delegate-build=yes --with-uhdr make # creates ROOT/libultrahdr/build/ImageMagick/build/config.log, and throws the errors below:

configure: WARNING: you should use --build, --host, --target
checking build system type... Invalid configuration 'make': machine 'make-unknown' not recognized
configure: error: /bin/sh ../config/config.sub make failed

@ram-mohan

Copy link
Copy Markdown
Contributor

@gregbenz ../configure --enable-delegate-build=yes --with-uhdr && make
make should be separate, can you try this.

@ram-mohan

Copy link
Copy Markdown
Contributor

@gregbenz just wanted to check if the build issue has resolved?

@gregbenz

Copy link
Copy Markdown
Contributor

@ram-mohan Ah, thanks! That missing line break was my problem.

I'm seeing the output and magick -version reports ImageMagick 7.1.1-29 Q16-HDRI aarch64 21991.

However, when I use the command to encode, the output is 2 standard JPG images, neither with an auxiliary image or gain map metadata. One is the SDR, and the other looks like an improperly encoded HDR, not a gain map. I'm not clear if the failure here is related to the type of source material I'm providing, my conversion commands, or something else. Any suggestions?

magick -depth 8 -sampling-factor 2x2 -colorspace YCbCr ./sdrSource.jpg ./temp/sdrSource.miff # convert sRGB SDR source

magick -depth 16 -sampling-factor 2x2 -colorspace YCbCr ./hdrSource.tif ./temp/hdrSource.miff # convert 32-bit linear Rec2020 HDR source

magick -define uhdr:hdr-color-transfer=hlg -define uhdr:hdr-color-gamut=bt2100 -define uhdr:sdr-color-gamut=bt709 ./temp/sdrSource.miff ./temp/hdrSource.miff ./final/output.jpg # this is producing output-0.jpg (looks like sdrSource.jpg) and output-1.jpg (looks HDR pixels with wrong encoding more than a gain map)

@ram-mohan

Copy link
Copy Markdown
Contributor

@gregbenz can you please share the input images. I can try from my side once.

@urban-warrior

urban-warrior commented Mar 30, 2024

Copy link
Copy Markdown
Member

We've implemented several patches to enhance support for UHDR in ImageMagick. Currently, we've removed the UHDR calls from JPEG since they wouldn't function properly anyway, and we don't advocate direct calls from one coder to another. Instead, for any UHDR disguised as JPEG, use udhr:myImage.jpeg.

This version maintains clarity while improving readability and coherence.

As expected, there is still work to do. We will evolve UHDR support over time.

@harishdm

Copy link
Copy Markdown

@urban-warrior Thank you for further changes for the uhdr integration.
Our initial implementation had UHDR as a separate coder, but we ran into issues in differentiating jpg and uhdr jpg files.
Your approach of prefixing uhdr: works great and keeps the coders independent.
This approach also works well once libultrahdr supports HEIF/AVIF.

We will continue to work on the TODO items listed in the doc above.
Please let us know if there are any updates needed in libultrahdr that would help in ImageMagick integration.
Thanks.

@harishdm harishdm deleted the uhdr branch March 30, 2024 15:46
@urban-warrior

urban-warrior commented Mar 30, 2024

Copy link
Copy Markdown
Member

We require a dynamic build of libutltrahdr (.so) and support for make install to install both the library and the headers in standard locations like /usr/local. Is this already available? If so, what are the cmake arguments for the dynamic build and method to install?

The header files should be copied to /usr/local/ultrahdr-1 on install. This setup ensures that the builds for ImageMagick and libultrahdr remain entirely independent of each other. Once that's available, we'll take a closer look at the uhdr.c coder. We want to ensure its robust before we push an ImageMagick release. Thanks.

@harishdm

Copy link
Copy Markdown

Sure. We will work towards updating libultrahdr to support dynamic library and to install in standard locations.

@GrousexyHKCN

GrousexyHKCN commented Jul 4, 2024

Copy link
Copy Markdown

hi guys, i follow the ''Steps to build imagemagick with ultrahdr''

however i found some strange problem that magick -version reports that: Version: ImageMagick 7.1.1-35 (Beta) Q16-HDRI aarch64 9980efa:20240702 https://imagemagick.org....... Features: Cipher DPC HDRI ;Delegates (built-in): bzlib uhdr x; Compiler: gcc (4.2);
it seems that there is no decoders for jpeg, tiff.....and any other format.

when i try ../configure --with-jpeg , the value of --with-jpeg still No.

and when i try ./utilities/magick -define uhdr:output-transfer-function=hlg mountains_uhdr_base.jpg out.heic, it reports that
magick: UnableToOpenConfigureFile delegates.xml' @ warning/configure.c/GetConfigureOptions/722. magick: NoDecodeDelegateForThisImageFormat JPG' @ error/constitute.c/ReadImage/746.

when i try ./utilities/magick -define uhdr:hdr-color-transfer=hlg -define uhdr:hdr-color-gamut=bt2100 -define uhdr:sdr-color-gamut=bt709 mountains_8.miff mountains_16.miff uhdr:mountains_uhdr.jpg, it reports that
magick: invalid range, expects one of {UHDR_CR_FULL_RANGE, UHDR_CR_LIMITED_RANGE} uhdr:mountains_uhdr.jpg' @ error/uhdr.c/WriteUHDRImage/829.`

any possible solution?

@fmw42

fmw42 commented Jul 4, 2024

Copy link
Copy Markdown

If you built from source code, you will need to install all the delegates that you need prior to installing Imagemagick. You cannot just use --with--XYZ. That only enables it if you already have it installed. However, that is not usually necessary if you install your delegates and be sure that they are in your $PATH.

Please always identify your IM version and platform/OS. It looks like you are on a Mac using arch64 platform. You can install delegates with either Homebrew or MacPorts, then install Imagemagick from source.

@ram-mohan

Copy link
Copy Markdown
Contributor

@GrousexyHKCN error message, "expects one of {UHDR_CR_FULL_RANGE, UHDR_CR_LIMITED_RANGE}" is due to missing initialization in uhdr.c. This was not a problem a while back but as more changes were pushed to libultrahdr this error is seen. We will issue a pull request that resolves this. thank you

@GrousexyHKCN

Copy link
Copy Markdown

If you built from source code, you will need to install all the delegates that you need prior to installing Imagemagick. You cannot just use --with--XYZ. That only enables it if you already have it installed. However, that is not usually necessary if you install your delegates and be sure that they are in your $PATH.

Thanks for your reply!
i use Macbook air m2 and directly download IM from source code so i believe it is the latest version. I have installed jpeg, libtiff and other delegates via homebrew before i install IM but still can not be recognized so i ask the above question. Maybe there is other ways to build ultrahdr with imagemagick?

@fmw42

fmw42 commented Jul 4, 2024

Copy link
Copy Markdown

You may have to point IM to where Homebrew installed your delegates in your config command. This is what I had used before when installing using MacPorts. Add this to your .configuration command and change the directory to where Homebrew installs.

CPPFLAGS='-I/opt/local/include' LDFLAGS='-L/opt/local/lib' \

Also be sure your path the your jpeg and libtiff (and any other delegates) are in your $PATH.

@ram-mohan

ram-mohan commented Jul 4, 2024

Copy link
Copy Markdown
Contributor

@GrousexyHKCN

assuming libjpeg is already installed, below steps should work

first install libultrahdr

git clone https://github.com/google/libultrahdr.git && cd libultrahdr && mkdir build && cd build
cmake -G "Unix Makefiles" ../
make
sudo make install

clone image magick and configure with uhdr enabled

git clone https://github.com/ImageMagick/ImageMagick.git && cd ImageMagick && mkdir build && cd build
../configure --with-uhdr && make

@isenberg

isenberg commented Sep 29, 2024

Copy link
Copy Markdown

In case others get stuck on Homebrew on macOS building it: It failed for with a conflict between two libjpeg versions in libultrahdr and ImageMagick. Solved with this to point it to libjpeg-turbo instead of libjpeg, all in one line:

CFLAGS="-Iopt/homebrew/opt/libjpeg-turbo/include" LDFLAGS="-L/opt/homebrew/opt/libjpeg-turbo/lib"
../configure --enable-delegate-build=yes --with-uhdr

Example command to create an UltraHDR JPEG:

magick -define uhdr:hdr-color-gamut=bt709 -define uhdr:hdr-color-transfer=hlg \
\( img_sdr.tif -depth 8 \)  \( img_hdr.tif -depth 16 \) uhdr:ultrahdr.jpg

If you see two images as output, like ultrahdr-0.jpg and ultrahdr-1.jpg, then your magick wasn't really built with this new uhdr support. Above example uses bt709 as that's almost sRGB which my input HDR was. Most recent update to this was last week: #7635

@gregbenz

Copy link
Copy Markdown
Contributor

libultra is working extremely well these days. It would be ideal if IM would use the library by default when transcoding (crop/compress/resize) from a support JPG gain map source image and not explicitly requesting a different output (something other than JPG, or deliberate conversion to SDR only or HDR only). Preserving the gain map by default should help support propagate without requiring updates from downstream users of IM.

To support this, I'm assuming IM would need to test that an image has a gain map and then use libultra or the standard JPG library as appropriate. Libultra has a function which can test the source image: google/libultrahdr#137 (reply in thread)

@urban-warrior, I would love to hear your thoughts on moving in this direction to allow JPG gain maps to be supported by default (preserved) when working with a gain map input. Do you agree that is the right direction, and do you believe we are at a state where testing default support in IM would make sense?

@urban-warrior

Copy link
Copy Markdown
Member

By default '.jpg' or '.jpeg' would produce standard JPEG images. With a define, we can optionally write UHDR images if the gain map is present otherwise standard JPEG.

For Linux, its up to the RPM package maintainers to include UHDR support. For Windows, @dlemstra, can we include support for UHDR images in future builds? If so, what would be the approximate ETA?

@isenberg

Copy link
Copy Markdown

The -define also as the advantage that stepwise further support can be added for other IM functions. Most will most likely currently just drop the gainmap when writing their output but it can be added individually then later to some functions to consider the gainmap to process.

@ram-mohan

Copy link
Copy Markdown
Contributor

There is one api we would like to add to uhdr.c. link. This is introduced in android 15. we are currently working on it. will issue a pull request once this done.

@dlemstra

Copy link
Copy Markdown
Member

For Linux, its up to the RPM package maintainers to include UHDR support. For Windows, @dlemstra, can we include support for UHDR images in future builds? If so, what would be the approximate ETA?

The ETA depends on how easy it would be to add this library as a dependency. Adding this is not high on my priority list so I don't know when I will start on adding this extra dependency.

@gregbenz

Copy link
Copy Markdown
Contributor

@ram-mohan Does the IM integration already include flags which would allow control of parameters relevant to cropping,
resizing, and compression quality?

Is there a set of default quality parameters if they are not provided?

@ram-mohan

Copy link
Copy Markdown
Contributor

@ram-mohan Does the IM integration already include flags which would allow control of parameters relevant to cropping, resizing, and compression quality?

Is there a set of default quality parameters if they are not provided?

The list of options supported by uhdr plugin is listed here, https://github.com/ImageMagick/Website/pull/107/commits. Further cropping, resizing, ... other IM features/options should work as usual.

@kmilos

kmilos commented Oct 28, 2024

Copy link
Copy Markdown
Contributor

The ETA depends on how easy it would be to add this library as a dependency.

libultrahdr is not yet packaged for a lot of distros (e.g. Debian and Fedora to begin with as largest bases for other derivatives), and for Windows it is only available via MSYS2, not vcpkg... No macOS presence either ATM (Homebrew nor MacPorts).

So anyone interested should start requesting it through the appropriate channels.

@ram-mohan

Copy link
Copy Markdown
Contributor

we have made some progress towards building packages. google/libultrahdr@202e5c3

For homebrew, Homebrew/homebrew-core@master...ram-mohan:homebrew-core:uhdr

@isenberg

isenberg commented Oct 28, 2024 via email

Copy link
Copy Markdown

@isenberg

isenberg commented Oct 28, 2024 via email

Copy link
Copy Markdown

@t0saki

t0saki commented Nov 16, 2024

Copy link
Copy Markdown

Hello,

I would like to ask if there is currently a recommended set of parameters or process to convert HEIC images shot on an iPhone to AVIF format while preserving HDR, specifically the GainMap data. As far as I know, the HDR GainMap implementation for these two formats should be somewhat similar.

When I perform a straightforward conversion using 7.1.1-40 HDRI version with the following command, the output image does not display HDR effects when viewed on an iPhone:

magick IMG_xxxx.HEIC IMG_xxxx.AVIF

Is there a way to ensure that the HDR information is preserved during the conversion? Any guidance or examples would be greatly appreciated.

Thank you!

@pallosp

pallosp commented Feb 2, 2025

Copy link
Copy Markdown

I'm trying to upload a couple of 10-bit HEIC images shot by Nikon Z6 III to Google Photos. AFAIK, the only HDR format it currently supports is JPG with a gain map. Does this conversion already work in the experimental ImageMagick build?

@isenberg

isenberg commented Feb 2, 2025

Copy link
Copy Markdown

Yes, works for me with the generated JPGs with IM+uhdr in Google Photos. If yours don't work, check out mine generated on my mars20 website linked from my profile.

@pallosp

pallosp commented Feb 5, 2025

Copy link
Copy Markdown

I'm currently stuck at building ImageMagick on MacOS. I ran brew install libjpeg and brew install libheif then followed the instructions in ram-mohan's comment, also passing --with-heic, --with-jpeg and --enable-delegate-build=yes to configure.

For some reason my build can't decode either JPG or HEIC:

$ ./utilities/magick identify --verbose ~/Pictures/DSC_0112.HIF

identify: UnableToOpenConfigureFile `delegates.xml' @ warning/configure.c/GetConfigureOptions/722.
identify: NoDecodeDelegateForThisImageFormat `' @ error/constitute.c/ReadImage/746.
identify: NoDecodeDelegateForThisImageFormat `HIF' @ error/constitute.c/ReadImage/746.

$ ./utilities/magick ~/Pictures/DSC_0112.HIF ~/Pictures/DSC_0112.JPG

magick: UnableToOpenConfigureFile `delegates.xml' @ warning/configure.c/GetConfigureOptions/722.
magick: NoDecodeDelegateForThisImageFormat `HIF' @ error/constitute.c/ReadImage/746.

@pallosp

pallosp commented Feb 5, 2025

Copy link
Copy Markdown

Update: I managed to build ImageMagick with libultrahdr with the help of the google/libultrahdr#89 thread and did my first conversion:

magick DSC_0055.HIF -define uhdr:hdr-color-transfer=hlg UHDR:DSC_0055.JPG

Chrome and the MacOS Preview show the result in HDR, but Google Photos falls back to the SDR image. What do I need to do to make Google Photos display the full dynamic range?

@kmilos

kmilos commented Feb 5, 2025

Copy link
Copy Markdown
Contributor

I managed to build ImageMagick with libultrahdr

@pallosp Why not request IM is built --with-uhdr in Homebrew (or even send a PR) since the library is now available there?

@gregbenz

gregbenz commented Feb 5, 2025

Copy link
Copy Markdown
Contributor

What do I need to do to make Google Photos display the full dynamic range?

You can confirm any gain map using the Adobe Gain Map Demo app (https://helpx.adobe.com/camera-raw/using/gain-map.html#resources). It is an outstanding resource and very reliable.

It will tell you in the far right side of the image is a gain map. If you click ctrl/cmd-I, it will show an overlay and confirm if the encoding is the ISO spec or another spec (Android using IM as that's libultra's default). If the image has dual encoding (ISO plus some XMP spec), it will simply list ISO and not mention the backup (ISO takes priority in any reader supporting it).

Libultra supports Android XMP by default and ISO when enabled in a compile flag. I would assume the current implementation of IM doesn't have ISO enabled. I believe that is safe and would be ideal to enable with the current libuotra code base (I have tested a large number of dual-encoded gain map exports from libultra and it has been working very well with the latest versions - support from various browsers/decoders has been robust).

It sounds like you have valid output. Once confirmed, that would indicate the issue was in subsequent transcoding after encoding via IM (such as uploading to a service or what it might deliver based on your device/browser). You'd have to work with that service to request HDR gain map support, as that would be outside the scope of IM and this thread.

More resources and info: https://gregbenzphotography.com/hdr/#developers

@pallosp

pallosp commented Feb 5, 2025

Copy link
Copy Markdown

Thanks a lot for the debugging tips.

According to Adobe Gain Map Demo my Pixel 9 photos have Adobe / Ultra HDR gain map type, while the Nikon HEIC photos converted by IM have ISO 21496-1. I believe that libultrahdr should be able to generate gain maps in a format that Google Photos understands. @isenberg had some positive results too.

@gregbenz

gregbenz commented Feb 5, 2025

Copy link
Copy Markdown
Contributor

@pallosp libultrahdr supports both of those formats, but only uses the Android XMP spec by default (which shows as "Adobe / Ultra HDR" in the demo app). IM may need to be updated to enable this flag for ISO encoding with the latest libultrahdr. That said, if you aren't seeing Google Photos support the Android spec, it likely isn't supporting any spec in that scenario (Google widely supports their Android encoding, and libultrahdr is created by Google). The only place I can think of where the ISO adds extra value right now is on Apple's latest operating systems, which supports ISO encoding (and their proprietary Apple XMP encoding), but not the Android/Adobe XMP spec.

@ram-mohan What are your thoughts here? Would you agree that enabling dual encoding by default in libultrahdr is ok at this time? And if so, what is the best way to enable that for IM's use of libultrahdr?

@isenberg

isenberg commented Feb 5, 2025

Copy link
Copy Markdown

Last week I noticed how the Adobe Gainmap Demo app on macOS showed my gainmap JPEGs created with IM+libuhdr as ISO-gainmap JPEG. So it looks like current IM has it already enabled by default.

@ram-mohan

Copy link
Copy Markdown
Contributor

The current default cmake build configuration of libultrahdr enables iso and disables xmp. So brew install libultrahdr will install the built library which has iso enabled and xmp disabled. So applications that do not support iso and support only xmp can have problems viewing the generated image. whether the jpg image generated has xmp or iso metadata is dependent on the uhdr library and not on IM. If only xmp is desired and not iso, then the library has to built with option UHDR_WRITE_XMP enabled and option UHDR_WRITE_ISO disabled, installed.

@pallosp

pallosp commented Feb 9, 2025

Copy link
Copy Markdown

Thanks a lot guys! You're awesome!

I managed to convert a 10-bit HEIF to a Google Photos compatible Ultra HDR JPG. Here's the complete list of steps:

  1. Uninstall any previous imagemagick and libultrahdr versions:
    brew uninstall imagemagick
    brew uninstall libultrahdr
  2. Download libultrahdr.rb from the GitHub page linked from https://formulae.brew.sh/formula/libultrahdr
  3. Open it with a text editor, and update the first cmake call under def install to
    system "cmake", "-S", ".", "-B", "build", *std_cmake_args, "-DUHDR_WRITE_XMP=ON"
    
  4. Install the modified version:
    brew tap-new me/local
    mv ./libultrahdr.rb $(brew --repository me/local)/Formula/
    brew install --build-from-source me/local/libultrahdr.rb
    
  5. Download imagemagick.rb from the GitHub page linked from https://formulae.brew.sh/formula/imagemagick
  6. Open it with a text editor. Add depends_on "libultrahdr" to the dependency section, and "--with-uhdr=yes", to the args section
  7. Install the modified version:
    mv ./imagemagick.rb $(brew --repository me/local)/Formula/
    brew install --build-from-source me/local/imagemagick.rb
    
  8. (Optional) Verify that magick --version lists uhdr under Delegates (built-in)
  9. Do the conversion:
    for file in *.HIF; do
      magick \
          -define uhdr:hdr-color-transfer=hlg \
          -define uhdr:hdr-color-gamut=bt2100 \
          -define uhdr:sdr-color-gamut=bt709 \
          -define uhdr:gainmap-quality=80 \
          "$file" uhdr:"${file%.*}.jpg"
    done
    
  10. (Optional) Verify the result:
    • exiftool converted.jpg | grep -A6 XMP should find the gain map
    • The Info window in the Mac Preview app (Cmd+I) should report Depth: 10
    • The Info panel in Google Photos (press I) should show Ultra HDR under the file name
    • Note that Adobe Gain Map Demo App doesn't recognize the dual gain map, and will only show ISO 21496-1 in the Info overlay (Cmd+I)

@gregbenz

gregbenz commented Feb 9, 2025

Copy link
Copy Markdown
Contributor

@pallosp Thank you for sharing all that great detail!

FYI that the Adobe Gain Map Demo app will only list ISO encoding if both that and the Ultra encoding (Android XMP) are in the file. So that tool won't mention the backup (Ultra) encoding. You can examine the file manually with something like EXIFTOOL to confirm the XMP when enabling both encodings, but it isn't necessary (it will just work if you turn on both).

It would generally be ideal to either encode both ISO + Ultra (most compatible today) or ISO only (as this saves about 2K in file size).

Turning off the ISO encoding (ie DUHDR_WRITE_ISO=OFF) will prevent HDR support on Apple devices and generally means a file which is less forward compatible as everything moves towards ISO as the key way of encoding the gain maps. Dual encoding works great everywhere I've tested with the latest libultrahdr (there was an older bug where the map was truncated when dual encoding, but that was resolved over a month ago). I would avoid disabling the ISO encoding.

@pallosp

pallosp commented Feb 10, 2025

Copy link
Copy Markdown

SGTM. I tested dual gain maps, and updated the list of steps.

BTW, is UHDR support in ImageMagick ready to be enabled by default? Does it need further testing or documentation?

@ram-mohan

Copy link
Copy Markdown
Contributor

the reason the library defaults to iso over xmp because, current xmp implementation of the library does not support signalling multi channel gainmap metadata. So if xmp is enabled, in multi channel gainmap encoding, gainmap images contains 3 channels but the metadata is same for all of them. For signalling multi channel gainmap metadata, there by preserving better detail library defaults to iso only and xmp disabled.

@pallosp

pallosp commented Feb 12, 2025

Copy link
Copy Markdown

I understand that multi-channel gain maps are quirky, and ISO is the future.

My request was not about changing the default gain map type in libultrahdr, but about linking ImageMagick with libultrahdr. That would halve the amount of tinkering required for creating Google Photos compatible HDR images. Is it reasonable?

@gregbenz

Copy link
Copy Markdown
Contributor

@pallosp XMP encoding is necessary for a few applications, but ISO works for most. Going forward, XMP-only images may lack support, so I recommend everything newly encoded includes ISO (either on its own or dual encoded with the Android XMP, as libultrahdr does).

While optimizing the red, green, and blue channels in the map metadata improves results theoretically and in testing, I have not seen a visible improvement in image quality across numerous test images. So dual encoding (which will cause single-channel metadata in libultra as the XMP does not support it) seems perfectly fine to me.

No perfect answer here, but I believe dual encoding now has much more benefit than downside. And switching to ISO-only encoding at some point in the future (when XMP-only decoding / transcoding is no longer a concern) will be ideal to reduce file size slightly (and allow the multi-channel optimization in this case).

@caydenm

caydenm commented May 3, 2025

Copy link
Copy Markdown

In case it helps anyone else, I used this for my Sony A6700 HIF with HLG to upload to Google Photos with Ultra HDR and the colours matching the bt2100 gamut that is set.

for file in *.HIF; do
  magick "$file" -define uhdr:hdr-color-transfer=hlg -define uhdr:hdr-color-gamut=bt2100 -define uhdr:sdr-color-gamut=bt2100 UHDR:"${file%.*}.jpg" 
done

Thanks @pallosp for the great guide above!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.