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 d45c6a75bd..f74612574d 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 @@ -1878,14 +1878,18 @@ ImageData getScaledImageData (int zoom) { protected ImageHandle newImageHandle(int zoom) { ImageData resizedData = getImageData(zoom); - if (type == SWT.ICON && resizedData.getTransparencyType() != SWT.TRANSPARENCY_MASK) { + return newImageHandle(resizedData, zoom); + } + + protected final ImageHandle newImageHandle(ImageData data, int zoom) { + if (type == SWT.ICON && data.getTransparencyType() != SWT.TRANSPARENCY_MASK) { // If the original type was an icon with transparency mask and re-scaling leads // to image data without transparency mask, this will create invalid images // so this fallback will "repair" the image data by explicitly passing // the transparency mask created from the scaled image data - return initIconHandle(device, resizedData, resizedData.getTransparencyMask(), zoom); + return initIconHandle(device, data, data.getTransparencyMask(), zoom); } else { - return init(resizedData, zoom); + return init(data, zoom); } } @@ -1933,26 +1937,43 @@ AbstractImageProviderWrapper createCopy(Image image) { } private abstract class ImageFromImageDataProviderWrapper extends AbstractImageProviderWrapper { + private final Map<Integer, ImageData> cachedImageData = new HashMap<>(); protected abstract ElementAtZoom<ImageData> loadImageData(int zoom); void initImage() { // As the init call configured some Image attributes (e.g. type) // it must be called - ImageData imageDataAt100 = getImageData(100); - init(imageDataAt100, 100); - destroyHandleForZoom(100); + getImageData(100); } @Override ImageData newImageData(int zoom) { - if (!zoomLevelToImageHandle.isEmpty()) { - return getScaledImageData(zoom); + Function<Integer, ImageData> imageDataRetrieval = zoomToRetrieve -> { + ImageHandle handle = initializeHandleFromSource(zoomToRetrieve); + ImageData data = handle.getImageData(); + destroyHandleForZoom(zoomToRetrieve); + return data; + }; + return cachedImageData.computeIfAbsent(zoom, imageDataRetrieval); + } + + @Override + protected ImageHandle newImageHandle(int zoom) { + ImageData cachedData = cachedImageData.remove(zoom); + if (cachedData != null) { + return newImageHandle(cachedData, zoom); } - ElementAtZoom<ImageData> loadedImageData = loadImageData(zoom); - ImageData scaledImageData = DPIUtil.scaleImageData(device, loadedImageData, zoom); - return adaptImageDataIfDisabledOrGray(scaledImageData); + return initializeHandleFromSource(zoom); + } + + private ImageHandle initializeHandleFromSource(int zoom) { + ElementAtZoom<ImageData> imageDataAtZoom = loadImageData(zoom); + ImageData imageData = DPIUtil.scaleImageData(device, imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom()); + imageData = adaptImageDataIfDisabledOrGray(imageData); + return newImageHandle(imageData, zoom); } + } private class PlainImageDataProviderWrapper extends ImageFromImageDataProviderWrapper { diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java index 5bc9cc034c..c18b01add6 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java @@ -1033,6 +1033,31 @@ public void test_imageDataSameViaDifferentProviders() { dataProviderImage.dispose(); } +@Test +public void test_imageDataSameViaProviderAndSimpleData() { + assumeFalse("Cocoa generates inconsistent image data", SwtTestUtil.isCocoa); + String imagePath = getPath("collapseall.png"); + ImageFileNameProvider imageFileNameProvider = __ -> { + return imagePath; + }; + ImageDataProvider dataProvider = __ -> { + try (InputStream imageStream = Files.newInputStream(Path.of(imagePath))) { + return new ImageData(imageStream); + } catch (IOException e) { + } + return null; + }; + Image fileNameProviderImage = new Image(display, imageFileNameProvider); + Image dataImage = new Image(display, dataProvider.getImageData(100)); + ImageData dataFromFileNameProviderImage = fileNameProviderImage.getImageData(100); + ImageData dataFromImageWithSimpleData = dataImage.getImageData(100); + assertEquals(0, imageDataComparator().compare(dataFromFileNameProviderImage, dataFromImageWithSimpleData)); + + fileNameProviderImage.dispose(); + dataImage.dispose(); +} + + private Comparator<ImageData> imageDataComparator() { return Comparator.<ImageData>comparingInt(d -> d.width) // .thenComparing(d -> d.height) //