Skip to content

Commit 4c9ac29

Browse files
committed
feat(heif): Read and write CICP, and do RGB to YUV encoding on write
1 parent 11715d1 commit 4c9ac29

12 files changed

+240
-4
lines changed

src/doc/builtinplugins.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,12 @@ preferred except when legacy file access is required.
688688
- string
689689
- Color space (see Section :ref:`sec-metadata-color`). We currently
690690
assume that any RGBE files encountered are linear with sRGB primaries.
691+
* - ``CICP``
692+
- int[4]
693+
- Coding-independent code points to describe the color profile.
694+
* - ``oiio:BitsPerSample``
695+
- int
696+
- Bits per sample in the file: 8, 10 or 12.
691697
* - ``heif:Orientation``
692698
- int
693699
- If the configuration option ``heif:reorient`` is nonzero and

src/heif.imageio/heifinput.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ class HeifInput final : public ImageInput {
3636
const char* format_name(void) const override { return "heif"; }
3737
int supports(string_view feature) const override
3838
{
39-
return feature == "exif";
39+
return feature == "exif"
40+
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
41+
|| feature == "cicp"
42+
#endif
43+
;
4044
}
4145
bool valid_file(const std::string& filename) const override;
4246
bool open(const std::string& name, ImageSpec& newspec) override;
@@ -264,6 +268,30 @@ HeifInput::seek_subimage(int subimage, int miplevel)
264268
}
265269
m_spec.set_colorspace("srgb_rec709_scene");
266270

271+
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
272+
// Read CICP. Have to use the C API to get it from the image handle,
273+
// the one on the decoded image is not what was written in the file.
274+
enum heif_color_profile_type profile_type
275+
= heif_image_handle_get_color_profile_type(
276+
m_ihandle.get_raw_image_handle());
277+
if (profile_type == heif_color_profile_type_nclx) {
278+
heif_color_profile_nclx* nclx = nullptr;
279+
const heif_error err = heif_image_handle_get_nclx_color_profile(
280+
m_ihandle.get_raw_image_handle(), &nclx);
281+
282+
if (nclx) {
283+
if (err.code == heif_error_Ok) {
284+
const int cicp[4] = { int(nclx->color_primaries),
285+
int(nclx->transfer_characteristics),
286+
int(nclx->matrix_coefficients),
287+
int(nclx->full_range_flag ? 1 : 0) };
288+
m_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp);
289+
}
290+
heif_nclx_color_profile_free(nclx);
291+
}
292+
}
293+
#endif
294+
267295
#if LIBHEIF_HAVE_VERSION(1, 12, 0)
268296
// Libheif >= 1.12 added API call to find out if the image is associated
269297
// alpha (i.e. colors are premultiplied).

