From 04d20e9326947fb3d8b1bf3d6aaf17a895ca42f2 Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Mon, 24 Mar 2025 11:26:28 +0100 Subject: [PATCH 1/2] Revert Smooth Scaling Rounding error fix for win32 This reverts commit 909a985f2b2c24a78b488b3ff1c12acb01517a04. # Conflicts: # bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java # Conflicts: # bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java --- .../org/eclipse/swt/internal/DPIUtil.java | 10 +---- .../win32/org/eclipse/swt/graphics/Image.java | 42 ++----------------- 2 files changed, 5 insertions(+), 47 deletions(-) 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 91c993bed75..e80d1ad6596 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 @@ -292,7 +292,7 @@ private static ImageData autoScaleImageData (Device device, final ImageData imag int height = imageData.height; int scaledWidth = Math.round (width * scaleFactor); int scaledHeight = Math.round (height * scaleFactor); - boolean useSmoothScaling = isSmoothScalingEnabled() && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK; + boolean useSmoothScaling = autoScaleMethod == AutoScaleMethod.SMOOTH && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK; if (useSmoothScaling) { Image original = new Image (device, (ImageDataProvider) zoom -> imageData); /* Create a 24 bit image data with alpha channel */ @@ -316,10 +316,6 @@ private static ImageData autoScaleImageData (Device device, final ImageData imag } } -public static boolean isSmoothScalingEnabled() { - return autoScaleMethod == AutoScaleMethod.SMOOTH; -} - /** * Returns a new rectangle as per the scaleFactor. */ @@ -640,10 +636,6 @@ public static boolean useCairoAutoScale() { } public static int getZoomForAutoscaleProperty (int nativeDeviceZoom) { - return getZoomForAutoscaleProperty(nativeDeviceZoom, autoScaleValue); -} - -private static int getZoomForAutoscaleProperty (int nativeDeviceZoom, String autoScaleValue) { int zoom = 0; if (autoScaleValue != null) { if ("false".equalsIgnoreCase (autoScaleValue)) { 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 b417ce5399d..b2ca3d30b34 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 @@ -1265,7 +1265,7 @@ private 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); } @@ -1855,40 +1855,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); } @@ -2233,7 +2199,7 @@ ImageData getImageData(int zoom) { private ImageData scaleIfNecessary(ElementAtZoom imageDataAtZoom, int zoom) { if (imageDataAtZoom.zoom() != zoom) { - return scaleImageData(imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom()); + return DPIUtil.scaleImageData(device, imageDataAtZoom, zoom); } return imageDataAtZoom.element(); } @@ -2457,13 +2423,13 @@ private class ImageDataProviderWrapper extends BaseImageProviderWrapper data = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom); - return scaleImageData(data.element(), zoom, data.zoom()); + return DPIUtil.scaleImageData (device, data.element(), zoom, data.zoom()); } @Override ImageHandle getImageMetadata(int zoom) { ElementAtZoom imageCandidate = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom); - ImageData resizedData = scaleImageData(imageCandidate.element(), zoom, imageCandidate.zoom()); + ImageData resizedData = DPIUtil.scaleImageData (device, imageCandidate.element(), zoom, imageCandidate.zoom()); ImageData newData = adaptImageDataIfDisabledOrGray(resizedData); init(newData, zoom); return zoomLevelToImageHandle.get(zoom); From 15c999a4fa336312653196f9a7d5c11eb791fb90 Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Mon, 24 Mar 2025 11:34:08 +0100 Subject: [PATCH 2/2] Move ImageData scaling logic to Image #62 This commit contributes to moving the logic for scaling the ImageData from DPIUtil to Image for each platform and use their own paltform specific implementations. The method gets rid of the methods specific to scaling ImageData, which are autoScaleImageData, scaleImageData, autoScaleUp and autoScaleDown from DPIUtil. 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 | 34 +++++++- .../org/eclipse/swt/internal/DPIUtil.java | 81 ++++--------------- .../gtk/org/eclipse/swt/graphics/Image.java | 55 ++++++++++--- .../org/eclipse/swt/graphics/Cursor.java | 18 +++-- .../win32/org/eclipse/swt/graphics/Image.java | 53 ++++++++---- 5 files changed, 142 insertions(+), 99 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 25ec987f0ee..bd9a9b781b7 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 @@ -1408,7 +1408,39 @@ public ImageData getImageData(int zoom) { } finally { if (pool != null) pool.release(); } - return DPIUtil.scaleImageData (device, getImageData(100), zoom, 100); + ImageData imageData = getImageData(100); + return scaledTo (imageData, zoom, 100, DPIUtil.getScalingType(imageData)); +} + +private ImageData scaledTo(ImageData imageData, int targetZoom, int currentZoom, int scaleType) { + if (imageData == null || currentZoom == targetZoom || !device.isAutoScalable()) { + return imageData; + } + float scaleFactor = (float) targetZoom / (float) currentZoom; + int scaledWidth = Math.round (imageData.width * scaleFactor); + int scaledHeight = Math.round (imageData.height * scaleFactor); + switch (scaleType) { + case SWT.SMOOTH: + return scaleUsingSmoothScaling(imageData, scaledWidth, scaledHeight); + default: + return imageData.scaledTo(scaledWidth, scaledHeight); + } +} + +private ImageData scaleUsingSmoothScaling(ImageData imageData, int width, int height) { + 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, 0, 0, width, height, false); + gc.dispose (); + original.dispose (); + ImageData result = resultImage.getImageData (DPIUtil.getDeviceZoom()); + resultImage.dispose (); + return result; } /** Returns the best available representation. May be 100% or 200% iff there is an image provider. */ 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 e80d1ad6596..dc5802164bf 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 @@ -109,15 +109,6 @@ private static enum AutoScaleMethod { AUTO, NEAREST, SMOOTH } } } -/** - * Auto-scale down ImageData - */ -public static ImageData autoScaleDown (Device device, final ImageData imageData) { - if (deviceZoom == 100 || imageData == null || (device != null && !device.isAutoScalable())) return imageData; - float scaleFactor = 1.0f / getScalingFactor (deviceZoom); - return autoScaleImageData(device, imageData, scaleFactor); -} - public static int[] autoScaleDown(int[] pointArray) { if (deviceZoom == 100 || pointArray == null) return pointArray; float scaleFactor = getScalingFactor (deviceZoom); @@ -272,47 +263,15 @@ public static Rectangle scaleDown(Drawable drawable, Rectangle rect, int zoom) { return scaleDown (rect, zoom); } -/** - * Auto-scale image with ImageData - */ -public static ImageData scaleImageData (Device device, final ImageData imageData, int targetZoom, int currentZoom) { - if (imageData == null || targetZoom == currentZoom || (device != null && !device.isAutoScalable())) return imageData; - float scaleFactor = (float) targetZoom / (float) currentZoom; - return autoScaleImageData(device, imageData, scaleFactor); -} - - -public static ImageData scaleImageData (Device device, final ElementAtZoom elementAtZoom, int targetZoom) { - return scaleImageData(device, elementAtZoom.element(), targetZoom, elementAtZoom.zoom()); -} - -private static ImageData autoScaleImageData (Device device, final ImageData imageData, float scaleFactor) { - // Guards are already implemented in callers: if (deviceZoom == 100 || imageData == null || scaleFactor == 1.0f) return imageData; - int width = imageData.width; - int height = imageData.height; - int scaledWidth = Math.round (width * scaleFactor); - int scaledHeight = Math.round (height * scaleFactor); - boolean useSmoothScaling = autoScaleMethod == AutoScaleMethod.SMOOTH && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK; - if (useSmoothScaling) { - Image original = new Image (device, (ImageDataProvider) zoom -> imageData); - /* Create a 24 bit image data with alpha channel */ - final ImageData resultData = new ImageData (scaledWidth, scaledHeight, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); - resultData.alphaData = new byte [scaledWidth * scaledHeight]; - 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))); - gc.dispose (); - original.dispose (); - ImageData result = resultImage.getImageData (getDeviceZoom ()); - resultImage.dispose (); - return result; - } else { - return imageData.scaledTo (scaledWidth, scaledHeight); +public static int getScalingType(ImageData imageData) { + switch(autoScaleMethod) { + case SMOOTH: + if (imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK) { + return SWT.SMOOTH; + } + return SWT.DEFAULT; + default: + return SWT.DEFAULT; } } @@ -330,22 +289,6 @@ public static Rectangle scaleBounds (Rectangle rect, int targetZoom, int current return returnRect; } -/** - * Auto-scale ImageData to device zoom that are at given zoom factor. - */ -public static ImageData autoScaleImageData (Device device, final ImageData imageData, int imageDataZoomFactor) { - if (deviceZoom == imageDataZoomFactor || imageData == null || (device != null && !device.isAutoScalable())) return imageData; - float scaleFactor = (float) deviceZoom / imageDataZoomFactor; - return autoScaleImageData(device, imageData, scaleFactor); -} - -/** - * Auto-scale up ImageData to device zoom that is at 100%. - */ -public static ImageData autoScaleUp (Device device, final ImageData imageData) { - return autoScaleImageData(device, imageData, 100); -} - public static int[] autoScaleUp(int[] pointArray) { return scaleUp(pointArray, deviceZoom); } @@ -738,7 +681,11 @@ public AutoScaleImageDataProvider(Device device, ImageData data, int zoom){ } @Override public ImageData getImageData(int zoom) { - return DPIUtil.scaleImageData(device, imageData, zoom, currentZoom); + Image image = new Image(device, imageData); + int adjustedZoom = (int) ((float) getDeviceZoom() / (float) currentZoom) * zoom; + ImageData imageData = image.getImageData(adjustedZoom); + image.dispose(); + return imageData; } } } \ No newline at end of file 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 9d69e5a3148..a22f2697355 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 @@ -423,7 +423,7 @@ public Image(Device device, ImageData data) { super(device); if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); currentDeviceZoom = DPIUtil.getDeviceZoom(); - data = DPIUtil.autoScaleUp (device, data); + data = scaledTo(data, DPIUtil.getDeviceZoom(), 100, DPIUtil.getScalingType(data)); init(data); init(); } @@ -466,8 +466,8 @@ public Image(Device device, ImageData source, ImageData mask) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } currentDeviceZoom = DPIUtil.getDeviceZoom(); - source = DPIUtil.autoScaleUp (device, source); - mask = DPIUtil.autoScaleUp (device, mask); + source = scaledTo(source, currentDeviceZoom, 100, DPIUtil.getScalingType(source)); + mask = scaledTo(mask, currentDeviceZoom, 100, DPIUtil.getScalingType(mask)); mask = ImageData.convertMask (mask); ImageData image = new ImageData(source.width, source.height, source.depth, source.palette, source.scanlinePad, source.data); image.maskPad = mask.scanlinePad; @@ -533,7 +533,7 @@ public Image(Device device, InputStream stream) { super(device); currentDeviceZoom = DPIUtil.getDeviceZoom(); ElementAtZoom image = ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, currentDeviceZoom); - ImageData data = DPIUtil.scaleImageData(device, image, currentDeviceZoom); + ImageData data = scaledTo(image.element(), currentDeviceZoom, image.zoom(), DPIUtil.getScalingType(image.element())); init(data); init(); } @@ -575,7 +575,7 @@ public Image(Device device, String filename) { if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); currentDeviceZoom = DPIUtil.getDeviceZoom(); ElementAtZoom image = ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, currentDeviceZoom); - ImageData data = DPIUtil.scaleImageData(device, image, currentDeviceZoom); + ImageData data = scaledTo(image.element(), currentDeviceZoom, image.zoom(), DPIUtil.getScalingType(image.element())); init(data); init(); } @@ -744,7 +744,7 @@ boolean refreshImageForZoom () { if (deviceZoomLevel != currentDeviceZoom) { ImageData data = getImageDataAtCurrentZoom(); destroy (); - ImageData resizedData = DPIUtil.scaleImageData(device, data, deviceZoomLevel, currentDeviceZoom); + ImageData resizedData = scaledTo(data, deviceZoomLevel, currentDeviceZoom, DPIUtil.getScalingType(data)); init(resizedData); init(); refreshed = true; @@ -778,7 +778,7 @@ private void initFromFileNameProvider(int zoom) { ElementAtZoom imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom); ImageData imageData = imageDataAtZoom.element(); if (imageDataAtZoom.zoom() != zoom) { - imageData = DPIUtil.scaleImageData(device, imageDataAtZoom, zoom); + imageData = scaledTo(imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom(), DPIUtil.getScalingType(imageData)); } init(imageData); } @@ -786,7 +786,7 @@ private void initFromFileNameProvider(int zoom) { private void initFromImageDataProvider(int zoom) { ElementAtZoom data = DPIUtil.validateAndGetImageDataAtZoom (imageDataProvider, zoom); - ImageData resizedData = DPIUtil.scaleImageData (device, data.element(), zoom, data.zoom()); + ImageData resizedData = scaledTo(data.element(), zoom, data.zoom(), DPIUtil.getScalingType(data.element())); init(resizedData); } @@ -1146,17 +1146,50 @@ public ImageData getImageData (int zoom) { return getImageDataAtCurrentZoom(); } else if (imageDataProvider != null) { ElementAtZoom data = DPIUtil.validateAndGetImageDataAtZoom (imageDataProvider, zoom); - return DPIUtil.scaleImageData (device, data.element(), zoom, data.zoom()); + return scaledTo(data.element(), zoom, data.zoom(), DPIUtil.getScalingType(data.element())); } else if (imageFileNameProvider != null) { ElementAtZoom fileName = DPIUtil.validateAndGetImagePathAtZoom (imageFileNameProvider, zoom); - return DPIUtil.scaleImageData (device, new ImageData (fileName.element()), zoom, fileName.zoom()); + ImageData imageData = new ImageData (fileName.element()); + return scaledTo(imageData, zoom, fileName.zoom(), DPIUtil.getScalingType(imageData)); } else if (imageGcDrawer != null) { return drawWithImageGcDrawer(width, height, zoom); } else { - return DPIUtil.scaleImageData (device, getImageDataAtCurrentZoom (), zoom, currentDeviceZoom); + ImageData imageData = getImageDataAtCurrentZoom (); + return scaledTo(imageData, zoom, currentDeviceZoom, DPIUtil.getScalingType(imageData)); } } +private ImageData scaledTo(ImageData imageData, int targetZoom, int currentZoom, int scaleType) { + if (imageData == null || currentZoom == targetZoom || !device.isAutoScalable()) { + return imageData; + } + float scaleFactor = (float) targetZoom / (float) currentZoom; + int scaledWidth = Math.round (imageData.width * scaleFactor); + int scaledHeight = Math.round (imageData.height * scaleFactor); + switch (scaleType) { + case SWT.SMOOTH: + return scaleUsingSmoothScaling(imageData, scaledWidth, scaledHeight); + default: + return imageData.scaledTo(scaledWidth, scaledHeight); + } +} + +private ImageData scaleUsingSmoothScaling(ImageData imageData, int width, int height) { + 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, 0, 0, width, height, false); + gc.dispose (); + original.dispose (); + ImageData result = resultImage.getImageData (DPIUtil.getDeviceZoom()); + resultImage.dispose (); + return result; +} + private ImageData drawWithImageGcDrawer(int width, int height, int zoom) { Image image = new Image(device, width, height); GC gc = new GC(image); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java index 719a4020a21..6c61c725b62 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java @@ -372,15 +372,21 @@ public static Long win32_getHandle (Cursor cursor, int zoom) { if (cursor.source == null) { cursor.setHandleForZoomLevel(cursor.handle, zoom); } else { - ImageData source = DPIUtil.scaleImageData(cursor.device, cursor.source, zoom, DEFAULT_ZOOM); + Image image; + ImageData source, mask; + Cursor newCursor; + image = new Image(cursor.device, cursor.source); + source = image.getImageData(zoom); + image.dispose(); if (cursor.isIcon) { - Cursor newCursor = new Cursor(cursor.device, source, cursor.hotspotX, cursor.hotspotY); - cursor.setHandleForZoomLevel(newCursor.handle, zoom); + newCursor = new Cursor(cursor.device, source, cursor.hotspotX, cursor.hotspotY); } else { - ImageData mask = DPIUtil.scaleImageData(cursor.device, cursor.mask, zoom, DEFAULT_ZOOM); - Cursor newCursor = new Cursor(cursor.device, source, mask, cursor.hotspotX, cursor.hotspotY); - cursor.setHandleForZoomLevel(newCursor.handle, zoom); + image = new Image(cursor.device, cursor.mask); + mask = image.getImageData(zoom); + image.dispose(); + newCursor = new Cursor(cursor.device, source, mask, cursor.hotspotX, cursor.hotspotY); } + cursor.setHandleForZoomLevel(newCursor.handle, zoom); } return cursor.zoomLevelToHandle.get(zoom); } 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 b2ca3d30b34..0a490d85c31 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 @@ -1265,7 +1265,39 @@ private ImageData getScaledImageData (int zoom) { } TreeSet availableZooms = new TreeSet<>(zoomLevelToImageHandle.keySet()); int closestZoom = Optional.ofNullable(availableZooms.higher(zoom)).orElse(availableZooms.lower(zoom)); - return DPIUtil.scaleImageData (device, getImageMetadata(closestZoom).getImageData(), zoom, closestZoom); + ImageData imageData = getImageMetadata(closestZoom).getImageData(); + return scaledTo(imageData, zoom, closestZoom, DPIUtil.getScalingType(imageData)); +} + +private ImageData scaledTo(ImageData imageData, int targetZoom, int currentZoom, int scaleType) { + if (imageData == null || currentZoom == targetZoom || !device.isAutoScalable()) { + return imageData; + } + float scaleFactor = (float) targetZoom / (float) currentZoom; + int scaledWidth = Math.round (imageData.width * scaleFactor); + int scaledHeight = Math.round (imageData.height * scaleFactor); + switch (scaleType) { + case SWT.SMOOTH: + return scaleUsingSmoothScaling(imageData, scaledWidth, scaledHeight); + default: + return imageData.scaledTo(scaledWidth, scaledHeight); + } +} + +private ImageData scaleUsingSmoothScaling(ImageData imageData, int width, int height) { + 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, 0, 0, width, height, false); + gc.dispose (); + original.dispose (); + ImageData result = resultImage.getImageData (resultImage.getZoom()); + resultImage.dispose (); + return result; } @@ -1933,7 +1965,7 @@ ImageData getImageData(int zoom) { return getScaledImageData(zoom); } ElementAtZoom loadedImageData = loadImageData(zoom); - return DPIUtil.scaleImageData(device, loadedImageData, zoom); + return scaledTo(loadedImageData.element(), zoom, loadedImageData.zoom(), DPIUtil.getScalingType(loadedImageData.element())); } @Override @@ -1991,8 +2023,8 @@ protected Rectangle getBounds(int zoom) { @Override protected ElementAtZoom loadImageData(int zoom) { - ImageData scaledSource = DPIUtil.scaleImageData(device, srcAt100, zoom, 100); - ImageData scaledMask = DPIUtil.scaleImageData(device, maskAt100, zoom, 100); + ImageData scaledSource = scaledTo(srcAt100, zoom, 100, DPIUtil.getScalingType(srcAt100)); + ImageData scaledMask = scaledTo(maskAt100, zoom, 100, DPIUtil.getScalingType(maskAt100)); scaledMask = ImageData.convertMask(scaledMask); ImageData mergedData = applyMask(scaledSource, scaledMask); return new ElementAtZoom<>(mergedData, zoom); @@ -2192,18 +2224,11 @@ ImageData getImageData(int zoom) { imageDataAtZoom = new ElementAtZoom<>(nativeInitializedImage.getImageData(), fileForZoom.zoom()); destroyHandleForZoom(zoom); } - ImageData imageData = scaleIfNecessary(imageDataAtZoom, zoom); + ImageData imageData = scaledTo(imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom(), DPIUtil.getScalingType(imageDataAtZoom.element())); imageData = adaptImageDataIfDisabledOrGray(imageData); return imageData; } - private ImageData scaleIfNecessary(ElementAtZoom imageDataAtZoom, int zoom) { - if (imageDataAtZoom.zoom() != zoom) { - return DPIUtil.scaleImageData(device, imageDataAtZoom, zoom); - } - return imageDataAtZoom.element(); - } - @Override ImageHandle getImageMetadata(int zoom) { ImageData imageData = getImageData(zoom); @@ -2423,13 +2448,13 @@ private class ImageDataProviderWrapper extends BaseImageProviderWrapper data = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom); - return DPIUtil.scaleImageData (device, data.element(), zoom, data.zoom()); + return scaledTo(data.element(), zoom, data.zoom(), DPIUtil.getScalingType(data.element())); } @Override ImageHandle getImageMetadata(int zoom) { ElementAtZoom imageCandidate = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom); - ImageData resizedData = DPIUtil.scaleImageData (device, imageCandidate.element(), zoom, imageCandidate.zoom()); + ImageData resizedData = scaledTo(imageCandidate.element(), zoom, imageCandidate.zoom(), DPIUtil.getScalingType(imageCandidate.element())); ImageData newData = adaptImageDataIfDisabledOrGray(resizedData); init(newData, zoom); return zoomLevelToImageHandle.get(zoom);