Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create handles for ImageDataProvider and ImageFilenameProvider on demand #1898

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ShahzaibIbrahim
Copy link
Contributor

Currently, when an image is instantiated using ImageDataProvider or ImageFileNameProvider, a handle is created immediately. We aim to optimize this by deferring handle creation until it is explicitly needed. To achieve this, getBounds() will return the bounds of a 100% zoomed image when called after instantiation, without requiring a handle to be created upfront. This change improves efficiency by reducing unnecessary resource allocation during image initialization.

Attaching the snippet to test the use cases after this change:

package org.eclipse.swt.snippets;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;

public class SnippetTestImage {

	final static String IMAGES_ROOT = "bin/org/eclipse/swt/snippets/";

	public static void main(String[] args) {
		imageFileNameProviderExample();
		imageDataProviderExample();
	}

	private static void imageDataProviderExample() {
		Image image;
		final Display display = new Display();
		ImageDataProvider imageDataProvider = zoom -> {
			String fileName;
			switch (zoom) {
			case 100:
				fileName = "eclipse16.png";
				break;
			case 150:
				fileName = "eclipse24.png";
				break;
			case 200:
			case 250:
				fileName = "eclipse32.png";
				break;
			default:
				return null;
			}
			return new ImageData(IMAGES_ROOT + fileName);
		};
		try {
			image = new Image(display, imageDataProvider);
			System.out.println("Image Bounds initially = " + image.getBounds());
			ImageData imgData = image.getImageData(250);
			System.out.println("Image Bounds on Demand (250) = " + imgData.height + " width = " + imgData.width);
			image.dispose();
		} catch (SWTException e) {
			System.out.println(e);
		}
	}

	private static void imageFileNameProviderExample() {
		Image image;
		final Display display = new Display();
		ImageFileNameProvider provider = zoom -> {
			String fileName;
			switch (zoom) {
			case 100:
				fileName = "eclipse16.png";
				break;
			case 150:
				fileName = "eclipse24.png";
				break;
			case 200:
			case 250:
				fileName = "eclipse32.png";
				break;
			default:
				return null;
			}
			return IMAGES_ROOT + fileName;
		};
		try {
			image = new Image(display, provider);
			System.out.println("Image Bounds initially = " + image.getBounds());
			ImageData imgData = image.getImageData(250);
			System.out.println("Image Bounds on Demand (250) = " + imgData.height + " width = " + imgData.width);
			image.dispose();
		} catch (SWTException e) {
			System.out.println(e);
		}
	}
}

Copy link
Contributor

github-actions bot commented Mar 11, 2025

Test Results

   510 files  + 1     510 suites  +1   8m 16s ⏱️ - 2m 4s
 4 345 tests +37   4 331 ✅ +36   14 💤 +3  0 ❌  - 2 
16 613 runs  +37  16 502 ✅ +36  111 💤 +3  0 ❌  - 2 

Results for commit 592917e. ± Comparison against base commit 7f381e8.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@fedejeanne fedejeanne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a NIT: width and height could be final (also in ImageGcDrawerWrapper)

Comment on lines +2123 to +2125
private boolean isDestroyed;
private int width;
private int height;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make sense to store these values in the AbstractImageProviderWrapper, now that all it's subclasses have such properties? You could also move the concrete implementations for isDisposed() and destroy() into the superclass then.

Copy link
Contributor

@akoch-yatta akoch-yatta Mar 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When testing the branch I noticed a weird behavior. When smooth scaling is involved we can run into exceptions with these changes and I am questioning, what the proper expectation here is. So, in smooth scaling we are doing this:
Image original = new Image (device, (ImageDataProvider) zoom -> imageData);
This returns for each zoom the same ImageData. As we are using the ImageData at zoom 100 to define width and height, we have a problem now, because the bounds of the Image at 150% will no longer match the ImageData size at 150%, because getBounds scales the width and height up.
For this concrete case you could argue the ImageDataProvider implementation should be adapted, but in general I think we need to go the less efficient route and not store width and height, but always calculate them on demand with a proper handle. We can not guarantee, that there is a linear relation between the ImageData returned from an ImageDataProvider or an ImageFileNameProvider and the zoom.

Copy link
Contributor

@HeikoKlare HeikoKlare Mar 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand and agree that we probably have to calculate height/width for the according handle.
Even if we could argue and reasonably assume that image data is scaled according to the zoom, there might different ways of rounding the sizes which can then lead to off-by-one errors in the sizes. Thus the bounds probably need to be calculated from the actual image handle / image data to be safe here.

But it would still be better to do that either on demand or or first request, as it would avoid the initial creation of a potentially unused handle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create handles for ImageDataProvider and ImageFilenameProvider on demand
4 participants