From a9f6171e44e3dcf7bdcb91686d9a61f4c7c96e18 Mon Sep 17 00:00:00 2001 From: Fabrice Aneche Date: Fri, 18 Sep 2026 12:45:27 -0400 Subject: [PATCH 1/2] fix: prevent clip_preprocess center crop from exceeding the resized image clip_preprocess truncated the aspect-preserving resize dimensions to int64_t, so a float result a hair below an integer (e.g. 736.0f/730.0f * 730.0f = 735.999...) left the resized side one pixel shorter than the crop target. The center crop then indexed past the end of the resized tensor and threw "Tensor index out of range" (SIGABRT). Round the resized dimensions up with std::ceil and clamp them to at least the crop target so the crop window is always covered. --- src/core/util.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index 2a233e695..710ea45f6 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -752,8 +752,14 @@ sd::Tensor clip_preprocess(const sd::Tensor& image, int target_wid float height_scale = static_cast(target_height) / static_cast(image.shape()[1]); float scale = std::fmax(width_scale, height_scale); - int64_t resized_width = static_cast(scale * static_cast(image.shape()[0])); - int64_t resized_height = static_cast(scale * static_cast(image.shape()[1])); + int64_t resized_width = static_cast(std::ceil(scale * static_cast(image.shape()[0]))); + int64_t resized_height = static_cast(std::ceil(scale * static_cast(image.shape()[1]))); + + // The resized image must cover the crop window. Rounding the scale could + // otherwise leave a side one pixel short (e.g. 730 -> 736.0 -> 735 after + // truncation) and the center crop would index past the tensor. + resized_width = std::max(resized_width, target_width); + resized_height = std::max(resized_height, target_height); sd::Tensor resized = sd::ops::interpolate( image, From 40a54ae6a2b77c87621cb02bb7b9db9bed878498 Mon Sep 17 00:00:00 2001 From: Fabrice Aneche Date: Fri, 18 Sep 2026 17:47:38 -0400 Subject: [PATCH 2/2] fix: keep truncation and only clamp clip_preprocess resize Rounding the resized dimensions up changed the CLIP preprocessing result for inputs that were already fine. Keep the original truncation and rely solely on clamping to the crop target to keep the center crop in bounds. --- src/core/util.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index 710ea45f6..1653f241b 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -752,12 +752,13 @@ sd::Tensor clip_preprocess(const sd::Tensor& image, int target_wid float height_scale = static_cast(target_height) / static_cast(image.shape()[1]); float scale = std::fmax(width_scale, height_scale); - int64_t resized_width = static_cast(std::ceil(scale * static_cast(image.shape()[0]))); - int64_t resized_height = static_cast(std::ceil(scale * static_cast(image.shape()[1]))); + int64_t resized_width = static_cast(scale * static_cast(image.shape()[0])); + int64_t resized_height = static_cast(scale * static_cast(image.shape()[1])); - // The resized image must cover the crop window. Rounding the scale could - // otherwise leave a side one pixel short (e.g. 730 -> 736.0 -> 735 after - // truncation) and the center crop would index past the tensor. + // The resized image must cover the crop window. Floating-point rounding can + // leave a side one pixel short of the crop target (e.g. 730 -> 735.999... + // -> 735 after truncation), so clamp to keep the center crop in bounds. + // Truncation is otherwise preserved to avoid changing existing results. resized_width = std::max(resized_width, target_width); resized_height = std::max(resized_height, target_height);