Skip to content

Commit

Permalink
Wpf/WinForms: Fix adding transparent images to the clipboard
Browse files Browse the repository at this point in the history
Ignore Thumbs.db files
  • Loading branch information
cwensley committed Oct 26, 2016
1 parent 326fb9d commit b6028e4
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Source/Components
AppPackages
packages/
.vs/
[Tt]humbs.db
3 changes: 3 additions & 0 deletions Source/Eto.WinForms/Eto.WinForms - net45.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
<Compile Include="..\Eto.Wpf\CustomControls\HttpServer.cs">
<Link>CustomControls\HttpServer.cs</Link>
</Compile>
<Compile Include="..\Eto.Wpf\Win32.dib.cs">
<Link>Win32.dib.cs</Link>
</Compile>
<Compile Include="..\Shared\Conversions.cs">
<Link>Conversions.cs</Link>
</Compile>
Expand Down
3 changes: 3 additions & 0 deletions Source/Eto.WinForms/Eto.WinForms.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
<Compile Include="..\Eto.Wpf\CustomControls\HttpServer.cs">
<Link>CustomControls\HttpServer.cs</Link>
</Compile>
<Compile Include="..\Eto.Wpf\Win32.dib.cs">
<Link>Win32.dib.cs</Link>
</Compile>
<Compile Include="..\Shared\Conversions.cs">
<Link>Conversions.cs</Link>
</Compile>
Expand Down
12 changes: 6 additions & 6 deletions Source/Eto.WinForms/Forms/ClipboardHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ public Image Image
{
set
{
var sdimage = value.ControlObject as sd.Image;
if (sdimage != null)
{
Control.SetImage(sdimage);
Update();
}
var dib = (value as Bitmap)?.ToDIB();
if (dib != null)
Control.SetData(swf.DataFormats.Dib, dib);
else
Control.SetImage(value.ToSD());
Update();
}
get
{
Expand Down
1 change: 1 addition & 0 deletions Source/Eto.Wpf/Eto.Wpf - net45.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<Compile Include="Forms\Cells\CustomCellHandler.cs" />
<Compile Include="Forms\Menu\MenuHandler.cs" />
<Compile Include="Forms\PerMonitorDpiHelper.cs" />
<Compile Include="Win32.dib.cs" />
<Compile Include="WpfConversions.cs" />
<Compile Include="CustomControls\EditableTextBlock.cs" />
<Compile Include="CustomControls\FontDialog\fontchooser.xaml.cs">
Expand Down
1 change: 1 addition & 0 deletions Source/Eto.Wpf/Eto.Wpf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@
<DependentUpon>FontDialogResources.resx</DependentUpon>
</Compile>
<Compile Include="PropertyPathHelper.cs" />
<Compile Include="Win32.dib.cs" />
<Compile Include="WpfConversions.cs" />
<Compile Include="WpfExtensions.cs" />
<Compile Include="Drawing\TransformStack.cs" />
Expand Down
17 changes: 16 additions & 1 deletion Source/Eto.Wpf/Forms/ClipboardHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
using Eto.Wpf.Drawing;
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using sw = System.Windows;
using swm = System.Windows.Media;
using swmi = System.Windows.Media.Imaging;

namespace Eto.Wpf.Forms
{
Expand Down Expand Up @@ -78,7 +82,18 @@ public string Html
public Image Image
{
get { return sw.Clipboard.ContainsImage() ? new Bitmap(new BitmapHandler(sw.Clipboard.GetImage())) : null; }
set { sw.Clipboard.SetImage(value.ToWpf()); }
set
{
var dib = (value as Bitmap).ToDIB();
if (dib != null)
{
// write a DIB here, so we can preserve transparency of the image
sw.Clipboard.SetData(sw.DataFormats.Dib, dib);
return;
}

sw.Clipboard.SetImage(value.ToWpf());
}
}

public void Clear()
Expand Down
103 changes: 103 additions & 0 deletions Source/Eto.Wpf/Win32.dib.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System;
using System.IO;
using Eto.Drawing;

namespace Eto
{
partial class Win32
{
public static Bitmap FromDIB(MemoryStream ms)
{
var header = new byte[40];
ms.Read(header, 0, header.Length);
var size = BitConverter.ToInt32(header, 0);
var width = BitConverter.ToInt32(header, 4);
var height = BitConverter.ToInt32(header, 8);
var bpp = BitConverter.ToInt16(header, 14);
var compression = BitConverter.ToInt32(header, 16);
if (size > header.Length)
ms.Seek(size - header.Length, SeekOrigin.Current);

if (bpp != 32)
return null;
if (compression == 3) // BI_BITFIELDS
{
// three dwords, each specifies the bits each RGB components takes
// we require each takes one byte
var segments = new byte[sizeof(int) * 3];
ms.Read(segments, 0, segments.Length);
var rcomp = BitConverter.ToInt32(segments, 0);
var gcomp = BitConverter.ToInt32(segments, 4);
var bcomp = BitConverter.ToInt32(segments, 8);
if (rcomp != 0xFF0000 || gcomp != 0xFF00 || bcomp != 0xFF)
return null;
}
else if (compression != 0) // BI_RGB
return null;

var bmp = new Bitmap(width, height, PixelFormat.Format32bppRgba);
using (var bd = bmp.Lock())
{
for (int y = height - 1; y >= 0; y--)
for (int x = 0; x < width; x++)
{
var b = ms.ReadByte();
var g = ms.ReadByte();
var r = ms.ReadByte();
var a = ms.ReadByte();
var af = a / 255f;
if (af > 0)
bd.SetPixel(x, y, new Color(r / af, g / af, b / af, af));
}
}
return bmp;
}

static void Write(Stream stream, byte[] val) => stream.Write(val, 0, val.Length);

public static MemoryStream ToDIB(this Bitmap bitmap, int dpi = 96)
{
using (var bd = bitmap.Lock())
{
if (bd.BytesPerPixel == 4 || bd.BytesPerPixel == 3) // only 32bpp or 24bpp supported
{
var ms = new MemoryStream(bitmap.Width * bitmap.Height * bd.BytesPerPixel + 40);
// write BITMAPINFOHEADER
const float InchesPerMeter = 39.37f;
var pelsPerMeter = Math.Round(dpi * InchesPerMeter); // convert dpi to ppm
Write(ms, BitConverter.GetBytes((uint)40)); // biSize
Write(ms, BitConverter.GetBytes((uint)bitmap.Width)); // biWidth
Write(ms, BitConverter.GetBytes((uint)bitmap.Height));// biHeight
Write(ms, BitConverter.GetBytes((ushort)1)); // biPlanes
Write(ms, BitConverter.GetBytes((ushort)bd.BitsPerPixel)); // biBitCount
Write(ms, BitConverter.GetBytes((uint)0)); // biCompression (BI_RGB, uncompressed)
Write(ms, BitConverter.GetBytes((uint)0)); // biSizeImage
Write(ms, BitConverter.GetBytes((uint)pelsPerMeter)); // biXPelsPerMeter
Write(ms, BitConverter.GetBytes((uint)pelsPerMeter)); // biYPelsPerMeter
Write(ms, BitConverter.GetBytes((uint)0)); // biClrUsed
Write(ms, BitConverter.GetBytes((uint)0)); // biClrImportant

var hasAlpha = bd.BytesPerPixel == 4;
// write RGB data, dibs are flipped vertically
for (int y = bitmap.Height - 1; y >= 0; y--)
{
for (int x = 0; x < bitmap.Width; x++)
{
var p = bd.GetPixel(x, y);
// need to write RGB premultiplied by alpha (and round up)
ms.WriteByte((byte)(p.B * p.A * 255f + .5f));
ms.WriteByte((byte)(p.G * p.A * 255f + .5f));
ms.WriteByte((byte)(p.R * p.A * 255f + .5f));
if (hasAlpha)
ms.WriteByte((byte)p.Ab);
}
}

ms.Position = 0;
return ms;
}
}
return null;
}
}
}

0 comments on commit b6028e4

Please sign in to comment.