Skip to content

Commit 05db35c

Browse files
committed
[Win32] Ensure consistent image data returned for data-based images
Due to the on-demand creation of image handles, there is not necessarily a handles anymore from which image data is retrieved when requesting is via the getImageData(...) methods. This results in potentially different kinds of image data (including different anti-aliasing results) depending on whether a handle has already been created for an image at the given zoom or not. This change adapts the implementation of Image based on static ImageData and streams to always use the image data retrieved from a native handle. To this end, it temporarily creates a handle if necessary. In order to avoid repeated loading and handle creation for the same source of image, a cache for the already retrieved image data is introduced. Fixes #2052
1 parent 504c82b commit 05db35c

File tree

2 files changed

+57
-11
lines changed

2 files changed

+57
-11
lines changed

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java

+32-11
Original file line numberDiff line numberDiff line change
@@ -1878,14 +1878,18 @@ ImageData getScaledImageData (int zoom) {
18781878

18791879
protected ImageHandle newImageHandle(int zoom) {
18801880
ImageData resizedData = getImageData(zoom);
1881-
if (type == SWT.ICON && resizedData.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
1881+
return newImageHandle(resizedData, zoom);
1882+
}
1883+
1884+
protected final ImageHandle newImageHandle(ImageData data, int zoom) {
1885+
if (type == SWT.ICON && data.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
18821886
// If the original type was an icon with transparency mask and re-scaling leads
18831887
// to image data without transparency mask, this will create invalid images
18841888
// so this fallback will "repair" the image data by explicitly passing
18851889
// the transparency mask created from the scaled image data
1886-
return initIconHandle(device, resizedData, resizedData.getTransparencyMask(), zoom);
1890+
return initIconHandle(device, data, data.getTransparencyMask(), zoom);
18871891
} else {
1888-
return init(resizedData, zoom);
1892+
return init(data, zoom);
18891893
}
18901894
}
18911895

@@ -1933,26 +1937,43 @@ AbstractImageProviderWrapper createCopy(Image image) {
19331937
}
19341938

19351939
private abstract class ImageFromImageDataProviderWrapper extends AbstractImageProviderWrapper {
1940+
private final Map<Integer, ImageData> cachedImageData = new HashMap<>();
19361941

19371942
protected abstract ElementAtZoom<ImageData> loadImageData(int zoom);
19381943

19391944
void initImage() {
19401945
// As the init call configured some Image attributes (e.g. type)
19411946
// it must be called
1942-
ImageData imageDataAt100 = getImageData(100);
1943-
init(imageDataAt100, 100);
1944-
destroyHandleForZoom(100);
1947+
getImageData(100);
19451948
}
19461949

19471950
@Override
19481951
ImageData newImageData(int zoom) {
1949-
if (!zoomLevelToImageHandle.isEmpty()) {
1950-
return getScaledImageData(zoom);
1952+
Function<Integer, ImageData> imageDataRetrieval = zoomToRetrieve -> {
1953+
ImageHandle handle = initializeHandleFromSource(zoomToRetrieve);
1954+
ImageData data = handle.getImageData();
1955+
destroyHandleForZoom(zoomToRetrieve);
1956+
return data;
1957+
};
1958+
return cachedImageData.computeIfAbsent(zoom, imageDataRetrieval);
1959+
}
1960+
1961+
@Override
1962+
protected ImageHandle newImageHandle(int zoom) {
1963+
ImageData cachedData = cachedImageData.remove(zoom);
1964+
if (cachedData != null) {
1965+
return newImageHandle(cachedData, zoom);
19511966
}
1952-
ElementAtZoom<ImageData> loadedImageData = loadImageData(zoom);
1953-
ImageData scaledImageData = DPIUtil.scaleImageData(device, loadedImageData, zoom);
1954-
return adaptImageDataIfDisabledOrGray(scaledImageData);
1967+
return initializeHandleFromSource(zoom);
1968+
}
1969+
1970+
private ImageHandle initializeHandleFromSource(int zoom) {
1971+
ElementAtZoom<ImageData> imageDataAtZoom = loadImageData(zoom);
1972+
ImageData imageData = scaleImageData(imageDataAtZoom.element(), zoom, imageDataAtZoom.zoom());
1973+
imageData = adaptImageDataIfDisabledOrGray(imageData);
1974+
return newImageHandle(imageData, zoom);
19551975
}
1976+
19561977
}
19571978

19581979
private class PlainImageDataProviderWrapper extends ImageFromImageDataProviderWrapper {

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java

+25
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,31 @@ public void test_imageDataSameViaDifferentProviders() {
10331033
dataProviderImage.dispose();
10341034
}
10351035

1036+
@Test
1037+
public void test_imageDataSameViaProviderAndSimpleData() {
1038+
assumeFalse("Cocoa generates inconsistent image data", SwtTestUtil.isCocoa);
1039+
String imagePath = getPath("collapseall.png");
1040+
ImageFileNameProvider imageFileNameProvider = __ -> {
1041+
return imagePath;
1042+
};
1043+
ImageDataProvider dataProvider = __ -> {
1044+
try (InputStream imageStream = Files.newInputStream(Path.of(imagePath))) {
1045+
return new ImageData(imageStream);
1046+
} catch (IOException e) {
1047+
}
1048+
return null;
1049+
};
1050+
Image fileNameProviderImage = new Image(display, imageFileNameProvider);
1051+
Image dataImage = new Image(display, dataProvider.getImageData(100));
1052+
ImageData dataFromFileNameProviderImage = fileNameProviderImage.getImageData(100);
1053+
ImageData dataFromImageWithSimpleData = dataImage.getImageData(100);
1054+
assertEquals(0, imageDataComparator().compare(dataFromFileNameProviderImage, dataFromImageWithSimpleData));
1055+
1056+
fileNameProviderImage.dispose();
1057+
dataImage.dispose();
1058+
}
1059+
1060+
10361061
private Comparator<ImageData> imageDataComparator() {
10371062
return Comparator.<ImageData>comparingInt(d -> d.width) //
10381063
.thenComparing(d -> d.height) //

0 commit comments

Comments
 (0)