Skip to content

Commit f767746

Browse files
committed
Allow to test for loading image at zoom and fix faulty Win32 image load
The ImageLoader and FileFormat implementations currently combine the check whether an image can be provided at a specific scale value and the provision of an image in the scale itself. In case a consumer wants to only test whether an image can be provided at a specific scale, it needs to request that image at that scale, even if it will not be used later one, e.g., because it cannot be provided in the required scale. With this change, ImageLoader and FileFormat provide separate methods for validating whether an image can be retrieved at a specific zoom (such as from an SVG) and the retrieval of the image itself. This is employed by the Cocoa Image implementation to avoid unnecessary load operations and in the Win32 Image implementation to correct erroneous scaling from an already initialized handle instead of loading at proper zoom (such as for an SVG). In addition, this fixes a faulty reuse of the same stream in the Cocoa Image implementation at the same place.
1 parent 3670670 commit f767746

File tree

5 files changed

+55
-23
lines changed

5 files changed

+55
-23
lines changed

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

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import org.eclipse.swt.*;
2222
import org.eclipse.swt.internal.*;
23-
import org.eclipse.swt.internal.DPIUtil.*;
2423
import org.eclipse.swt.internal.cocoa.*;
2524
import org.eclipse.swt.internal.graphics.*;
2625
import org.eclipse.swt.internal.image.*;
@@ -695,8 +694,12 @@ public Image(Device device, InputStream stream) {
695694
NSAutoreleasePool pool = null;
696695
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
697696
try {
698-
initWithSupplier(zoom -> ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, zoom));
697+
byte[] input = stream.readAllBytes();
698+
initWithSupplier(zoom -> ImageDataLoader.canLoadAtZoom(new ByteArrayInputStream(input), FileFormat.DEFAULT_ZOOM, zoom),
699+
zoom -> ImageDataLoader.load(new ByteArrayInputStream(input), FileFormat.DEFAULT_ZOOM, zoom).element());
699700
init();
701+
} catch (IOException e) {
702+
SWT.error(SWT.ERROR_INVALID_ARGUMENT, e);
700703
} finally {
701704
if (pool != null) pool.release();
702705
}
@@ -741,7 +744,10 @@ public Image(Device device, String filename) {
741744
try {
742745
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
743746
initNative(filename);
744-
if (this.handle == null) initWithSupplier(zoom -> ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, zoom));
747+
if (this.handle == null) {
748+
initWithSupplier(zoom -> ImageDataLoader.canLoadAtZoom(filename, FileFormat.DEFAULT_ZOOM, zoom),
749+
zoom -> ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, zoom).element());
750+
}
745751
init();
746752
} finally {
747753
if (pool != null) pool.release();
@@ -795,15 +801,13 @@ public Image(Device device, ImageFileNameProvider imageFileNameProvider) {
795801
id id = NSImageRep.imageRepWithContentsOfFile(NSString.stringWith(filename2x));
796802
NSImageRep rep = new NSImageRep(id);
797803
handle.addRepresentation(rep);
798-
} else {
804+
} else if (ImageDataLoader.canLoadAtZoom(filename, 100, 200)) {
799805
// Try to natively scale up the image (e.g. possible if it's an SVG)
800-
ElementAtZoom<ImageData> imageData2x = ImageDataLoader.load(filename, 100, 200);
801-
if (imageData2x.zoom() == 200) {
802-
alphaInfo_200 = new AlphaInfo();
803-
NSBitmapImageRep rep = createRepresentation (imageData2x.element(), alphaInfo_200);
804-
handle.addRepresentation(rep);
805-
rep.release();
806-
}
806+
ImageData imageData2x = ImageDataLoader.load(filename, 100, 200).element();
807+
alphaInfo_200 = new AlphaInfo();
808+
NSBitmapImageRep rep = createRepresentation (imageData2x, alphaInfo_200);
809+
handle.addRepresentation(rep);
810+
rep.release();
807811
}
808812
} finally {
809813
if (pool != null) pool.release();
@@ -1484,17 +1488,11 @@ void init(ImageData image) {
14841488
handle.setCacheMode(OS.NSImageCacheNever);
14851489
}
14861490

1487-
private void initWithSupplier(Function<Integer, ElementAtZoom<ImageData>> zoomToImageData) {
1488-
ElementAtZoom<ImageData> imageData = zoomToImageData.apply(DPIUtil.getDeviceZoom());
1489-
ImageData imageData2x = null;
1490-
if (imageData.zoom() == 200) {
1491-
imageData2x = imageData.element();
1492-
}
1493-
if (imageData.zoom() != 100) {
1494-
imageData = zoomToImageData.apply(100);
1495-
}
1496-
init(imageData.element());
1497-
if (imageData2x != null) {
1491+
private void initWithSupplier(Function<Integer, Boolean> canLoadAtZoom, Function<Integer, ImageData> zoomToImageData) {
1492+
ImageData imageData = zoomToImageData.apply(100);
1493+
init(imageData);
1494+
if (canLoadAtZoom.apply(200)) {
1495+
ImageData imageData2x = zoomToImageData.apply(200);
14981496
alphaInfo_200 = new AlphaInfo();
14991497
NSBitmapImageRep rep = createRepresentation (imageData2x, alphaInfo_200);
15001498
handle.addRepresentation(rep);

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataLoader.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,20 @@ public static ImageData load(String filename) {
3737
return data[0];
3838
}
3939

40+
public static boolean canLoadAtZoom(InputStream stream, int fileZoom, int targetZoom) {
41+
return ImageLoader.canLoadAtZoom(stream, fileZoom, targetZoom);
42+
}
43+
4044
public static ElementAtZoom<ImageData> load(InputStream stream, int fileZoom, int targetZoom) {
4145
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(stream, fileZoom, targetZoom);
4246
if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE);
4347
return data.get(0);
4448
}
4549

50+
public static boolean canLoadAtZoom(String filename, int fileZoom, int targetZoom) {
51+
return ImageLoader.canLoadAtZoom(filename, fileZoom, targetZoom);
52+
}
53+
4654
public static ElementAtZoom<ImageData> load(String filename, int fileZoom, int targetZoom) {
4755
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(filename, fileZoom, targetZoom);
4856
if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE);

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ List<ElementAtZoom<ImageData>> load(InputStream stream, int fileZoom, int target
163163
return images;
164164
}
165165

166+
static boolean canLoadAtZoom(InputStream stream, int fileZoom, int targetZoom) {
167+
if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
168+
return FileFormat.canLoadAtZoom(new ElementAtZoom<>(stream, fileZoom), targetZoom);
169+
}
170+
166171
/**
167172
* Loads an array of <code>ImageData</code> objects from the
168173
* file with the specified name. Throws an error if either
@@ -196,6 +201,16 @@ List<ElementAtZoom<ImageData>> load(String filename, int fileZoom, int targetZoo
196201
return null;
197202
}
198203

204+
static boolean canLoadAtZoom(String filename, int fileZoom, int targetZoom) {
205+
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
206+
try (InputStream stream = new FileInputStream(filename)) {
207+
return canLoadAtZoom(stream, fileZoom, targetZoom);
208+
} catch (IOException e) {
209+
SWT.error(SWT.ERROR_IO, e);
210+
}
211+
return false;
212+
}
213+
199214
/**
200215
* Saves the image data in this ImageLoader to the specified stream.
201216
* The format parameter can have one of the following values:

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public static List<ElementAtZoom<ImageData>> load(ElementAtZoom<InputStream> is,
136136
return fileFormat.loadFromStream(stream, is.zoom(), targetZoom);
137137
}
138138

139+
public static boolean canLoadAtZoom(ElementAtZoom<InputStream> is, int targetZoom) {
140+
return is.zoom() == targetZoom || isDynamicallySizableFormat(is.element());
141+
}
142+
139143
/**
140144
* Write the device independent image array stored in the specified loader
141145
* to the specified output stream using the specified file format.

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2212,13 +2212,20 @@ private class ImageFileNameProviderWrapper extends BaseImageProviderWrapper<Imag
22122212
@Override
22132213
ImageData getImageData(int zoom) {
22142214
ElementAtZoom<String> fileForZoom = DPIUtil.validateAndGetImagePathAtZoom(provider, zoom);
2215+
2216+
// Load at appropriate zoom via loader
2217+
if (fileForZoom.zoom() != zoom && ImageDataLoader.canLoadAtZoom(fileForZoom.element(), fileForZoom.zoom(), zoom)) {
2218+
ElementAtZoom<ImageData> imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom);
2219+
return adaptImageDataIfDisabledOrGray(imageDataAtZoom.element());
2220+
}
2221+
2222+
// Load at file zoom (native or via loader) and rescale
22152223
ImageHandle nativeInitializedImage;
22162224
if (zoomLevelToImageHandle.containsKey(fileForZoom.zoom())) {
22172225
nativeInitializedImage = zoomLevelToImageHandle.get(fileForZoom.zoom());
22182226
} else {
22192227
nativeInitializedImage = initNative(fileForZoom.element(), fileForZoom.zoom());
22202228
}
2221-
22222229
ElementAtZoom<ImageData> imageDataAtZoom;
22232230
if (nativeInitializedImage == null) {
22242231
imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom);

0 commit comments

Comments
 (0)