Skip to content

Conversation

@emmauss
Copy link
Contributor

@emmauss emmauss commented Dec 3, 2025

What does the pull request do?

Adds more image format when bitmaps are exported to clipboard, namely the png and native bitmap(CF_BITMAP) formats, on Windows.
Due to some cleanup, jpeg format is removed from the input preferred formats, i.e. formats we read from the clipboard. This support may be added back later.

What is the current behavior?

We currently export bitmaps using the CF_DIB format. Some apps may not support this format, and thus can't read our bitmaps.
With this PR, our bitmaps are exported in the following formats: image/png, PNG, CF_DIB, CF_BITMAP, in that order.

What is the updated/expected behavior with this PR?

How was the solution implemented (if it's not obvious)?

Checklist

Breaking changes

Obsoletions / Deprecations

Fixed issues

Fixes #20183

using var stream = new MemoryStream();
bitmap.Save(stream);

return WriteBytesToHGlobal(ref hGlobal, stream.ToArray().AsSpan());
Copy link
Contributor

@miloush miloush Dec 3, 2025

Choose a reason for hiding this comment

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

we could probably do here without a copy, there is MemoryStream.GetBuffer(), but it might be larger than you need, so you need to use Length

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thats probably over-optimization. We are rarely copying images that often to have issues with memory copies. Best to be stable in this case.

biPlanes = 1,
biBitCount = (ushort)(bitmap.Format?.BitsPerPixel ?? 0),
biCompression = 0,
biSizeImage = (uint)(pixelSize.Width * 4 * Math.Abs(pixelSize.Height))
Copy link
Contributor

@miloush miloush Dec 3, 2025

Choose a reason for hiding this comment

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

You are assuming pixel is 4 bytes here but use any BitsPerPixel value you get from the bitmap. These should be made to match (and match the reality). Some of the formats, and especially the ones with transparency cannot be supported using BITMAPINFOHEADER, you need V5 header. The main benefit of using HBITMAP is that it can support more pixel formats than CF_DIB.

public static extern int SetDIBits(IntPtr hdc, IntPtr hbm, uint start, uint cLines, IntPtr lpBits, [In] ref BITMAPINFO lpbmi, uint fuColorUse);

[DllImport("gdi32.dll")]
public static extern int SetDIBits(IntPtr hdc, IntPtr hbm, uint start, uint cLines, IntPtr lpBits, [In] ref BITMAPINFOHEADER lpbmi, uint fuColorUse);
Copy link
Contributor

@miloush miloush Dec 3, 2025

Choose a reason for hiding this comment

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

instead of [In] ref you can just do in (and pass it without a qualifier at callsite)

or ClipboardFormatRegistry.BitmapFormat
or ClipboardFormatRegistry.PngFormatMimeType
or ClipboardFormatRegistry.JpegFormatMimeType)
or ClipboardFormatRegistry.PngFormatMimeType)
Copy link
Contributor

Choose a reason for hiding this comment

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

"PNG"?

private static readonly List<(DataFormat Format, ushort Id)> s_formats = [];

public static DataFormat PngSystemDataFormat = DataFormat.FromSystemName<Bitmap>("PNG" , AppPrefix);
public static DataFormat PngDataFormat = DataFormat.FromSystemName<Bitmap>(PngFormatMimeType , AppPrefix);
Copy link
Contributor

@miloush miloush Dec 3, 2025

Choose a reason for hiding this comment

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

The names are not too helpful, would prefer PngDataFormat for PNG and PngMimeDataFormat for image/png.

public const string DibFormat = "CF_DIB";
private static readonly List<(DataFormat Format, ushort Id)> s_formats = [];

public static DataFormat PngSystemDataFormat = DataFormat.FromSystemName<Bitmap>("PNG" , AppPrefix);
Copy link
Contributor

Choose a reason for hiding this comment

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

why is image/png format extracted into const and PNG not?

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0060587-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0060597-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

bitmap.CopyPixels(new PixelRect(pixelSize), (IntPtr)bytes, buffer.Length, stride);

var infoHeader = new BITMAPINFOHEADER()
if (!isV5)
Copy link
Contributor

Choose a reason for hiding this comment

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

it is not V5 you would need to ensure the bitmap is one of the supported formats

bV5Height = -pixelSize.Height,
bV5Planes = 1,
bV5BitCount = (ushort)bpp,
bV5Compression = BitmapCompressionMode.BI_BITFIELDS,
Copy link
Contributor

Choose a reason for hiding this comment

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

only valid for 16bpp and 32bpp, must be BI_RGB otherwise

Copy link
Contributor

@miloush miloush Dec 3, 2025

Choose a reason for hiding this comment

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

for 555 bitmaps, either provide filter or use BI_RGB

bV5GreenMask = GetGreenMask(bitmap),
bV5AlphaMask = GetAlphaMask(bitmap),
bV5CSType = BitmapColorSpace.LCS_sRGB,
bV5Intent = BitmapIntent.LCS_GM_BUSINESS,
Copy link
Contributor

Choose a reason for hiding this comment

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

why business here but colorimetric for dib?

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0060607-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0060611-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: Clipboard SetValueAsync(DataFormat.Bitmap, bmp) generates invalid CF_DIB, CF_BITMAP entries

4 participants