From c57c55d87ba6fca492fc876c1be3bc3d6cb9a353 Mon Sep 17 00:00:00 2001 From: Andreas Koch Date: Mon, 28 Apr 2025 14:34:05 +0200 Subject: [PATCH 1/2] Extend ImageGcDrawer to support transparency This commit extends the usage of ImageGcDraware to support SWT.Transparency as style that will initialize each GC with a proper transparent bitmap. --- .../cocoa/org/eclipse/swt/graphics/Image.java | 12 ++++- .../gtk/org/eclipse/swt/graphics/Image.java | 31 ++++++++--- .../win32/org/eclipse/swt/graphics/Image.java | 40 ++++++++++++--- .../org/eclipse/swt/snippets/Snippet367.java | 22 ++++++-- .../org/eclipse/swt/snippets/Snippet382.java | 51 +++++++++++++------ 5 files changed, 121 insertions(+), 35 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 7d0ff95942d..3770107184a 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 @@ -903,8 +903,16 @@ public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) } private ImageData drawWithImageGcDrawer(ImageGcDrawer imageGcDrawer, int width, int height, int zoom) { - Image image = new Image(device, width, height); - GC gc = new GC(image); + int gcStyle = imageGcDrawer.getGcStyle(); + Image image; + if ((gcStyle & SWT.TRANSPARENT) != 0) { + final ImageData resultData = new ImageData (width, height, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); + resultData.alphaData = new byte [width * height]; + image = new Image(device, resultData); + } else { + image = new Image(device, width, height); + } + GC gc = new GC(image, gcStyle); try { imageGcDrawer.drawOn(gc, width, height); ImageData imageData = image.getImageData(zoom); 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 c73e4dfe873..841810fc2f1 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 @@ -437,11 +437,14 @@ public Image(Device device, Rectangle bounds) { * @see #dispose() */ public Image(Device device, ImageData data) { + this(device, DPIUtil.autoScaleUp(device, data), DPIUtil.getDeviceZoom()); +} + +private Image(Device device, ImageData data, int zoom) { super(device); if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - currentDeviceZoom = DPIUtil.getDeviceZoom(); - data = DPIUtil.autoScaleUp (device, data); - init(data); + currentDeviceZoom = zoom; + init(data, zoom); init(); } @@ -695,9 +698,9 @@ public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) SWT.error(SWT.ERROR_NULL_ARGUMENT); } this.imageGcDrawer = imageGcDrawer; - currentDeviceZoom = DPIUtil.getDeviceZoom(); + currentDeviceZoom = 100; ImageData imageData = drawWithImageGcDrawer(width, height, currentDeviceZoom); - init (imageData); + init (imageData, currentDeviceZoom); init (); } @@ -1162,8 +1165,16 @@ public ImageData getImageData (int zoom) { } private ImageData drawWithImageGcDrawer(int width, int height, int zoom) { - Image image = new Image(device, width, height); - GC gc = new GC(image); + int gcStyle = imageGcDrawer.getGcStyle(); + Image image; + if ((gcStyle & SWT.TRANSPARENT) != 0) { + final ImageData resultData = new ImageData(width, height, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); + resultData.alphaData = new byte [width * height]; + image = new Image(device, resultData, zoom); + } else { + image = new Image(device, width, height); + } + GC gc = new GC(image, gcStyle); try { imageGcDrawer.drawOn(gc, width, height); ImageData imageData = image.getImageData(zoom); @@ -1274,6 +1285,10 @@ void init(int width, int height) { } void init(ImageData image) { + init(image, DPIUtil.getDeviceZoom()); +} + +void init(ImageData image, int zoom) { if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); PaletteData palette = image.palette; @@ -1286,7 +1301,7 @@ void init(ImageData image) { int imageDataHeight = image.height; // Scale dimensions of Image object to 100% scale factor - double scaleFactor = DPIUtil.getDeviceZoom() / 100f; + double scaleFactor = zoom / 100f; this.width = (int) Math.round(imageDataWidth / scaleFactor); this.height = (int) Math.round(imageDataHeight / scaleFactor); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index 4c6b8532f16..7145035c6da 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -380,6 +380,15 @@ public Image(Device device, ImageData data) { this.device.registerResourceWithZoomSupport(this); } +private Image(Device device, ImageData data, int zoom) { + super(device); + if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + initialNativeZoom = zoom; + this.imageProvider = new PlainImageDataProviderWrapper(data, zoom); + init(); + this.device.registerResourceWithZoomSupport(this); +} + /** * Constructs an instance of this class, whose type is * SWT.ICON, from the two given ImageData @@ -1956,27 +1965,34 @@ private ImageHandle initializeHandleFromSource(int zoom) { } private class PlainImageDataProviderWrapper extends ImageFromImageDataProviderWrapper { - private ImageData imageDataAt100; + private ImageData imageDataAtBaseZoom; + private int baseZoom; PlainImageDataProviderWrapper(ImageData imageData) { - this.imageDataAt100 = (ImageData) imageData.clone(); + this(imageData, 100); + } + + PlainImageDataProviderWrapper(ImageData imageData, int zoom) { + this.imageDataAtBaseZoom = (ImageData) imageData.clone(); + this.baseZoom = zoom; initImage(); } @Override protected Rectangle getBounds(int zoom) { - Rectangle rectangle = new Rectangle(0, 0, imageDataAt100.width, imageDataAt100.height); + Rectangle rectangle = new Rectangle(0, 0, imageDataAtBaseZoom.width, imageDataAtBaseZoom.height); + rectangle = DPIUtil.scaleDown(rectangle, baseZoom); return DPIUtil.scaleUp(rectangle, zoom); } @Override protected ElementAtZoom loadImageData(int zoom) { - return new ElementAtZoom<>(imageDataAt100, 100); + return new ElementAtZoom<>(imageDataAtBaseZoom, baseZoom); } @Override AbstractImageProviderWrapper createCopy(Image image) { - return image.new PlainImageDataProviderWrapper(this.imageDataAt100); + return image.new PlainImageDataProviderWrapper(this.imageDataAtBaseZoom); } } @@ -2478,8 +2494,18 @@ ImageData newImageData(int zoom) { @Override protected ImageHandle newImageHandle(int zoom) { initialNativeZoom = zoom; - Image image = new Image(device, width, height, zoom); - GC gc = new GC(image, drawer.getGcStyle()); + int gcStyle = drawer.getGcStyle(); + Image image; + if ((gcStyle & SWT.TRANSPARENT) != 0) { + int scaledHeight = DPIUtil.scaleUp(height, zoom); + int scaledWidth = DPIUtil.scaleUp(width, zoom); + final ImageData resultData = new ImageData (scaledWidth, scaledHeight, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); + resultData.alphaData = new byte [scaledWidth * scaledHeight]; + image = new Image(device, resultData, zoom); + } else { + image = new Image(device, width, height, zoom); + } + GC gc = new GC(image, gcStyle); try { gc.data.nativeZoom = zoom; drawer.drawOn(gc, width, height); diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java index fc5b6aee5b5..54b53dc1d39 100644 --- a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java +++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java @@ -36,6 +36,8 @@ public class Snippet367 { private static final String IMAGE_PATH_200 = IMAGES_ROOT + IMAGE_200; public static void main (String [] args) { + final Display display = new Display (); + final ImageFileNameProvider filenameProvider = zoom -> { switch (zoom) { case 100: @@ -65,7 +67,17 @@ public static void main (String [] args) { gc.drawLine(3, 3, width - 3, height - 3); }; - final Display display = new Display (); + Image imageWithDataProvider = new Image (display, imageDataProvider); + final ImageGcDrawer transparentImageGcDrawer = new ImageGcDrawer() { + @Override + public void drawOn(GC gc, int width, int height) { + gc.drawImage(imageWithDataProvider, 0, 0); + } + @Override + public int getGcStyle() { + return SWT.TRANSPARENT; + } + }; final Shell shell = new Shell (display); shell.setText("Snippet367"); shell.setLayout (new GridLayout (3, false)); @@ -99,13 +111,17 @@ public static void main (String [] args) { new Button(shell, SWT.NONE).setImage (new Image (display, filenameProvider)); new Label (shell, SWT.NONE).setText ("ImageDataProvider:"); - new Label (shell, SWT.NONE).setImage (new Image (display, imageDataProvider)); - new Button(shell, SWT.NONE).setImage (new Image (display, imageDataProvider)); + new Label (shell, SWT.NONE).setImage (imageWithDataProvider); + new Button(shell, SWT.NONE).setImage (imageWithDataProvider); new Label (shell, SWT.NONE).setText ("ImageGcDrawer:"); new Label (shell, SWT.NONE).setImage (new Image (display, imageGcDrawer, 20, 20)); new Button(shell, SWT.NONE).setImage (new Image (display, imageGcDrawer, 20, 20)); + new Label (shell, SWT.NONE).setText ("Transparent ImageGcDrawer:"); + new Label (shell, SWT.NONE).setImage (new Image (display, transparentImageGcDrawer, 20, 20)); + new Button(shell, SWT.NONE).setImage (new Image (display, transparentImageGcDrawer, 20, 20)); + createSeparator(shell); new Label (shell, SWT.NONE).setText ("1. Canvas\n(PaintListener)"); diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java index 821cfcec277..bb639b08287 100644 --- a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java +++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java @@ -64,6 +64,18 @@ public static void main (String [] args) { final Display display = new Display (); + final Image imageWithFileNameProvider = new Image (display, filenameProvider); + final Image disabledImageWithFileNameProvider = new Image (display,imageWithFileNameProvider, SWT.IMAGE_DISABLE); + final Image greyImageWithFileNameProvider = new Image (display,imageWithFileNameProvider, SWT.IMAGE_GRAY); + + final Image imageWithDataProvider = new Image (display, imageDataProvider); + final Image disabledImageWithDataProvider = new Image (display,imageWithDataProvider, SWT.IMAGE_DISABLE); + final Image greyImageWithDataProvider = new Image (display,imageWithDataProvider, SWT.IMAGE_GRAY); + + final Image imageWithData = new Image (display, IMAGE_PATH_100); + final Image disabledImageWithData = new Image (display,imageWithData, SWT.IMAGE_DISABLE); + final Image greyImageWithData = new Image (display,imageWithData, SWT.IMAGE_GRAY); + final ImageGcDrawer imageGcDrawer = (gc, width, height) -> { gc.setBackground(display.getSystemColor(SWT.COLOR_RED)); gc.fillRectangle(0, 0, width, height); @@ -71,6 +83,25 @@ public static void main (String [] args) { gc.drawRectangle(4, 4, width - 8, height - 8); }; + final Image imageWithGcDrawer = new Image (display, imageGcDrawer, 16, 16); + final Image disabledImageWithGcDrawer = new Image (display, imageWithGcDrawer, SWT.IMAGE_DISABLE); + final Image greyImageWithGcDrawer = new Image (display, imageWithGcDrawer, SWT.IMAGE_GRAY); + + final ImageGcDrawer transparentImageGcDrawer = new ImageGcDrawer() { + @Override + public void drawOn(GC gc, int width, int height) { + gc.drawImage(imageWithDataProvider, 0, 0); + } + @Override + public int getGcStyle() { + return SWT.TRANSPARENT; + } + }; + + final Image imageWithTransparentGcDrawer = new Image (display, transparentImageGcDrawer, 16, 16); + final Image disabledImageWithTransparentGcDrawer = new Image (display, imageWithTransparentGcDrawer, SWT.IMAGE_DISABLE); + final Image greyImageWithTransparentGcDrawer = new Image (display, imageWithTransparentGcDrawer, SWT.IMAGE_GRAY); + final Shell shell = new Shell (display); shell.setText("Snippet382"); shell.setLayout (new GridLayout (3, false)); @@ -80,21 +111,7 @@ public void handleEvent(Event e) { if (e.type == SWT.Paint) { GC mainGC = e.gc; GCData gcData = mainGC.getGCData(); - final Image imageWithFileNameProvider = new Image (display, filenameProvider); - final Image disabledImageWithFileNameProvider = new Image (display,imageWithFileNameProvider, SWT.IMAGE_DISABLE); - final Image greyImageWithFileNameProvider = new Image (display,imageWithFileNameProvider, SWT.IMAGE_GRAY); - final Image imageWithDataProvider = new Image (display, imageDataProvider); - final Image disabledImageWithDataProvider = new Image (display,imageWithDataProvider, SWT.IMAGE_DISABLE); - final Image greyImageWithDataProvider = new Image (display,imageWithDataProvider, SWT.IMAGE_GRAY); - - final Image imageWithData = new Image (display, IMAGE_PATH_100); - final Image disabledImageWithData = new Image (display,imageWithData, SWT.IMAGE_DISABLE); - final Image greyImageWithData = new Image (display,imageWithData, SWT.IMAGE_GRAY); - - final Image imageWithGcDrawer = new Image (display, imageGcDrawer, 16, 16); - final Image disabledImageWithGcDrawer = new Image (display, imageWithGcDrawer, SWT.IMAGE_DISABLE); - final Image greyImageWithGcDrawer = new Image (display, imageWithGcDrawer, SWT.IMAGE_GRAY); try { drawImages(mainGC, gcData, "Normal",40, imageWithFileNameProvider); @@ -112,6 +129,10 @@ public void handleEvent(Event e) { drawImages(mainGC, gcData, "Normal", 400, imageWithGcDrawer); drawImages(mainGC, gcData, "Disabled", 440, disabledImageWithGcDrawer); drawImages(mainGC, gcData, "Greyed", 480, greyImageWithGcDrawer); + + drawImages(mainGC, gcData, "Normal", 520, imageWithTransparentGcDrawer); + drawImages(mainGC, gcData, "Disabled", 560, disabledImageWithTransparentGcDrawer); + drawImages(mainGC, gcData, "Greyed", 600, greyImageWithTransparentGcDrawer); } finally { mainGC.dispose (); } @@ -130,7 +151,7 @@ private void drawImages(GC mainGC, GCData gcData, String text, int y, final Imag }; shell.addListener(SWT.Paint, l); - shell.setSize(400, 550); + shell.setSize(400, 750); shell.open (); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); From 6b1f43602dc01b705c1112f3dddc1f53baf35544 Mon Sep 17 00:00:00 2001 From: Andreas Koch Date: Mon, 28 Apr 2025 15:46:17 +0200 Subject: [PATCH 2/2] Use ImageGcDrawer for smooth scaling of ImageData This commit adapts the smooth scaling implementation to use ImageGcDrawer. --- .../cocoa/org/eclipse/swt/graphics/Image.java | 1 + .../org/eclipse/swt/internal/DPIUtil.java | 23 +++++++++++-------- .../gtk/org/eclipse/swt/graphics/Image.java | 3 ++- .../win32/org/eclipse/swt/graphics/Image.java | 3 ++- 4 files changed, 19 insertions(+), 11 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 3770107184a..8040df584bf 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 @@ -906,6 +906,7 @@ private ImageData drawWithImageGcDrawer(ImageGcDrawer imageGcDrawer, int width, int gcStyle = imageGcDrawer.getGcStyle(); Image image; if ((gcStyle & SWT.TRANSPARENT) != 0) { + /* Create a 24 bit image data with alpha channel */ final ImageData resultData = new ImageData (width, height, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); resultData.alphaData = new byte [width * height]; image = new Image(device, resultData); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java index 10a60eb0048..7b197fa6e3f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java @@ -306,16 +306,21 @@ private static ImageData autoScaleImageData (Device device, final ImageData imag boolean useSmoothScaling = isSmoothScalingEnabled() && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK; if (useSmoothScaling) { Image original = new Image (device, (ImageDataProvider) zoom -> imageData); - /* Create a 24 bit image data with alpha channel */ - final ImageData resultData = new ImageData (scaledWidth, scaledHeight, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); - resultData.alphaData = new byte [scaledWidth * scaledHeight]; - Image resultImage = new Image (device, (ImageDataProvider) zoom -> resultData); - GC gc = new GC (resultImage); - gc.setAntialias (SWT.ON); - Image.drawScaled(gc, original, width, height, scaleFactor); - gc.dispose (); + ImageGcDrawer drawer = new ImageGcDrawer() { + @Override + public void drawOn(GC gc, int imageWidth, int imageHeight) { + gc.setAntialias (SWT.ON); + Image.drawScaled(gc, original, width, height, scaleFactor); + }; + + @Override + public int getGcStyle() { + return SWT.TRANSPARENT; + } + }; + Image resultImage = new Image (device, drawer, scaledWidth, scaledHeight); + ImageData result = resultImage.getImageData (100); original.dispose (); - ImageData result = resultImage.getImageData (getDeviceZoom ()); resultImage.dispose (); return result; } else { 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 841810fc2f1..f174e431738 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 @@ -1168,6 +1168,7 @@ private ImageData drawWithImageGcDrawer(int width, int height, int zoom) { int gcStyle = imageGcDrawer.getGcStyle(); Image image; if ((gcStyle & SWT.TRANSPARENT) != 0) { + /* Create a 24 bit image data with alpha channel */ final ImageData resultData = new ImageData(width, height, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); resultData.alphaData = new byte [width * height]; image = new Image(device, resultData, zoom); @@ -1288,7 +1289,7 @@ void init(ImageData image) { init(image, DPIUtil.getDeviceZoom()); } -void init(ImageData image, int zoom) { +private void init(ImageData image, int zoom) { if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); PaletteData palette = image.palette; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index 7145035c6da..f2b96c560b1 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -1972,7 +1972,7 @@ private class PlainImageDataProviderWrapper extends ImageFromImageDataProviderWr this(imageData, 100); } - PlainImageDataProviderWrapper(ImageData imageData, int zoom) { + private PlainImageDataProviderWrapper(ImageData imageData, int zoom) { this.imageDataAtBaseZoom = (ImageData) imageData.clone(); this.baseZoom = zoom; initImage(); @@ -2499,6 +2499,7 @@ protected ImageHandle newImageHandle(int zoom) { if ((gcStyle & SWT.TRANSPARENT) != 0) { int scaledHeight = DPIUtil.scaleUp(height, zoom); int scaledWidth = DPIUtil.scaleUp(width, zoom); + /* Create a 24 bit image data with alpha channel */ final ImageData resultData = new ImageData (scaledWidth, scaledHeight, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); resultData.alphaData = new byte [scaledWidth * scaledHeight]; image = new Image(device, resultData, zoom);