From 8e281f99c7cca5826c14e7b4ca0d1c99636c07d4 Mon Sep 17 00:00:00 2001 From: Shahzaib Ibrahim Date: Tue, 13 Jan 2026 16:02:11 +0100 Subject: [PATCH] Sharp rendering of SVGs passed as InputStream Wrapping the input stream handling in an ImageDataProvider. In case stream data belong to a dynamically sizable image we create a provider with ImageDataAtSizeProvider else we use ImageDataProvider. - The ImageDataAtSizeProvider will store the stream data and return accordingly loaded image data in its getImageData(width, height) and getImageData(zoom) methods. - The ImageDataProvider will only return according image data at 100% and none for the other zoom, so it does not need to store the stream data. Contributes to: https://github.com/eclipse-platform/eclipse.platform.swt/issues/2917 --- .../cocoa/org/eclipse/swt/graphics/Image.java | 42 +++++++++++-------- .../gtk/org/eclipse/swt/graphics/Image.java | 30 ++++++++++--- 2 files changed, 49 insertions(+), 23 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 f8287bb25d5..5399e86f375 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 @@ -691,9 +691,8 @@ public Image(Device device, InputStream stream) { NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { - byte[] input = stream.readAllBytes(); - initWithSupplier(zoom -> ImageDataLoader.canLoadAtZoom(new ByteArrayInputStream(input), FileFormat.DEFAULT_ZOOM, zoom), - zoom -> ImageDataLoader.loadByZoom(new ByteArrayInputStream(input), FileFormat.DEFAULT_ZOOM, zoom).element()); + ImageDataProvider imageDataProvider = createImageDataProvider(stream); + initUsingImageDataProvider(imageDataProvider); init(); } catch (IOException e) { SWT.error(SWT.ERROR_IO, e); @@ -847,24 +846,14 @@ private void initUsingFileNameProvider(ImageFileNameProvider imageFileNameProvid public Image(Device device, ImageDataProvider imageDataProvider) { super(device); if (imageDataProvider == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - this.imageDataProvider = imageDataProvider; - ImageData data = imageDataProvider.getImageData (100); - if (data == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { - init (data, 100); + initUsingImageDataProvider(imageDataProvider); init (); StrictChecks.runIfStrictChecksEnabled(() -> { DPIUtil.validateLinearScaling(imageDataProvider); }); - ImageData data2x = imageDataProvider.getImageData (200); - if (data2x != null) { - alphaInfo_200 = new AlphaInfo(); - NSBitmapImageRep rep = createRepresentation (data2x, alphaInfo_200); - handle.addRepresentation(rep); - rep.release(); - } } finally { if (pool != null) pool.release(); } @@ -1511,11 +1500,15 @@ void init(ImageData image, int imageZoom) { handle.setCacheMode(OS.NSImageCacheNever); } -private void initWithSupplier(Function canLoadAtZoom, Function zoomToImageData) { - ImageData imageData = zoomToImageData.apply(100); +private void initUsingImageDataProvider(ImageDataProvider imageDataProvider) { + this.imageDataProvider = imageDataProvider; + ImageData imageData = imageDataProvider.getImageData(100); + if (imageData == null) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } init(imageData, 100); - if (canLoadAtZoom.apply(200)) { - ImageData imageData2x = zoomToImageData.apply(200); + ImageData imageData2x = imageDataProvider.getImageData(200); + if (imageData2x != null) { alphaInfo_200 = new AlphaInfo(); NSBitmapImageRep rep = createRepresentation (imageData2x, alphaInfo_200); handle.addRepresentation(rep); @@ -1523,6 +1516,19 @@ private void initWithSupplier(Function canLoadAtZoom, Function } } +private static ImageDataProvider createImageDataProvider(InputStream stream) throws IOException { + byte[] streamData = stream.readAllBytes(); + if (ImageDataLoader.isDynamicallySizable(new ByteArrayInputStream(streamData))) { + ImageDataAtSizeProvider imageDataAtSizeProvider = (width, height) -> ImageDataLoader + .loadBySize(new ByteArrayInputStream(streamData), width, height); + return imageDataAtSizeProvider; + } + + ImageData imageData = ImageDataLoader + .loadByZoom(new ByteArrayInputStream(streamData), FileFormat.DEFAULT_ZOOM, 100) + .element(); + return zoom -> zoom == 100 ? imageData : null; +} void initAlpha_200(NSBitmapImageRep nativeRep) { NSAutoreleasePool pool = null; 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 0b8372c6860..dbfeae394a6 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 @@ -554,11 +554,17 @@ public Image(Device device, ImageData source, ImageData mask) { */ public Image(Device device, InputStream stream) { super(device); - currentDeviceZoom = DPIUtil.getDeviceZoom(); - ElementAtZoom image = ImageDataLoader.loadByZoom(stream, FileFormat.DEFAULT_ZOOM, currentDeviceZoom); - ImageData data = DPIUtil.scaleImageData(device, image, currentDeviceZoom); - init(data); - init(); + if (stream == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + try { + currentDeviceZoom = DPIUtil.getDeviceZoom(); + this.imageDataProvider = createImageDataProvider(stream); + initFromImageDataProvider(currentDeviceZoom); + init(); + } catch (IOException e) { + SWT.error(SWT.ERROR_IO, e); + } } /** @@ -802,6 +808,20 @@ private void initFromImageDataProvider(int zoom) { init(resizedData); } +private static ImageDataProvider createImageDataProvider(InputStream stream) throws IOException { + byte[] streamData = stream.readAllBytes(); + if (ImageDataLoader.isDynamicallySizable(new ByteArrayInputStream(streamData))) { + ImageDataAtSizeProvider imageDataAtSizeProvider = (width, height) -> ImageDataLoader + .loadBySize(new ByteArrayInputStream(streamData), width, height); + return imageDataAtSizeProvider; + } + + ImageData imageData = ImageDataLoader + .loadByZoom(new ByteArrayInputStream(streamData), FileFormat.DEFAULT_ZOOM, 100) + .element(); + return zoom -> zoom == 100 ? imageData : null; +} + void createFromPixbuf(int type, long pixbuf) { this.type = type;