From c4c4a13b48a4b6aa75ded6531eb7dabbd1d2b9bd Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Mon, 8 Jun 2026 12:47:19 +0200 Subject: [PATCH] Add support for decoding fp16 TIFF images --- src/codecs/tiff.rs | 18 +++++++++++++++++ src/color.rs | 19 +++++++++++++++++- tests/images/tiff/testsuite/random-fp16.tiff | Bin 0 -> 621 bytes .../tiff/testsuite/random-fp16.tiff.png | Bin 0 -> 520 bytes tests/reference_images.rs | 6 ++++++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/images/tiff/testsuite/random-fp16.tiff create mode 100644 tests/reference/tiff/testsuite/random-fp16.tiff.png diff --git a/src/codecs/tiff.rs b/src/codecs/tiff.rs index 43fb401f41..d1fa68f000 100644 --- a/src/codecs/tiff.rs +++ b/src/codecs/tiff.rs @@ -126,6 +126,7 @@ where (tiff::ColorType::Gray(1), Uint) => ColorType::L8, (tiff::ColorType::Gray(8), Uint) => ColorType::L8, (tiff::ColorType::Gray(16), Uint) => ColorType::L16, + (tiff::ColorType::Gray(16), IEEEFP) => ColorType::L32F, (tiff::ColorType::Gray(32), IEEEFP) => ColorType::L32F, (tiff::ColorType::GrayA(8), Uint) => ColorType::La8, (tiff::ColorType::GrayA(16), Uint) => ColorType::La16, @@ -135,6 +136,8 @@ where (tiff::ColorType::RGBA(16), Uint) => ColorType::Rgba16, (tiff::ColorType::CMYK(8), Uint) => ColorType::Rgb8, (tiff::ColorType::CMYK(16), Uint) => ColorType::Rgb16, + (tiff::ColorType::CMYK(16), IEEEFP) => ColorType::Rgb32F, + (tiff::ColorType::RGBA(16), IEEEFP) => ColorType::Rgba32F, (tiff::ColorType::RGB(32), IEEEFP) => ColorType::Rgb32F, (tiff::ColorType::RGBA(32), IEEEFP) => ColorType::Rgba32F, (tiff::ColorType::YCbCr(8), Uint) => ColorType::Rgb8, @@ -152,6 +155,9 @@ where (tiff::ColorType::CMYK(8), Uint) => ExtendedColorType::Cmyk8, (tiff::ColorType::CMYK(16), Uint) => ExtendedColorType::Cmyk16, (tiff::ColorType::YCbCr(8), Uint) => ExtendedColorType::YCbCr8, + (tiff::ColorType::Gray(16), IEEEFP) => ExtendedColorType::L16F, + (tiff::ColorType::CMYK(16), IEEEFP) => ExtendedColorType::Rgb16F, + (tiff::ColorType::RGBA(16), IEEEFP) => ExtendedColorType::Rgba16F, _ => color_type.into(), }; @@ -534,6 +540,18 @@ impl ImageDecoder for TiffDecoder { ycbcr_to_rgb8(ycbcr, lr, lg, lb, out); } + DecodingResult::F16(v) + if matches!( + info.original_color_type, + ExtendedColorType::L16F + | ExtendedColorType::Rgb16F + | ExtendedColorType::Rgba16F + ) => + { + for (half, out) in v.iter().zip(buf.as_chunks_mut::<4>().0.iter_mut()) { + *out = half.to_f32().to_ne_bytes(); + } + } DecodingResult::U8(v) => { buf.copy_from_slice(v); } diff --git a/src/color.rs b/src/color.rs index 80c0955b11..4c24ecf831 100644 --- a/src/color.rs +++ b/src/color.rs @@ -153,7 +153,16 @@ pub enum ExtendedColorType { /// Pixel is 8-bit BGR with an alpha channel Bgra8, - // TODO f16 types? + // TODO: Should the new f16 types come after Ycbcr8 for serde backwards compatibility? + /// Pixel is 16-bit float luminance + L16F, + /// Pixel is 16-bit float luminance with an alpha channel + La16F, + /// Pixel is 16-bit float RGB + Rgb16F, + /// Pixel is 16-bit float RGBA + Rgba16F, + /// Pixel is 32-bit float luminance L32F, /// Pixel is 32-bit float luminance with an alpha channel @@ -191,6 +200,7 @@ impl ExtendedColorType { | ExtendedColorType::L4 | ExtendedColorType::L8 | ExtendedColorType::L16 + | ExtendedColorType::L16F | ExtendedColorType::L32F | ExtendedColorType::Unknown(_) => 1, ExtendedColorType::La1 @@ -198,6 +208,7 @@ impl ExtendedColorType { | ExtendedColorType::La4 | ExtendedColorType::La8 | ExtendedColorType::La16 + | ExtendedColorType::La16F | ExtendedColorType::La32F => 2, ExtendedColorType::Rgb1 | ExtendedColorType::Rgb2 @@ -205,6 +216,7 @@ impl ExtendedColorType { | ExtendedColorType::Rgb5x1 | ExtendedColorType::Rgb8 | ExtendedColorType::Rgb16 + | ExtendedColorType::Rgb16F | ExtendedColorType::Rgb32F | ExtendedColorType::YCbCr8 | ExtendedColorType::Bgr8 => 3, @@ -213,6 +225,7 @@ impl ExtendedColorType { | ExtendedColorType::Rgba4 | ExtendedColorType::Rgba8 | ExtendedColorType::Rgba16 + | ExtendedColorType::Rgba16F | ExtendedColorType::Rgba32F | ExtendedColorType::Bgra8 | ExtendedColorType::Cmyk8 @@ -246,6 +259,10 @@ impl ExtendedColorType { ExtendedColorType::La16 => 32, ExtendedColorType::Rgb16 => 48, ExtendedColorType::Rgba16 => 64, + ExtendedColorType::L16F => 16, + ExtendedColorType::La16F => 32, + ExtendedColorType::Rgb16F => 48, + ExtendedColorType::Rgba16F => 64, ExtendedColorType::L32F => 32, ExtendedColorType::La32F => 64, ExtendedColorType::Rgb32F => 96, diff --git a/tests/images/tiff/testsuite/random-fp16.tiff b/tests/images/tiff/testsuite/random-fp16.tiff new file mode 100644 index 0000000000000000000000000000000000000000..77b7a276c3fe5a56e7a82634e4e39ff25a87075a GIT binary patch literal 621 zcmebD)MChEWMHV6<2%9HgV|A_jo+nJh-y>l>MmTCIE4?We3jn+;HM{LrZIqEt!`XJN=~XRIz7`$=2s%pT?Z~V){#KPxt@o-n_v558g5CdbBp! z-?*4%c@XEp4O}L1m9xu#Z@sK@efm}YyC>c@eNoJ=4La0vb??c9iO(MT$rqp3JNNMp zud&8oPg~abGv8jd@NK*#Z=KS(l|hh!fsvU37~Bj3K+K55W}}XpyEI#Lok%h3}l0V4$wT1+hDYFQEFmIYKlU6W=V#EyQgmegHvL1c6w2M IXZ} z?^M0_^}WF6&HGTd24#+EyP}dH@!Xgwsa*$2Dws@Ks1*~DMkX|{?u zVMEum4=?)l5kJV;ah0TIiqkc3R`}*87u=ozat82tMQ-eYIH$X(26O9_C-R*8>Mz59 z0R@-l^je;71@65Vual;|4 zCi31NwSW4*E=Ojmrr3E=!|f8VS1;59Ul0=W>Iyc|g~CVOqE-PJ49%IDH3Pc<0000< KMNUMnLSTa1lk?*M literal 0 HcmV?d00001 diff --git a/tests/reference_images.rs b/tests/reference_images.rs index 1188f0512c..acb1007b41 100644 --- a/tests/reference_images.rs +++ b/tests/reference_images.rs @@ -133,6 +133,12 @@ fn main() -> std::process::ExitCode { if reference_format == ImageFormat::Png && image_format == Some(ImageFormat::Tiff) { match test_img { + DynamicImage::ImageLuma32F(_) => { + test_img = test_img.to_luma16().into(); + } + DynamicImage::ImageLumaA32F(_) => { + test_img = test_img.to_luma_alpha16().into(); + } DynamicImage::ImageRgb32F(_) => { test_img = test_img.to_rgb16().into(); }