From 31181b5bedef5b6123d7575880cfb5d589440791 Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Thu, 9 Jul 2026 17:41:43 +0200 Subject: [PATCH] [Win32] Improve size calculation for cropped and scaled image drawing When drawing cropped and scaled images, the calculation for the source rectangle to draw is quite error prone: - It does not distinguish between different scale factor in X and Y direction, leading to large rounding errors if the extent in one directions is highly different from the extent in the other direction - It does not apply rounding that is consistent to the scaling done by the Image class, thus leading to differently rounded sizes when scaling an image in the Image class and drawing that same image in the GC - The "error correction" to deal with rounding at fractional scale factors is too restrictive, in particular when the scale factor is less than 1 This change reimplements the source rectangle calculation as follows: - It treats the scale factors for both axes independently - It applies the same rounding method to the rectangle extents than done by Image scaling implementation - It rounds up the scale factor when checking for the allowed size error on fractional scaling, such that a scale factor less than 1 still allows for an error of 1 in size. --- .../win32/org/eclipse/swt/graphics/GC.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index e6b99131a7..6f19756651 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -1250,20 +1250,24 @@ private Rectangle computeSourceRectangle(ImageHandle imageHandle, Rectangle full * computed to pixels depending on the factor of the full image bounds to the * actual OS handle size that will be used. */ - float scaleFactor = Math.min(1f * imageHandle.width() / fullImageBounds.width, 1f * imageHandle.height() / fullImageBounds.height); - int closestZoomOfHandle = Math.round(scaleFactor * 100); - Rectangle srcPixels = Win32DPIUtils.pointToPixel(drawable, src, closestZoomOfHandle); - - if (closestZoomOfHandle != 100) { + float scaleFactorX = 1f * imageHandle.width() / fullImageBounds.width; + float scaleFactorY = 1f * imageHandle.height() / fullImageBounds.height; + int srcXPixels = Math.round(scaleFactorX * src.x); + int srcWidthPixels = Math.round(scaleFactorX * (src.x + src.width)) - srcXPixels; + int srcYPixels = Math.round(scaleFactorY * src.y); + int srcHeightPixels = Math.round(scaleFactorY * (src.y + src.height)) - srcYPixels; + Rectangle srcPixels = new Rectangle(srcXPixels, srcYPixels, srcWidthPixels, srcHeightPixels); + + if (Float.compare(scaleFactorX, 100) >= 0.01 && Float.compare(scaleFactorY, 100) >= 0.01) { /* * This is a HACK! Due to rounding errors at fractional scale factors, * the coordinates may be slightly off. The workaround is to restrict * coordinates to the allowed bounds. */ int errX = srcPixels.x + srcPixels.width - imageHandle.width(); - int errY = srcPixels.y + srcPixels.height - imageHandle.height(); + int errY = srcPixels.y + srcPixels.height- imageHandle.height(); if (errX != 0 || errY != 0) { - if (errX <= closestZoomOfHandle / 100 && errY <= closestZoomOfHandle / 100) { + if (errX <= Math.ceil(scaleFactorX) && errY <= Math.ceil(scaleFactorY)) { srcPixels.intersect(new Rectangle(0, 0, imageHandle.width(), imageHandle.height())); } else { SWT.error (SWT.ERROR_INVALID_ARGUMENT);