Commit 0840e332 for libheif

commit 0840e3323e71952ff39d49e66af50055ac70e308
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Sun May 17 19:07:10 2026 +0200

    move omaf functions into its own header file and provide heif_image variant

diff --git a/libheif/CMakeLists.txt b/libheif/CMakeLists.txt
index b6182c6f..27660b22 100644
--- a/libheif/CMakeLists.txt
+++ b/libheif/CMakeLists.txt
@@ -27,6 +27,7 @@ set(libheif_headers
         api/libheif/heif_uncompressed.h
         api/libheif/heif_uncompressed_types.h
         api/libheif/heif_text.h
+        api/libheif/heif_omaf.h
         api/libheif/heif_cxx.h
         ${CMAKE_CURRENT_BINARY_DIR}/heif_version.h)

@@ -94,6 +95,7 @@ set(libheif_sources
         api/libheif/heif_tiling.cc
         api/libheif/heif_uncompressed.cc
         api/libheif/heif_text.cc
+        api/libheif/heif_omaf.cc
         codecs/decoder.h
         codecs/decoder.cc
         codecs/encoder.h
diff --git a/libheif/api/libheif/heif.h b/libheif/api/libheif/heif.h
index dfbe5ba4..085e453f 100644
--- a/libheif/api/libheif/heif.h
+++ b/libheif/api/libheif/heif.h
@@ -37,5 +37,6 @@
 #include <libheif/heif_context.h>
 #include <libheif/heif_image_handle.h>
 #include <libheif/heif_tiling.h>
+#include <libheif/heif_omaf.h>

 #endif
diff --git a/libheif/api/libheif/heif_context.h b/libheif/api/libheif/heif_context.h
index 0965f539..6a268c7f 100644
--- a/libheif/api/libheif/heif_context.h
+++ b/libheif/api/libheif/heif_context.h
@@ -298,7 +298,6 @@ void heif_context_debug_dump_boxes_to_file(heif_context* ctx, int fd);
 // ====================================================================================================
 //   Mini format (experimental)

-//NEWAPI
 // Enable writing in the compact 'mini' box format (ISO/IEC 23008-12 DAmd2).
 // When enabled, the output file will use a single 'mini' box instead of the standard
 // meta+mdat box structure, if the file content is compatible with the mini format.
diff --git a/libheif/api/libheif/heif_decoding.h b/libheif/api/libheif/heif_decoding.h
index 6f73f642..3f1e8902 100644
--- a/libheif/api/libheif/heif_decoding.h
+++ b/libheif/api/libheif/heif_decoding.h
@@ -39,7 +39,6 @@ extern "C" {
 LIBHEIF_API
 void heif_context_set_max_decoding_threads(heif_context* ctx, int max_threads);

-//NEWAPI
 // Returns the current maximum number of background threads used for parallel tile decoding.
 // This reflects either the library default or the value last passed to
 // heif_context_set_max_decoding_threads().
diff --git a/libheif/api/libheif/heif_image.cc b/libheif/api/libheif/heif_image.cc
index 2dd2d9bf..144b07c9 100644
--- a/libheif/api/libheif/heif_image.cc
+++ b/libheif/api/libheif/heif_image.cc
@@ -315,16 +315,6 @@ void heif_image_handle_set_pixel_aspect_ratio(heif_image_handle* handle, uint32_
   handle->image->set_pixel_ratio(aspect_h, aspect_v);
 }

-heif_omaf_image_projection heif_image_get_omaf_image_projection(const heif_image* image)
-{
-  return image->image->get_omaf_image_projection();
-}
-
-void heif_image_set_omaf_image_projection(const heif_image* image, heif_omaf_image_projection image_projection)
-{
-  image->image->set_omaf_image_projection(image_projection);
-}
-
 heif_error heif_image_create(int width, int height,
                              heif_colorspace colorspace,
                              heif_chroma chroma,
diff --git a/libheif/api/libheif/heif_image.h b/libheif/api/libheif/heif_image.h
index 7fc8f1ae..f5c654b9 100644
--- a/libheif/api/libheif/heif_image.h
+++ b/libheif/api/libheif/heif_image.h
@@ -130,45 +130,6 @@ typedef enum heif_channel
   heif_channel_unknown = 65535
 } heif_channel;

-//NEWAPI
-/**
- * OMAF Image projection.
- *
- * The image projection for most images is flat - it is projected as intended to be shown on
- * a flat screen or print. For immersive or omnidirectional media (e.g. VR headsets, or
- * equivalent), there are alternatives such as an equirectangular projection or cubemap projection.
- *
- * See ISO/IEC 23090-2 "Omnidirectional media format" for more information.
- */
-typedef enum heif_omaf_image_projection
-{
-  /**
-   * Equirectangular projection.
-   */
-  heif_omaf_image_projection_equirectangular = 0x00,
-
-  /**
-   * Cube map.
-   */
-  heif_omaf_image_projection_cube_map = 0x01,
-
-  /*
-   * Values 2 through 31 are reserved in ISO/IEC 23090-2:2023 Table 10.
-   * Files may carry any of them; libheif passes the raw projection_type
-   * value through unchanged, so callers can log or round-trip it.
-   * Handle anything outside the named constants in a `default:` arm.
-   */
-
-  /**
-   * Flat projection. Also returned by the get-projection accessors when no
-   * projection information is present on the image, so callers can use
-   * `result == heif_omaf_image_projection_flat` to test for "no prfr box".
-   * 0xFF lies outside the prfr value range reserved by ISO 23090-2:2023
-   * Table 10, so it cannot collide with a value read from a file.
-   */
-  heif_omaf_image_projection_flat = 0xFF,
-} heif_omaf_image_projection;
-
 // An heif_image contains a decoded pixel image in various colorspaces, chroma formats,
 // and bit depths.

@@ -366,14 +327,6 @@ void heif_image_set_pixel_aspect_ratio(heif_image*, uint32_t aspect_h, uint32_t
 LIBHEIF_API
 void heif_image_handle_set_pixel_aspect_ratio(heif_image_handle*, uint32_t aspect_h, uint32_t aspect_v);

-//NEWAPI
-LIBHEIF_API
-heif_omaf_image_projection heif_image_get_omaf_image_projection(const heif_image*);
-
-//NEWAPI
-LIBHEIF_API
-void heif_image_set_omaf_image_projection(const heif_image*, heif_omaf_image_projection image_projection);
-
 // --- heif_image allocation

 /**
diff --git a/libheif/api/libheif/heif_omaf.cc b/libheif/api/libheif/heif_omaf.cc
new file mode 100644
index 00000000..c300dc10
--- /dev/null
+++ b/libheif/api/libheif/heif_omaf.cc
@@ -0,0 +1,47 @@
+/*
+ * HEIF codec.
+ * Copyright (c) 2026 Brad Hards <bradh@frogmouth.net>
+ * Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com>
+ *
+ * This file is part of libheif.
+ *
+ * libheif is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * libheif is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libheif/heif_omaf.h"
+#include "api_structs.h"
+
+
+heif_omaf_image_projection heif_image_handle_get_omaf_image_projection(const heif_image_handle* handle)
+{
+  return handle->image->get_omaf_image_projection();
+}
+
+void heif_image_handle_set_omaf_image_projection(heif_image_handle* handle,
+                                                 heif_omaf_image_projection image_projection)
+{
+  handle->image->set_omaf_image_projection(image_projection);
+}
+
+
+heif_omaf_image_projection heif_image_get_omaf_image_projection(const heif_image* image)
+{
+  return image->image->get_omaf_image_projection();
+}
+
+void heif_image_set_omaf_image_projection(heif_image* image,
+                                          heif_omaf_image_projection image_projection)
+{
+  image->image->set_omaf_image_projection(image_projection);
+}
diff --git a/libheif/api/libheif/heif_omaf.h b/libheif/api/libheif/heif_omaf.h
new file mode 100644
index 00000000..23e5ea74
--- /dev/null
+++ b/libheif/api/libheif/heif_omaf.h
@@ -0,0 +1,104 @@
+/*
+ * HEIF codec.
+ * Copyright (c) 2026 Brad Hards <bradh@frogmouth.net>
+ * Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com>
+ *
+ * This file is part of libheif.
+ *
+ * libheif is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * libheif is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBHEIF_HEIF_OMAF_H
+#define LIBHEIF_HEIF_OMAF_H
+
+#include <libheif/heif_library.h>
+#include <libheif/heif_error.h>
+#include <libheif/heif_image.h>
+#include <libheif/heif_image_handle.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ------------------------- OMAF projection information -------------------------
+//
+// ISO/IEC 23090-2 "Omnidirectional media format" describes formats for
+// representing immersive / 360-degree imagery. The 'prfr' (projection format)
+// item property records the kind of projection used by the encoded image.
+
+/**
+ * OMAF Image projection.
+ *
+ * The image projection for most images is flat - it is projected as intended to be shown on
+ * a flat screen or print. For immersive or omnidirectional media (e.g. VR headsets, or
+ * equivalent), there are alternatives such as an equirectangular projection or cubemap projection.
+ *
+ * See ISO/IEC 23090-2 "Omnidirectional media format" for more information.
+ */
+typedef enum heif_omaf_image_projection
+{
+  /**
+   * Equirectangular projection.
+   */
+  heif_omaf_image_projection_equirectangular = 0x00,
+
+  /**
+   * Cube map.
+   */
+  heif_omaf_image_projection_cube_map = 0x01,
+
+  /*
+   * Values 2 through 31 are reserved in ISO/IEC 23090-2:2023 Table 10.
+   * Files may carry any of them; libheif passes the raw projection_type
+   * value through unchanged, so callers can log or round-trip it.
+   * Handle anything outside the named constants in a `default:` arm.
+   */
+
+  /**
+   * Flat projection. Also returned by the get-projection accessors when no
+   * projection information is present on the image, so callers can use
+   * `result == heif_omaf_image_projection_flat` to test for "no prfr box".
+   * 0xFF lies outside the prfr value range reserved by ISO 23090-2:2023
+   * Table 10, so it cannot collide with a value read from a file.
+   */
+  heif_omaf_image_projection_flat = 0xFF,
+} heif_omaf_image_projection;
+
+
+// To test whether projection information is present, compare the getter's
+// result against heif_omaf_image_projection_flat.
+
+LIBHEIF_API
+heif_omaf_image_projection heif_image_handle_get_omaf_image_projection(const heif_image_handle* handle);
+
+LIBHEIF_API
+void heif_image_handle_set_omaf_image_projection(heif_image_handle* handle,
+                                                 heif_omaf_image_projection image_projection);
+
+// Variants operating on a heif_image (a decoded or about-to-be-encoded pixel
+// image). Setting the projection on a heif_image before encoding causes the
+// resulting image item to carry the corresponding prfr property.
+
+LIBHEIF_API
+heif_omaf_image_projection heif_image_get_omaf_image_projection(const heif_image* image);
+
+LIBHEIF_API
+void heif_image_set_omaf_image_projection(heif_image* image,
+                                          heif_omaf_image_projection image_projection);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libheif/api/libheif/heif_plugin.h b/libheif/api/libheif/heif_plugin.h
index b90cbeb7..77123039 100644
--- a/libheif/api/libheif/heif_plugin.h
+++ b/libheif/api/libheif/heif_plugin.h
@@ -73,7 +73,6 @@ typedef struct heif_decoder_plugin_options
   int strict_decoding; // bool
   int num_threads; // 0 - undefined, use decoder default

-  //NEWAPI
   // --- added in plugin_api_version 6 ---
   // Security limits the plugin must enforce for image allocations during decoding.
   // The pointee must outlive the decoder instance (typically the context's limits).
diff --git a/libheif/api/libheif/heif_properties.cc b/libheif/api/libheif/heif_properties.cc
index 656086b6..bc18e416 100644
--- a/libheif/api/libheif/heif_properties.cc
+++ b/libheif/api/libheif/heif_properties.cc
@@ -458,16 +458,3 @@ heif_error heif_camera_extrinsic_matrix_get_rotation_matrix(const heif_camera_ex
   return heif_error_success;
 }

-heif_omaf_image_projection heif_image_handle_get_omaf_image_projection(const heif_image_handle* handle)
-{
-  return handle->image->get_omaf_image_projection();
-}
-
-heif_error heif_image_handle_set_omaf_image_projection(const heif_image_handle* handle, heif_omaf_image_projection image_projection)
-{
-  if (!handle) {
-    return heif_error_null_pointer_argument;
-  }
-  handle->image->set_omaf_image_projection(image_projection);
-  return heif_error_success;
-}
diff --git a/libheif/api/libheif/heif_properties.h b/libheif/api/libheif/heif_properties.h
index d04c74a9..ceda2aa2 100644
--- a/libheif/api/libheif/heif_properties.h
+++ b/libheif/api/libheif/heif_properties.h
@@ -228,17 +228,6 @@ LIBHEIF_API
 heif_error heif_camera_extrinsic_matrix_get_rotation_matrix(const heif_camera_extrinsic_matrix*,
                                                             double* out_matrix_row_major);

-// ------------------------- OMAF projection information -------------------------
-// To test whether projection information is present, compare the getter's result
-// against heif_omaf_image_projection_flat.
-//NEWAPI
-LIBHEIF_API
-heif_omaf_image_projection heif_image_handle_get_omaf_image_projection(const heif_image_handle* handle);
-
-//NEWAPI
-LIBHEIF_API
-heif_error heif_image_handle_set_omaf_image_projection(const heif_image_handle* handle, heif_omaf_image_projection image_projection);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/tests/omaf.cc b/tests/omaf.cc
index 72991c23..36acd8a2 100644
--- a/tests/omaf.cc
+++ b/tests/omaf.cc
@@ -73,9 +73,71 @@ static void do_encode(heif_image* input_image, const char* filename, heif_omaf_i
   heif_image_handle *readbackHandle = get_primary_image_handle(readbackCtx);
   heif_omaf_image_projection readbackProjection = heif_image_handle_get_omaf_image_projection(readbackHandle);
   REQUIRE(readbackProjection == projection);
+
+  // The projection should also be reachable on the decoded heif_image, as it
+  // is copied from the image item into the pixel image during decoding.
+  heif_image* decoded = get_primary_image(readbackHandle);
+  REQUIRE(heif_image_get_omaf_image_projection(decoded) == projection);
+  heif_image_release(decoded);
+
   heif_image_handle_release(readbackHandle);
   heif_context_free(readbackCtx);
-
+
+  heif_deinit();
+}
+
+// Variant that sets the projection on the input heif_image rather than on the
+// encoded heif_image_handle. The projection should still be persisted to the
+// file's prfr property and round-trip via the handle and the decoded image.
+static void do_encode_via_image(heif_image* input_image, const char* filename, heif_omaf_image_projection projection)
+{
+  REQUIRE(input_image != nullptr);
+  heif_init(nullptr);
+
+  // A fresh heif_image starts with no projection information.
+  REQUIRE(heif_image_get_omaf_image_projection(input_image) == heif_omaf_image_projection_flat);
+
+  heif_image_set_omaf_image_projection(input_image, projection);
+  REQUIRE(heif_image_get_omaf_image_projection(input_image) == projection);
+
+  heif_context *ctx = heif_context_alloc();
+  heif_encoder *encoder;
+  heif_error err;
+  err = heif_context_get_encoder_for_format(ctx, heif_compression_HEVC, &encoder);
+  REQUIRE(err.code == heif_error_Ok);
+
+  heif_encoding_options *options = set_encoding_options();
+
+  heif_image_handle *output_image_handle;
+
+  err = heif_context_encode_image(ctx, input_image, encoder, options, &output_image_handle);
+  REQUIRE(err.code == heif_error_Ok);
+
+  // The projection set on the input image should have flowed into the
+  // encoded image item without any explicit handle-side call.
+  REQUIRE(heif_image_handle_get_omaf_image_projection(output_image_handle) == projection);
+
+  err = heif_context_write_to_file(ctx, filename);
+  REQUIRE(err.code == heif_error_Ok);
+
+  heif_image_handle_release(output_image_handle);
+  heif_encoding_options_free(options);
+  heif_encoder_release(encoder);
+  heif_image_release(input_image);
+
+  heif_context_free(ctx);
+
+  heif_context *readbackCtx = get_context_for_local_file(filename);
+  heif_image_handle *readbackHandle = get_primary_image_handle(readbackCtx);
+  REQUIRE(heif_image_handle_get_omaf_image_projection(readbackHandle) == projection);
+
+  heif_image* decoded = get_primary_image(readbackHandle);
+  REQUIRE(heif_image_get_omaf_image_projection(decoded) == projection);
+  heif_image_release(decoded);
+
+  heif_image_handle_release(readbackHandle);
+  heif_context_free(readbackCtx);
+
   heif_deinit();
 }

@@ -89,4 +151,16 @@ TEST_CASE("Encode OMAF HEIC Cubemap")
 {
   heif_image *input_image = createImage_RGB_planar();
   do_encode(input_image, "encode_omaf_cubemap.heic", heif_omaf_image_projection::heif_omaf_image_projection_cube_map);
+}
+
+TEST_CASE("Encode OMAF HEIC via heif_image")
+{
+  heif_image *input_image = createImage_RGB_planar();
+  do_encode_via_image(input_image, "encode_omaf_equirectangular_via_image.heic", heif_omaf_image_projection::heif_omaf_image_projection_equirectangular);
+}
+
+TEST_CASE("Encode OMAF HEIC Cubemap via heif_image")
+{
+  heif_image *input_image = createImage_RGB_planar();
+  do_encode_via_image(input_image, "encode_omaf_cubemap_via_image.heic", heif_omaf_image_projection::heif_omaf_image_projection_cube_map);
 }
\ No newline at end of file