Skip to content

Conversation

ShahzaibIbrahim
Copy link
Contributor

@ShahzaibIbrahim ShahzaibIbrahim commented Oct 10, 2025

Description

Move Transparent Pixel Handling from Image to ImageHandle

Previously, the transparency pixel was managed at the Image level, which caused issues when an Image had multiple handles at different zoom levels or color models (e.g., indexed vs. direct/ARGB). For example, a GIF image at 100% zoom may use a transparency pixel, but when scaled, SWT converts it to a direct image with alpha data, making the transparency pixel concept invalid for the scaled handle.

This change moves the transparency pixel field from the Image class to the ImageHandle class. Now, each handle manages its own transparency information, allowing a single Image to have multiple handles, each with the correct transparency type (pixel or alpha) according to its color model. This ensures correct transparency handling for all handles, regardless of how they were created or scaled.

How to test

  1. Run the following snippet on 100% zoom monitor
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;


public class ButtonWithGifImage {
    public static void main(String[] args) {
    	System.setProperty("swt.autoScale.updateOnRuntime", "true");
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("SWT Button with GIF Image");
        shell.setSize(300, 200);

        Button button = new Button(shell, SWT.PUSH);
        button.setBounds(80, 60, 140, 60);
        button.setText("Click Me");

        Image image = new Image(display,
            ButtonWithGifImage.class.getResourceAsStream("sample.gif"));
        button.setImage(image);

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

        image.dispose();
        display.dispose();
    }
}

  1. Move the window to a 150% DPI monitor (causing scaling) — verify the image still renders correctly (no jagged/incorrect background).
  2. Move back to 100% — verify the image still renders correctly and no gray background appears.

Result

Here's the preview how it looked before and after this PR change. 100 -> 150 -> 100

Before:
image

After
image

Fixes: #2494

@merks
Copy link
Contributor

merks commented Oct 10, 2025

Yeah! 🥳

Copy link
Contributor

github-actions bot commented Oct 10, 2025

Test Results

  115 files  ±0    115 suites  ±0   9m 55s ⏱️ - 2m 27s
4 554 tests ±0  4 538 ✅ ±0  16 💤 ±0  0 ❌ ±0 
  311 runs  ±0    308 ✅ ±0   3 💤 ±0  0 ❌ ±0 

Results for commit df77fa7. ± Comparison against base commit 9cacd32.

♻️ This comment has been updated with latest results.

@ShahzaibIbrahim ShahzaibIbrahim marked this pull request as draft October 10, 2025 15:01
@ShahzaibIbrahim ShahzaibIbrahim force-pushed the master-442 branch 2 times, most recently from 4340fa2 to 08fa953 Compare October 15, 2025 13:51
@ShahzaibIbrahim ShahzaibIbrahim marked this pull request as ready for review October 15, 2025 14:07
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

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

As we already discussed, moving transparentPixel/transparentColor to the individual handle makes sense. However, there now seem to be some flaws on how to retrieve the transparentPixel at Image level, where arbitrary handles or image data are used for that. Would it maybe make sense to additionally store whether the image was (originally) based on a transparent pixel to have this information available at image level, no matter whether some rescaling operation produced other handles that do not use the transparent pixel anymore? Or maybe store a reference to the according image handle, such that getBackgroundColor() can use the correct handle that is based on the transparent color?

Previously, the transparency pixel was managed at the Image level, which
caused issues when an Image had multiple handles at different zoom
levels or color models (e.g., indexed vs. direct/ARGB). For example, a
GIF image at 100% zoom may use a transparency pixel, but when scaled,
SWT converts it to a direct image with alpha data, making the
transparency pixel concept invalid for the scaled handle.

This change moves the transparency pixel field from the Image class to
the ImageHandle class. Now, each handle manages its own transparency
information, allowing a single Image to have multiple handles, each with
the correct transparency type (pixel or alpha) according to its color
model. This ensures correct transparency handling for all handles,
regardless of how they were created or scaled.
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

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

I think that we agree that the transparentPixelbelongs to the handle and not to the image, so this is generally the right thing to do. @ShahzaibIbrahim can you please extract the preparatory refactoring to change the return type ofgetHandle()and use that one instead ofwin32_getHandle()` into a separate preparatory PR, such that this one becomes easier to review?
I left some additional comments regarding the functional changes in this PR.

OS.SelectObject(hdcDest, hOldDest);
OS.DeleteDC(hdcSource);
OS.DeleteDC(hdcDest);
imageMetadata.transparentPixel = imageHandle.transparentPixel;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not pass this to the constructor call to ImageHandle above?

*/
int transparentPixel = -1, transparentColor = -1;

public ImageHandle(long handle, int zoom) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't we remove this constructor to put the responsibility for thinking about whether a transparentPixel needs to be specified or not to the consumer? Otherwise we risk that we or someone unexperienced just calls this constructor without thinking about the transparent pixel, but would actually need to take into account that it must be set.

if (transparentPixel == -1) return;
transparentColor = -1;
backgroundColor = color.getRGB();
zoomLevelToImageHandle.values().forEach(imageHandle -> imageHandle.setBackground(backgroundColor));
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we completely remove this? In case there are already existing handles, shouldn't we ...

  • apply the color if possible?
  • print a warning that it cannot be applied if the existing handles are scaled versions (maybe encapsulated in a strict check to avoid performance impacts)?

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.

Eclipse 2025-06: UI rendering issues on Windows with monitors using different scale factors Gif images sometimes have black backgrounds

3 participants