Skip to content

Commit cf6ee39

Browse files
HeikoKlarefedejeanne
authored andcommitted
Add snippet for demonstrating options to programmatically create images
With the implementation of monitor-specific UI scaling on Windows, an SWT application does not have a static zoom anymore. The zoom will be specific for each shell and the monitor it is currently placed on. As a consequence, when programmatically creating an image, the target zoom at which it will be used is not known when creating the image anymore. Instead, it will depend on the context in which the image is used later on. There are multiple options how to achieve that such an image will still be rendered at the according zoom in a sharp way instead of rendering it at an arbitrary zoom and then scaling it in a blurry way. This snippet demonstrates these different options and also a common way for programmatic image creation that will lead to blurry results.
1 parent b608609 commit cf6ee39

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

examples/org.eclipse.swt.snippets/Snippets.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ To contribute a new snippet, [create a snippet contribution as a pull request](h
216216
- [draw a disabled/grayed image at various zoom levels](https://github.com/eclipse-platform/eclipse.platform.swt/tree/master/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java)[(preview)](https://github.com/eclipse-platform/eclipse.platform.swt/blob/master/examples/org.eclipse.swt.snippets/previews/Snippet382.png "Preview for Snippet 382")
217217
- [compare algorithms for rendering disabled images](https://github.com/eclipse-platform/eclipse.platform.swt/tree/master/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet384.java)[(preview)](https://github.com/eclipse-platform/eclipse.platform.swt/blob/master/examples/org.eclipse.swt.snippets/previews/Snippet384.png "Preview for Snippet 384")
218218
- [draw an image with watermark using ImageGcProvider](https://github.com/eclipse-platform/eclipse.platform.swt/tree/master/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet385.java)[(preview)](https://github.com/eclipse-platform/eclipse.platform.swt/blob/master/examples/org.eclipse.swt.snippets/previews/Snippet385.png "Preview for Snippet 385")
219+
- [options for programmatically creating an image](https://github.com/eclipse-platform/eclipse.platform.swt/tree/master/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet387.java)[(preview)](https://github.com/eclipse-platform/eclipse.platform.swt/blob/master/examples/org.eclipse.swt.snippets/previews/Snippet387.png "Preview for Snippet 387")
219220

220221
### **ImageData**
221222
- [display an animated GIF](https://github.com/eclipse-platform/eclipse.platform.swt/tree/master/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet141.java)
15 KB
Loading
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Vector Informatik GmbH and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*******************************************************************************/
11+
package org.eclipse.swt.snippets;
12+
13+
import org.eclipse.swt.graphics.*;
14+
import org.eclipse.swt.widgets.*;
15+
16+
/**
17+
* Demonstrates different ways of programmatically creating an image with a GC
18+
* <p>
19+
* When creating an image programmatically, it is important to use an
20+
* appropriate way of doing that when at the time of image creation it is not
21+
* yet known at which zoom the image will be used. This is particularly the case
22+
* when using monitor-specific scaling on Windows.
23+
* <p>
24+
* There are two general options how to programmatically create an image:
25+
* <ul>
26+
* <li>{@link ImageGcDrawer}: create an image with an {@link ImageGcDrawer};
27+
* preferred way as the drawer will be called with the requested zoom when
28+
* needed
29+
* <li>{@link GC} on image: create an image with fixed dimensions and create a
30+
* {@link GC} for the image to drawn on; this is the legacy way of drawing an
31+
* image and should only be used if the whole drawing logic cannot be wrapped
32+
* into an {@link ImageGcDrawer} but the {@link GC} may be passed around to
33+
* collect drawing contributions from different places
34+
* </ul>
35+
* When using the second approach creating a {@link GC} on top of an image, it
36+
* is important to not dispose the GC before using the image, as in that case
37+
* the Windows implementation of an image can request its regeneration at the
38+
* desired zoom from the GC. If the GC is disposed before the image is used at
39+
* desired zoom, it may need to blurry-scale any existing drawing result to the
40+
* requested zoom instead of sharply rendering it at that zoom.
41+
* <p>
42+
* This snippet demonstrates both proper usages of the above mentioned options
43+
* as well as a usage that disposes the GC before consuming the image at the
44+
* desired zoom, leading to a blurry result. To see such a bad result, the
45+
* snippet needs to be executed on Windows and has to be moved between monitors
46+
* with different monitor zooms.
47+
* <p>
48+
* For a list of all SWT example snippets see
49+
* http://www.eclipse.org/swt/snippets/
50+
* </p>
51+
*/
52+
public class Snippet387 {
53+
54+
private static final int PADDING = 5;
55+
private static final int IMAGE_WIDTH = 270;
56+
private static final int IMAGE_HEIGHT = 50;
57+
58+
public static void main(String[] args) {
59+
activateMonitorSpecificScaling();
60+
61+
Display display = new Display();
62+
Shell shell = new Shell(display);
63+
shell.setText("Programmatic Images");
64+
shell.setSize(IMAGE_WIDTH + 2 * PADDING + 20, 3 * IMAGE_HEIGHT + 4 * PADDING + 40);
65+
66+
Image staticImage = createStaticImage(display, "Static Image with disposed GC", true);
67+
Image staticImageUndisposedGC = createStaticImage(display, "Static Image with non-disposed GC", false);
68+
Image dynamicImage = createDynamicImage(display, "Dynamic Image");
69+
70+
shell.addPaintListener(event -> {
71+
GC gc = event.gc;
72+
gc.drawImage(staticImage, PADDING, PADDING);
73+
gc.drawImage(staticImageUndisposedGC, PADDING, 2 * PADDING + IMAGE_HEIGHT);
74+
gc.drawImage(dynamicImage, PADDING, 3 * PADDING + 2 * IMAGE_HEIGHT);
75+
});
76+
77+
shell.open();
78+
while (!shell.isDisposed()) {
79+
if (!display.readAndDispatch()) {
80+
display.sleep();
81+
}
82+
}
83+
display.dispose();
84+
}
85+
86+
private static void activateMonitorSpecificScaling() {
87+
System.setProperty("swt.autoScale.updateOnRuntime", "true");
88+
}
89+
90+
private static Image createStaticImage(Display display, String text, boolean disposeGC) {
91+
Image staticImage = new Image(display, IMAGE_WIDTH, IMAGE_HEIGHT);
92+
GC imageGC = new GC(staticImage);
93+
try {
94+
drawImageContent(imageGC, text, IMAGE_WIDTH, IMAGE_HEIGHT);
95+
} finally {
96+
if (disposeGC) {
97+
imageGC.dispose();
98+
}
99+
}
100+
return staticImage;
101+
}
102+
103+
private static Image createDynamicImage(Display display, String text) {
104+
return new Image(display, (gc, w, h) -> drawImageContent(gc, text, w, h), IMAGE_WIDTH, IMAGE_HEIGHT);
105+
}
106+
107+
private static void drawImageContent(GC gc, String text, int width, int height) {
108+
gc.drawRectangle(0, 0, width - 1, height - 1);
109+
gc.drawText(text, PADDING, PADDING);
110+
}
111+
112+
}

0 commit comments

Comments
 (0)