src/heif.imageio/heifoutput.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ class HeifOutput final : public ImageOutput {
2626
const char* format_name(void) const override { return "heif"; }
2727
int supports(string_view feature) const override
2828
{
29-
return feature == "alpha" || feature == "exif" || feature == "tiles";
29+
return feature == "alpha" || feature == "exif" || feature == "tiles"
30+
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
31+
|| feature == "cicp"
32+
#endif
33+
;
3034
}
3135
bool open(const std::string& name, const ImageSpec& spec,
3236
OpenMode mode) override;
@@ -238,8 +242,26 @@ HeifOutput::close()
238242
} else if (compqual.first == "none") {
239243
m_encoder.set_lossless(true);
240244
}
245+
heif::Context::EncodingOptions options;
246+
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
247+
// Write CICP. we can only set output_nclx_profile with the C API.
248+
std::unique_ptr<heif_color_profile_nclx,
249+
void (*)(heif_color_profile_nclx*)>
250+
nclx(heif_nclx_color_profile_alloc(), heif_nclx_color_profile_free);
251+
const ParamValue* p = m_spec.find_attribute("CICP",
252+
TypeDesc(TypeDesc::INT, 4));
253+
if (p) {
254+
const int* cicp = static_cast<const int*>(p->data());
255+
nclx->color_primaries = heif_color_primaries(cicp[0]);
256+
nclx->transfer_characteristics = heif_transfer_characteristics(
257+
cicp[1]);
258+
nclx->matrix_coefficients = heif_matrix_coefficients(cicp[2]);
259+
nclx->full_range_flag = cicp[3];
260+
options.output_nclx_profile = nclx.get();
261+
}
262+
#endif
241263
encode_exif(m_spec, exifblob, endian::big);
242-
m_ihandle = m_ctx->encode_image(m_himage, m_encoder);
264+
m_ihandle = m_ctx->encode_image(m_himage, m_encoder, options);
243265
std::vector<char> head { 'E', 'x', 'i', 'f', 0, 0 };
244266
exifblob.insert(exifblob.begin(), head.begin(), head.end());
245267
try {

testsuite/heif/ref/out-libheif1.12-orient.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,34 @@ ref/IMG_7702_small.heic : 512 x 300, 3 channel, uint8 heif
3939
Exif:SubsecTimeOriginal: "006"
4040
Exif:WhiteBalance: 0 (auto)
4141
oiio:ColorSpace: "srgb_rec709_scene"
42+
Reading ref/Chimera-AV1-8bit-162.avif
43+
ref/Chimera-AV1-8bit-162.avif : 480 x 270, 3 channel, uint8 heif
44+
SHA-1: F8FDAF1BD56A21E3AF99CF8EE7FA45434D2826C7
45+
channel list: R, G, B
46+
oiio:ColorSpace: "srgb_rec709_scene"
47+
Reading ref/test-10bit.avif
48+
ref/test-10bit.avif : 16 x 16, 4 channel, uint10 heif
49+
SHA-1: FFDB2271C871832C052DA19F0C0B18BB8AFC99EE
50+
channel list: R, G, B, A
51+
Software: "OpenImageIO 3.2.0.0dev : B4BD496D92983E84F1FD621682CAB821C1E2126C"
52+
Exif:ExifVersion: "0230"
53+
Exif:FlashPixVersion: "0100"
54+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
55+
heif:UnassociatedAlpha: 1
56+
oiio:BitsPerSample: 10
57+
oiio:ColorSpace: "srgb_rec709_scene"
58+
Reading cicp_pq.avif
59+
cicp_pq.avif : 16 x 16, 4 channel, uint10 heif
60+
SHA-1: 973A58CD6B420F205AA89967C18A60CD8ED8894B
61+
channel list: R, G, B, A
62+
CICP: 9, 16, 9, 1
63+
Software: "OpenImageIO 3.2.0.0dev : 959A97A4C33635B41A62F65A11C62361F43A36E5"
64+
Exif:ExifVersion: "0230"
65+
Exif:FlashPixVersion: "0100"
66+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
67+
heif:UnassociatedAlpha: 1
68+
oiio:BitsPerSample: 10
69+
oiio:ColorSpace: "srgb_rec709_scene"
4270
Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic
4371
../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif
4472
SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E

testsuite/heif/ref/out-libheif1.4.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ ref/Chimera-AV1-8bit-162.avif : 480 x 270, 3 channel, uint8 heif
4444
SHA-1: F8FDAF1BD56A21E3AF99CF8EE7FA45434D2826C7
4545
channel list: R, G, B
4646
oiio:ColorSpace: "srgb_rec709_scene"
47+
Reading ref/test-10bit.avif
48+
ref/test-10bit.avif : 16 x 16, 4 channel, uint10 heif
49+
SHA-1: FFDB2271C871832C052DA19F0C0B18BB8AFC99EE
50+
channel list: R, G, B, A
51+
Software: "OpenImageIO 3.2.0.0dev : B4BD496D92983E84F1FD621682CAB821C1E2126C"
52+
Exif:ExifVersion: "0230"
53+
Exif:FlashPixVersion: "0100"
54+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
55+
heif:UnassociatedAlpha: 1
56+
oiio:BitsPerSample: 10
57+
oiio:ColorSpace: "srgb_rec709_scene"
58+
Reading cicp_pq.avif
59+
cicp_pq.avif : 16 x 16, 4 channel, uint10 heif
60+
SHA-1: 973A58CD6B420F205AA89967C18A60CD8ED8894B
61+
channel list: R, G, B, A
62+
CICP: 9, 16, 9, 1
63+
Software: "OpenImageIO 3.2.0.0dev : 959A97A4C33635B41A62F65A11C62361F43A36E5"
64+
Exif:ExifVersion: "0230"
65+
Exif:FlashPixVersion: "0100"
66+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
67+
heif:UnassociatedAlpha: 1
68+
oiio:BitsPerSample: 10
69+
oiio:ColorSpace: "srgb_rec709_scene"
4770
Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic
4871
../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif
4972
SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E

testsuite/heif/ref/out-libheif1.5.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ ref/Chimera-AV1-8bit-162.avif : 480 x 270, 3 channel, uint8 heif
4444
SHA-1: F8FDAF1BD56A21E3AF99CF8EE7FA45434D2826C7
4545
channel list: R, G, B
4646
oiio:ColorSpace: "srgb_rec709_scene"
47+
Reading ref/test-10bit.avif
48+
ref/test-10bit.avif : 16 x 16, 4 channel, uint10 heif
49+
SHA-1: FFDB2271C871832C052DA19F0C0B18BB8AFC99EE
50+
channel list: R, G, B, A
51+
Software: "OpenImageIO 3.2.0.0dev : B4BD496D92983E84F1FD621682CAB821C1E2126C"
52+
Exif:ExifVersion: "0230"
53+
Exif:FlashPixVersion: "0100"
54+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
55+
heif:UnassociatedAlpha: 1
56+
oiio:BitsPerSample: 10
57+
oiio:ColorSpace: "srgb_rec709_scene"
58+
Reading cicp_pq.avif
59+
cicp_pq.avif : 16 x 16, 4 channel, uint10 heif
60+
SHA-1: 973A58CD6B420F205AA89967C18A60CD8ED8894B
61+
channel list: R, G, B, A
62+
CICP: 9, 16, 9, 1
63+
Software: "OpenImageIO 3.2.0.0dev : 959A97A4C33635B41A62F65A11C62361F43A36E5"
64+
Exif:ExifVersion: "0230"
65+
Exif:FlashPixVersion: "0100"
66+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
67+
heif:UnassociatedAlpha: 1
68+
oiio:BitsPerSample: 10
69+
oiio:ColorSpace: "srgb_rec709_scene"
4770
Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic
4871
../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif
4972
SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E

testsuite/heif/ref/out-libheif1.9-alt2.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,34 @@ ref/IMG_7702_small.heic : 512 x 300, 3 channel, uint8 heif
3939
Exif:SubsecTimeOriginal: "006"
4040
Exif:WhiteBalance: 0 (auto)
4141
oiio:ColorSpace: "srgb_rec709_scene"
42+
Reading ref/Chimera-AV1-8bit-162.avif
43+
ref/Chimera-AV1-8bit-162.avif : 480 x 270, 3 channel, uint8 heif
44+
SHA-1: F8FDAF1BD56A21E3AF99CF8EE7FA45434D2826C7
45+
channel list: R, G, B
46+
oiio:ColorSpace: "srgb_rec709_scene"
47+
Reading ref/test-10bit.avif
48+
ref/test-10bit.avif : 16 x 16, 4 channel, uint10 heif
49+
SHA-1: FFDB2271C871832C052DA19F0C0B18BB8AFC99EE
50+
channel list: R, G, B, A
51+
Software: "OpenImageIO 3.2.0.0dev : B4BD496D92983E84F1FD621682CAB821C1E2126C"
52+
Exif:ExifVersion: "0230"
53+
Exif:FlashPixVersion: "0100"
54+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
55+
heif:UnassociatedAlpha: 1
56+
oiio:BitsPerSample: 10
57+
oiio:ColorSpace: "srgb_rec709_scene"
58+
Reading cicp_pq.avif
59+
cicp_pq.avif : 16 x 16, 4 channel, uint10 heif
60+
SHA-1: 973A58CD6B420F205AA89967C18A60CD8ED8894B
61+
channel list: R, G, B, A
62+
CICP: 9, 16, 9, 1
63+
Software: "OpenImageIO 3.2.0.0dev : 959A97A4C33635B41A62F65A11C62361F43A36E5"
64+
Exif:ExifVersion: "0230"
65+
Exif:FlashPixVersion: "0100"
66+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
67+
heif:UnassociatedAlpha: 1
68+
oiio:BitsPerSample: 10
69+
oiio:ColorSpace: "srgb_rec709_scene"
4270
Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic
4371
../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif
4472
SHA-1: 8064B23A1A995B0D6525AFB5248EEC6C730BBB6C

testsuite/heif/ref/out-libheif1.9-with-av1-alt2.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ ref/Chimera-AV1-8bit-162.avif : 480 x 270, 3 channel, uint8 heif
4444
SHA-1: F8FDAF1BD56A21E3AF99CF8EE7FA45434D2826C7
4545
channel list: R, G, B
4646
oiio:ColorSpace: "srgb_rec709_scene"
47+
Reading ref/test-10bit.avif
48+
ref/test-10bit.avif : 16 x 16, 4 channel, uint10 heif
49+
SHA-1: FFDB2271C871832C052DA19F0C0B18BB8AFC99EE
50+
channel list: R, G, B, A
51+
Software: "OpenImageIO 3.2.0.0dev : B4BD496D92983E84F1FD621682CAB821C1E2126C"
52+
Exif:ExifVersion: "0230"
53+
Exif:FlashPixVersion: "0100"
54+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
55+
heif:UnassociatedAlpha: 1
56+
oiio:BitsPerSample: 10
57+
oiio:ColorSpace: "srgb_rec709_scene"
58+
Reading cicp_pq.avif
59+
cicp_pq.avif : 16 x 16, 4 channel, uint10 heif
60+
SHA-1: 973A58CD6B420F205AA89967C18A60CD8ED8894B
61+
channel list: R, G, B, A
62+
CICP: 9, 16, 9, 1
63+
Software: "OpenImageIO 3.2.0.0dev : 959A97A4C33635B41A62F65A11C62361F43A36E5"
64+
Exif:ExifVersion: "0230"
65+
Exif:FlashPixVersion: "0100"
66+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
67+
heif:UnassociatedAlpha: 1
68+
oiio:BitsPerSample: 10
69+
oiio:ColorSpace: "srgb_rec709_scene"
4770
Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic
4871
../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif
4972
SHA-1: 8064B23A1A995B0D6525AFB5248EEC6C730BBB6C

testsuite/heif/ref/out-libheif1.9-with-av1.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ ref/Chimera-AV1-8bit-162.avif : 480 x 270, 3 channel, uint8 heif
4444
SHA-1: F8FDAF1BD56A21E3AF99CF8EE7FA45434D2826C7
4545
channel list: R, G, B
4646
oiio:ColorSpace: "srgb_rec709_scene"
47+
Reading ref/test-10bit.avif
48+
ref/test-10bit.avif : 16 x 16, 4 channel, uint10 heif
49+
SHA-1: FFDB2271C871832C052DA19F0C0B18BB8AFC99EE
50+
channel list: R, G, B, A
51+
Software: "OpenImageIO 3.2.0.0dev : B4BD496D92983E84F1FD621682CAB821C1E2126C"
52+
Exif:ExifVersion: "0230"
53+
Exif:FlashPixVersion: "0100"
54+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
55+
heif:UnassociatedAlpha: 1
56+
oiio:BitsPerSample: 10
57+
oiio:ColorSpace: "srgb_rec709_scene"
58+
Reading cicp_pq.avif
59+
cicp_pq.avif : 16 x 16, 4 channel, uint10 heif
60+
SHA-1: 973A58CD6B420F205AA89967C18A60CD8ED8894B
61+
channel list: R, G, B, A
62+
CICP: 9, 16, 9, 1
63+
Software: "OpenImageIO 3.2.0.0dev : 959A97A4C33635B41A62F65A11C62361F43A36E5"
64+
Exif:ExifVersion: "0230"
65+
Exif:FlashPixVersion: "0100"
66+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
67+
heif:UnassociatedAlpha: 1
68+
oiio:BitsPerSample: 10
69+
oiio:ColorSpace: "srgb_rec709_scene"
4770
Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic
4871
../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif
4972
SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E

testsuite/heif/ref/out-libheif1.9.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,34 @@ ref/IMG_7702_small.heic : 512 x 300, 3 channel, uint8 heif
3939
Exif:SubsecTimeOriginal: "006"
4040
Exif:WhiteBalance: 0 (auto)
4141
oiio:ColorSpace: "srgb_rec709_scene"
42+
Reading ref/Chimera-AV1-8bit-162.avif
43+
ref/Chimera-AV1-8bit-162.avif : 480 x 270, 3 channel, uint8 heif
44+
SHA-1: F8FDAF1BD56A21E3AF99CF8EE7FA45434D2826C7
45+
channel list: R, G, B
46+
oiio:ColorSpace: "srgb_rec709_scene"
47+
Reading ref/test-10bit.avif
48+
ref/test-10bit.avif : 16 x 16, 4 channel, uint10 heif
49+
SHA-1: FFDB2271C871832C052DA19F0C0B18BB8AFC99EE
50+
channel list: R, G, B, A
51+
Software: "OpenImageIO 3.2.0.0dev : B4BD496D92983E84F1FD621682CAB821C1E2126C"
52+
Exif:ExifVersion: "0230"
53+
Exif:FlashPixVersion: "0100"
54+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
55+
heif:UnassociatedAlpha: 1
56+
oiio:BitsPerSample: 10
57+
oiio:ColorSpace: "srgb_rec709_scene"
58+
Reading cicp_pq.avif
59+
cicp_pq.avif : 16 x 16, 4 channel, uint10 heif
60+
SHA-1: 973A58CD6B420F205AA89967C18A60CD8ED8894B
61+
channel list: R, G, B, A
62+
CICP: 9, 16, 9, 1
63+
Software: "OpenImageIO 3.2.0.0dev : 959A97A4C33635B41A62F65A11C62361F43A36E5"
64+
Exif:ExifVersion: "0230"
65+
Exif:FlashPixVersion: "0100"
66+
Exif:ImageHistory: "oiiotool --pattern fill:topleft=1,0,0,1:topright=0,1,0,1:bottomleft=0,0,1,1:bottomright=1,1,1,1 16x16 4 -d uint16 -o test16.png"
67+
heif:UnassociatedAlpha: 1
68+
oiio:BitsPerSample: 10
69+
oiio:ColorSpace: "srgb_rec709_scene"
4270
Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic
4371
../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif
4472
SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E

0 commit comments

Comments
 (0)