Skip to content

Commit a93a487

Browse files
committed
feat(heif): Read and write CICP
By setting the matrix coefficients, the library will perform RGB to YUV conversion on write. The YUV to RBG conversion was already happening on read automatically. Signed-off-by: Brecht Van Lommel <[email protected]>
1 parent 414d80b commit a93a487

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;
@@ -234,8 +238,26 @@ HeifOutput::close()
234238
} else if (compqual.first == "none") {
235239
m_encoder.set_lossless(true);
236240
}
241+
heif::Context::EncodingOptions options;
242+
#if LIBHEIF_HAVE_VERSION(1, 9, 0)
243+
// Write CICP. we can only set output_nclx_profile with the C API.
244+
std::unique_ptr<heif_color_profile_nclx,
245+
void (*)(heif_color_profile_nclx*)>
246+
nclx(heif_nclx_color_profile_alloc(), heif_nclx_color_profile_free);
247+
const ParamValue* p = m_spec.find_attribute("CICP",
248+
TypeDesc(TypeDesc::INT, 4));
249+
if (p) {
250+
const int* cicp = static_cast<const int*>(p->data());
251+
nclx->color_primaries = heif_color_primaries(cicp[0]);
252+
nclx->transfer_characteristics = heif_transfer_characteristics(
253+
cicp[1]);
254+
nclx->matrix_coefficients = heif_matrix_coefficients(cicp[2]);
255+
nclx->full_range_flag = cicp[3];
256+
options.output_nclx_profile = nclx.get();
257+
}
258+
#endif
237259
encode_exif(m_spec, exifblob, endian::big);
238-
m_ihandle = m_ctx->encode_image(m_himage, m_encoder);
260+
m_ihandle = m_ctx->encode_image(m_himage, m_encoder, options);
239261
std::vector<char> head { 'E', 'x', 'i', 'f', 0, 0 };
240262
exifblob.insert(exifblob.begin(), head.begin(), head.end());
241263
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 : A50DC799B2B4CA667217608C0F82302455E5D32A"
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 : A50DC799B2B4CA667217608C0F82302455E5D32A"
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 : A50DC799B2B4CA667217608C0F82302455E5D32A"
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 : A50DC799B2B4CA667217608C0F82302455E5D32A"
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 : A50DC799B2B4CA667217608C0F82302455E5D32A"
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 : A50DC799B2B4CA667217608C0F82302455E5D32A"
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 : A50DC799B2B4CA667217608C0F82302455E5D32A"
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)