Skip to content

GC#drawImage() does not consider applied Transform when selecting best-fitting image source #2919

@HeikoKlare

Description

@HeikoKlare

Describe the bug
When a Transform is applied to a GC and any of the drawImage methods is used, the selection of the best fitting scaled version of the image does not take into account that applied transformation. E.g., drawing a 16x16 image that exists at 100% and 200% (or even at any zoom if provided as SVG) with a Transform scaling by 2 in each direction, the 100% image is used an scaled up even though a 200% image as perfect fit exists.

To Reproduce
The following snippet shows the behavior. It can be placed in the SWT snippets project to have the according images available.
When starting the snippet, the images at the left are drawn with GC#drawImage() methods using double the destination size than the source size (where the best fitting scaled version is taken). The images at the right are drawn with GC#drawImage() methods using the same source and destination size but using a Transform applied to the GC that scaled by factor 2:

import org.eclipse.swt.widgets.*;

public class Snippet389 {

public static void main (String [] args) {
	Display display = new Display ();
	Shell shell = new Shell(display);
	shell.setText("Snippet 389");
	ImageFileNameProvider fileNameProvider = zoom -> {
		if (zoom == 200) {
			return "src/org/eclipse/swt/snippets/eclipse32.png";
		} else if (zoom == 100) {
			return "src/org/eclipse/swt/snippets/eclipse16.png";
		}
		return null;
	};
	Image image = new Image(display, fileNameProvider);
	shell.addPaintListener(e -> {
		e.gc.drawImage(image, 0, 0, 32, 32);
		e.gc.drawImage(image, 0, 0, 16, 16, 0, 50, 32, 32);
	});

	shell.addPaintListener(e -> {
		e.gc.setTransform(new Transform(display, 2, 0, 0, 2, 0, 0));
		e.gc.drawImage(image, 25, 0, 16, 16);
		e.gc.drawImage(image, 0, 0, 16, 16, 25, 25, 16, 16);
		e.gc.setTransform(null);
	});

	shell.open ();

	while (!shell.isDisposed ()) {
		if (!display.readAndDispatch ()) display.sleep ();
	}
	display.dispose ();
}
}

Expected behavior
The GC#drawImage() methods shall take into account a Transform applied to the GC, such that the best fitting image handle is used. Especially in case of an SVG, it shall be rendered as a perfect fit.

Note that currently the different GC#drawImage() methods use different means to determine the best fitting image handle. E.g., on Windows, some do not even consider any zoom, some rely on calculateZoomForImage, some defer to Image#executeOnImageHandleAtBestFittingSize().
In my opionion, the most universal solution would be to have the GC only determine the required size (based on source and destination width/height and potentially x and y as well as an applied Transform) and let Image#executeOnImageHandleAtBestFittingSize() select the best fitting handle for that desired size.

Screenshots
This is how the snippet looks:
Image

Left reflects the expected state, right reflects the current state when using a Transform on a GC.

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • All OS
    • Windows
    • Linux
    • macOS

Version since
This functionality has never been implemented.

Workaround (or) Additional context
As a consumer, you can work around the issue by trying to fake an image that best fits to the applied Transform, such as being tried for GEF:

Also see:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions