Karel Tomanec - 2025-01-29

Description

When saving a .exr file using FreeImage with a FIBITMAP of type
FIT_RGBF and the EXR_FLOAT flag, the resulting file is saved with a
16-bit depth per channel instead of the expected 32-bit float depth. This
behavior persists even though the EXR_FLOAT flag is explicitly passed to
the FreeImage_Save function.

My code:

Click to expand code
#include <FreeImage.h>
#include <iostream>
#include <string>

FIBITMAP* CreateTestImage(unsigned width, unsigned height)
{
FIBITMAP* bitmap = FreeImage_AllocateT(FIT_RGBF, width, height);
if (!bitmap)
{
std::cerr << "Failed to allocate image." << std::endl;
return nullptr;
}

// Fill the image with a gradient
float* bits = reinterpret_cast<float*>(FreeImage_GetBits(bitmap));
for (unsigned y = 0; y < height; ++y)
{
for (unsigned x = 0; x < width; ++x)
{
unsigned index = (y * width + x) * 3;
bits[index + 0] = static_cast<float>(x) / width;
bits[index + 1] = static_cast<float>(y) / height;
bits[index + 2] = 0.5f;
}
}

return bitmap;
}

void SaveTestImage(const std::string& filename, FIBITMAP* bitmap, int flags)
{
if (!bitmap)
{
std::cerr << "Invalid bitmap, cannot save." << std::endl;
return;
}

unsigned width = FreeImage_GetWidth(bitmap);
unsigned height = FreeImage_GetHeight(bitmap);
unsigned bpp = FreeImage_GetBPP(bitmap);
FREE_IMAGE_TYPE type = FreeImage_GetImageType(bitmap);

std::cout << "Image properties:" << std::endl;
std::cout << "  Width: " << width << std::endl;
std::cout << "  Height: " << height << std::endl;
std::cout << "  Bits per pixel: " << bpp << std::endl;
std::cout << "  Image type: " << type << std::endl;

std::cout << "Saving image to " << filename << "..." << std::endl;
if (FreeImage_Save(FIF_EXR, bitmap, filename.c_str(), flags))
{
std::cout << "Image saved successfully: " << filename << std::endl;
}
else
{
std::cerr << "Failed to save image: " << filename << std::endl;
}
}

int main()
{
FreeImage_Initialise();

const unsigned width = 512;
const unsigned height = 512;
const std::string filename = "test_image.exr";

FIBITMAP* bitmap = CreateTestImage(width, height);
if (!bitmap)
{
FreeImage_DeInitialise();
return 1;
}

int flags = EXR_FLOAT;
SaveTestImage(filename, bitmap, flags);

FreeImage_Unload(bitmap);
FreeImage_DeInitialise();

return 0;
}

magick output:

Click to expand loge
 magick identify -verbose test_image.exr
Image:
  Filename: test_image.exr
  Permissions: rw-rw-rw-
  Format: EXR (High Dynamic-range (HDR))
  Class: DirectClass
  Geometry: 512x512+0+0
  Units: Undefined
  Colorspace: sRGB
  Type: TrueColor
  Base type: Undefined
  Endianness: Undefined
  Depth: 16-bit
  Channels: 3.0
  Channel depth:
    Red: 16-bit
    Green: 16-bit
    Blue: 16-bit
  Channel statistics:
    Pixels: 262144
    Red:
      min: 0  (0)
      max: 65407 (0.998047)
      mean: 32703.5 (0.499023)
      median: 32639.5 (0.498047)
      standard deviation: 18918.3 (0.288675)
      kurtosis: -1.20002
      skewness: -9.10919e-10
      entropy: 1
    Green:
      min: 0  (0)
      max: 65407 (0.998047)
      mean: 32703.5 (0.499023)
      median: 32639.5 (0.498047)
      standard deviation: 18918.3 (0.288675)
      kurtosis: -1.20002
      skewness: -9.10884e-10
      entropy: 1
    Blue:
      min: 32767.5  (0.5)
      max: 32767.5 (0.5)
      mean: 32767.5 (0.5)
      median: 32767.5 (0.5)
      standard deviation: 0 (0)
      kurtosis: 0
      skewness: 0
      entropy: 0
  Image statistics:
    Overall:
      min: 0  (0)
      max: 65407 (0.998047)
      mean: 32724.8 (0.499349)
      median: 32682.2 (0.498698)
      standard deviation: 12612.2 (0.19245)
      kurtosis: -0.800015
      skewness: -6.07268e-10
      entropy: 0.666667
  Rendering intent: Perceptual
  Gamma: 1
  Chromaticity:
    red primary: (0.64,0.33,0.03)
    green primary: (0.3,0.6,0.1)
    blue primary: (0.15,0.06,0.79)
    white point: (0.3127,0.329,0.3583)
  Matte color: grey74
  Background color: white
  Border color: srgb(223,223,223)
  Transparent color: black
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 512x512+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: Piz
  Orientation: Undefined
  Properties:
    date:create: 2025-01-28T10:44:56+00:00
    date:modify: 2025-01-28T11:12:23+00:00
    date:timestamp: 2025-01-28T11:18:29+00:00
    signature:
e3e00cda1b1142bd3ac1a130f916bddddfdde7e6f4442f15fa24bef51628bfe3
  Artifacts:
    verbose: true
  Tainted: False
  Filesize: 203153B
  Number pixels: 262144
  Pixel cache type: Memory
  Pixels per second: 48.2761MP
  User time: 0.005u
  Elapsed time: 0:01.005
  Version: ImageMagick 7.1.1-36 Q16-HDRI x64 852a4e9:20240727
https://imagemagick.org

Expected Behaviour

The .exr file should be saved with 32-bit float depth per channel.