Commit d43b642e for libheif

commit d43b642e30f612be52e6b0382281edf94f3f6517
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Fri May 15 01:21:09 2026 +0200

    Reject subsampled chroma in HeifPixelImage::overlay()

diff --git a/libheif/image/pixelimage.cc b/libheif/image/pixelimage.cc
index f617ffce..7ec8ccdc 100644
--- a/libheif/image/pixelimage.cc
+++ b/libheif/image/pixelimage.cc
@@ -1617,7 +1617,23 @@ uint32_t negate_negative_int32(int32_t x)

 Error HeifPixelImage::overlay(std::shared_ptr<HeifPixelImage>& overlay, int32_t dx, int32_t dy)
 {
-  std::set<enum heif_channel> channels = overlay->get_channel_set();
+  // This function places the overlay using the full-resolution (dx,dy) offset
+  // directly as a per-plane offset. That is only correct when every plane has
+  // the full logical image size, i.e. for non-subsampled chroma formats.
+  // Subsampled chroma (4:2:0 / 4:2:2) would be mis-placed and could even write
+  // outside of the smaller Cb/Cr planes.
+  auto has_subsampled_chroma = [](heif_chroma chroma) {
+    return chroma == heif_chroma_420 || chroma == heif_chroma_422;
+  };
+
+  if (has_subsampled_chroma(get_chroma_format()) ||
+      has_subsampled_chroma(overlay->get_chroma_format())) {
+    return {heif_error_Unsupported_feature,
+            heif_suberror_Unspecified,
+            "Overlaying images with subsampled chroma is not supported"};
+  }
+
+  std::set<heif_channel> channels = overlay->get_channel_set();

   bool has_alpha = overlay->has_channel(heif_channel_Alpha);
   //bool has_alpha_me = has_channel(heif_channel_Alpha);
@@ -1648,6 +1664,9 @@ Error HeifPixelImage::overlay(std::shared_ptr<HeifPixelImage>& overlay, int32_t


     // --- check whether overlay image overlaps with current image
+    // Note: all components share the logical image size, so if the overlay
+    // image lies completely outside for one component it does so for all of
+    // them -> we can return instead of just skipping the current component.

     if (dx > 0 && static_cast<uint32_t>(dx) >= out_w) {
       // the overlay image is completely outside the right border -> skip overlaying