From 215cbfd4e3439446f405dae74bc635aee0582c1f Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Tue, 22 Apr 2025 16:41:03 +0200 Subject: [PATCH] Move ImageData scaling logic to Image #62 This commit contributes to moving the logic for scaling the ImageData using GC from DPIUtil to Image for each platform and DPIUtil calls the platform specific code from the method DPIUtil:autoScaleImageData. contributes to https://github.com/eclipse-platform/eclipse.platform.swt/issues/62 and https://github.com/eclipse-platform/eclipse.platform.swt/issues/127 --- .../cocoa/org/eclipse/swt/graphics/Image.java | 23 ++++++++ .../org/eclipse/swt/internal/DPIUtil.java | 6 +- .../gtk/org/eclipse/swt/graphics/Image.java | 23 ++++++++ .../win32/org/eclipse/swt/graphics/Image.java | 58 +++++++------------ 4 files changed, 69 insertions(+), 41 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java index 4ecc29fbcb6..7d0ff95942d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java @@ -1801,5 +1801,28 @@ public String toString () { return "Image {" + handle + "}"; } +/** + * IMPORTANT: This method is not part of the public + * API for Image. It is marked public only so that it + * can be shared within the packages provided by SWT. + * + * Draws a scaled image using the GC by another image. + * + * @param gc the GC to draw on the resulting image + * @param original the image which is supposed to be scaled and drawn on the resulting image + * @param width the width of the original image + * @param height the height of the original image + * @param scaleFactor the factor with which the image is supposed to be scaled + * + * @noreference This method is not intended to be referenced by clients. + */ +public static void drawScaled(GC gc, Image original, int width, int height, float scaleFactor) { + gc.drawImage (original, 0, 0, DPIUtil.autoScaleDown (width), DPIUtil.autoScaleDown (height), + /* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors. + * Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..). + */ + 0, 0, Math.round (DPIUtil.autoScaleDown (width * scaleFactor)), Math.round (DPIUtil.autoScaleDown (height * scaleFactor))); +} + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java index 3390c28e1c9..10a60eb0048 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java @@ -312,11 +312,7 @@ private static ImageData autoScaleImageData (Device device, final ImageData imag Image resultImage = new Image (device, (ImageDataProvider) zoom -> resultData); GC gc = new GC (resultImage); gc.setAntialias (SWT.ON); - gc.drawImage (original, 0, 0, autoScaleDown (width), autoScaleDown (height), - /* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors. - * Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..). - */ - 0, 0, Math.round (autoScaleDown (width * scaleFactor)), Math.round (autoScaleDown (height * scaleFactor))); + Image.drawScaled(gc, original, width, height, scaleFactor); gc.dispose (); original.dispose (); ImageData result = resultImage.getImageData (getDeviceZoom ()); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java index dd8581c1348..c73e4dfe873 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java @@ -1551,4 +1551,27 @@ public String toString () { return "Image {" + surface + "}"; } +/** + * IMPORTANT: This method is not part of the public + * API for Image. It is marked public only so that it + * can be shared within the packages provided by SWT. + * + * Draws a scaled image using the GC by another image. + * + * @param gc the GC to draw on the resulting image + * @param original the image which is supposed to be scaled and drawn on the resulting image + * @param width the width of the original image + * @param height the height of the original image + * @param scaleFactor the factor with which the image is supposed to be scaled + * + * @noreference This method is not intended to be referenced by clients. + */ +public static void drawScaled(GC gc, Image original, int width, int height, float scaleFactor) { + gc.drawImage (original, 0, 0, DPIUtil.autoScaleDown (width), DPIUtil.autoScaleDown (height), + /* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors. + * Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..). + */ + 0, 0, Math.round (DPIUtil.autoScaleDown (width * scaleFactor)), Math.round (DPIUtil.autoScaleDown (height * scaleFactor))); +} + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index 7eaaaa9d36b..d45c6a75bd3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -807,6 +807,26 @@ public static long win32_getHandle (Image image, int zoom) { return image.getImageMetadata(zoom).handle; } +/** + * IMPORTANT: This method is not part of the public + * API for Image. It is marked public only so that it + * can be shared within the packages provided by SWT. + * + * Draws a scaled image using the GC by another image. + * + * @param gc the GC to draw on the resulting image + * @param original the image which is supposed to be scaled and drawn on the resulting image + * @param width the width of the original image + * @param height the height of the original image + * @param scaleFactor the factor with which the image is supposed to be scaled + * + * @noreference This method is not intended to be referenced by clients. + */ +public static void drawScaled(GC gc, Image original, int width, int height, float scaleFactor) { + gc.drawImage (original, 0, 0, width, height, + 0, 0, Math.round (width * scaleFactor), Math.round (height * scaleFactor), false); +} + long [] createGdipImage() { return createGdipImage(this.getZoom()); } @@ -1793,40 +1813,6 @@ public void setBackground(Color color) { zoomLevelToImageHandle.values().forEach(imageHandle -> imageHandle.setBackground(backgroundColor)); } -private ImageData scaleImageData(final ImageData imageData, int targetZoom, int currentZoom) { - if (imageData == null || targetZoom == currentZoom || (device != null && !device.isAutoScalable())) return imageData; - float scaleFactor = (float) targetZoom / (float) currentZoom; - int width = imageData.width; - int height = imageData.height; - int scaledWidth = Math.round (width * scaleFactor); - int scaledHeight = Math.round (height * scaleFactor); - boolean useSmoothScaling = DPIUtil.isSmoothScalingEnabled() && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK; - if (useSmoothScaling) { - return scaleToUsingSmoothScaling(scaledWidth, scaledHeight, imageData); - } - return imageData.scaledTo (scaledWidth, scaledHeight); -} - -private ImageData scaleToUsingSmoothScaling(int width, int height, ImageData imageData) { - Image original = new Image (device, (ImageDataProvider) zoom -> imageData); - /* Create a 24 bit image data with alpha channel */ - final ImageData resultData = new ImageData (width, height, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); - resultData.alphaData = new byte [width * height]; - Image resultImage = new Image (device, (ImageDataProvider) zoom -> resultData); - GC gc = new GC (resultImage); - gc.setAntialias (SWT.ON); - gc.drawImage (original, 0, 0, imageData.width, imageData.height, - /* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors. - * Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..). - */ - 0, 0, width, height, false); - gc.dispose (); - original.dispose (); - ImageData result = resultImage.getImageData (resultImage.getZoom()); - resultImage.dispose (); - return result; -} - private int getZoom() { return DPIUtil.getZoomForAutoscaleProperty(initialNativeZoom); } @@ -1887,7 +1873,7 @@ ImageData getScaledImageData (int zoom) { } TreeSet availableZooms = new TreeSet<>(zoomLevelToImageHandle.keySet()); int closestZoom = Optional.ofNullable(availableZooms.higher(zoom)).orElse(availableZooms.lower(zoom)); - return scaleImageData(getImageMetadata(closestZoom).getImageData(), zoom, closestZoom); + return DPIUtil.scaleImageData(device, getImageMetadata(closestZoom).getImageData(), zoom, closestZoom); } protected ImageHandle newImageHandle(int zoom) { @@ -2197,7 +2183,7 @@ protected ImageHandle newImageHandle(int zoom) { private ImageHandle initializeHandleFromSource(int zoom) { ElementAtZoom imageDataAtZoom = loadImageData(zoom); - ImageData imageData = scaleImageData(imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom()); + ImageData imageData = DPIUtil.scaleImageData (device,imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom()); imageData = adaptImageDataIfDisabledOrGray(imageData); return init(imageData, zoom); }