Sample code: Noc.Demo.Clipboard.zip (163.36 KB)

I came across an interesting problem, the other day. The task at had was to copy an image to the Clipboard and maintain the alpha channel for pasting into applications such as Word, PowerPoint, Gimp, or Paint.NET.

What boggles my mind is: this is actually somewhat... well... hard.

Clipboard handling that the .NET Framework forgot

Don't get me wrong. Getting an image onto the clipboard is somewhat easy. It's a one-liner, really:

Clipboard.SetImage(myImage);

The problem with this approach is that the image loses its alpha channel, converting an image like this:

... to an image like this:

 

The resulting image is a 24-bit per pixel bitmap, with the transparent background filled by a soft gray. I have it on good report that older versions of windows swap out the transparent color for a virulent blue.

Now, I've seen applications cop out of transparency by using black or white, or even a gut wrenching magenta, for the intent of masking out the default color at run time. But gray? Why not try to be right some of the time instead of being wrong all of the time. Who ever really wants to swap out transparency for soft gray?

Covering up the gray with a little color

We all know someone who does it. Age creeps up and it's off to the salon for some dye.

When transparency is not strictly a requirement, a little bit of code can get us on the way to filling an image with a solid background. For this, I prefer the following extension method:

public static Image CreateOpaqueBitmap(this Image image, Color backgroundColor)
{
   
var bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
   
using (var graphics = Graphics.FromImage(bitmap))
   
{
        graphics
.Clear(backgroundColor);
        graphics
.DrawImage(image, 0, 0, image.Width, image.Height);
   
}

   
return bitmap;
}

With the extension method in hand, adding an opaque image to the clipboard was never easier:

using (var bitmap = image.CreateOpaqueBitmap(Color.Magenta))
{
   
Clipboard.Clear();
   
Clipboard.SetImage(bitmap);
}

But I really need transparency!

Creating opaque images really only massages an ache, but really doesn't solve the problem. What can be done about transparency?

A complete answer requires a little understanding of Windows clipboard formats. It helps to think of clipboard data as a set of key-value pairs. The key identifies what format the data is expected to be, and the value is the actual data. The clipboard can have multiple kinds of data, all representing (supposedly) the same thing, at any given time.

Some applications can take advantage of this fact to provide text data along with an image, so that pastes will provide something if pasting in a text editor, and something else if pasted in an image editor.

What is more often the case is that an application will provide multiple image formats to increase compatibility with other image software. As a matter of fact, Windows provides free type conversions between some of the most common image types (e.g. Bitmap to System.Drawing.Bitmap).

It helps to get a feel for what formats are supported for pasting in an application and their relative priority by inspecting what formats are generated when copying from the application. Here are formats generated when copying images from a few favorite applications:

  • GIMP: PNG, DeviceIndependentBitmap, System.Drawing.Bitmap, Bitmap, Format17
  • Paint.NET: System.Drawing.Bitmap, Bitmap, PaintDotNet.MaskedSurface
  • Fireworks: Fireworks Internal Clipboard Format 3.0, PNG, DeviceIndependentBitmap
  • MS Paint: Embed Source, Object Descriptor, MetaFilePict, DeviceIndependentBitmap
  • Print Screen (on the keyboard): System.Drawing.Bitmap, Bitmap, DeviceIndependentBitmap, Format17
  • PhotoScape: System.Drawing.Bitmap, Bitmap, DeviceIndependentBitmap, Format17
  • MS Word: Art::GVML ClipFormat, System.Drawing.Bitmap, Bitmap, PNG, JFIF, GIF, EnhancedMetafile, MetaFilePict, Object Descriptor
  • MS PowerPoint: Preferred DropEffect, InShellDragLoop, PowerPoint 12.0 Internal Shapes, Object Descriptor, Art::GVML ClipFormat, PNG, JFIF, GIF, System.Drawing.Bitmap, Bitmap, EnhancedMetafile, MetaFilePict, PowerPoint 12.0 Internal Theme, PowerPoint 12.0 Internal Color Scheme

Adding transparency with PNG.

It would seem that DeviceIndependentBitmap, Bitmap, and System.Drawing.Bitmap are the most common formats in the group; however, they are 24-bit opaque bitmaps. Generating a transparent clipboard data type requires that we properly encode data using a format that supports an alpha channel.

In the applications above, the PNG (Portable Network Graphics) format is generated by GIMP, Fireworks, Word, and PowerPoint. We can hope for transparency success in a broad array of applications merely by placing PNG-formatted data on the clipboard. Lucky for us, it doesn't take much to write:

using (var stream = new MemoryStream())
{
    image
.Save(stream, ImageFormat.Png);
   
var data = new DataObject("PNG", stream);

   
Clipboard.Clear();
   
Clipboard.SetDataObject(data, true);
}

Adding transparency with 32-bit ARGB bitmap

Not every application supports PNG formats. It is probably a good idea to have a secondary format at hand to deal with transparency. It is possible to get a 32bpp image into the clipboard with a little bit of work.

The format at hand, Format17 (a.k.a. CF_DIBV5)

I almost hate to bring it up, really, mostly because so many applications either mishandle it, or ignore it altogether. Take the print screen utility, for example. It does generate valid 32bpp Format17 content, but zeroes all the alpha bytes, and keeps a zero-ing byte mask for alpha just in case. In other words, it may be using a transparency-enabled format, but the content isn't transparent. GIMP mishandles the BITMAPV5HEADER, by accidentally omitting the bV5SizeImage field that is responsible for identifying how many bits are in the bitmap. (In fairness to GIMP, a clever application could compute the value based on other fields in the header.) Paint.NET appears to disregard formats other than 24bpp bitmaps and its own internal MaskedSurface format. Both PhotoScape and GIMP either disregard Format17 altogether (in favor of Bitmap formats) or mishandle the alpha, giving paste results like this:

So, with "You probably won't find this useful," as a disclaimer, let's see how it's done.

The first method is a utility method that copies a 32bpp image into global memory using interop and a little native marshalling. Basically, the method creates a bitmap header and marshals it out into memory, then adds the image bits, last row first, after the header. Note that all the interop methods and constants are omitted for brevity.

private static IntPtr CreatePackedDIBV5(this Bitmap bitmap)
{
   
BitmapData bmData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
   
uint bufferLen = (uint)(Marshal.SizeOf(typeof(BITMAPV5HEADER)) + bmData.Height * bmData.Stride);
   
IntPtr hMem = Kernel32.NativeMethods.GlobalAlloc(User32.GHND | User32.GMEM_DDESHARE, bufferLen);
   
IntPtr packedDIBV5 = Kernel32.NativeMethods.GlobalLock(hMem);

    BITMAPV5HEADER bmi
= (BITMAPV5HEADER)Marshal.PtrToStructure(packedDIBV5, typeof(BITMAPV5HEADER));
    bmi
.bV5Size = (uint)Marshal.SizeOf(typeof(BITMAPV5HEADER));
    bmi
.bV5Width = bmData.Width;
    bmi
.bV5Height = bmData.Height;
    bmi
.bV5Planes = 1;
    bmi
.bV5BitCount = 32;
    bmi
.bV5Compression = User32.BI_BITFIELDS;
    bmi
.bV5SizeImage = (uint)(bmData.Height * bmData.Stride);
    bmi
.bV5XPelsPerMeter = 0;
    bmi
.bV5YPelsPerMeter = 0;
    bmi
.bV5ClrUsed = 0;
    bmi
.bV5ClrImportant = 0;
    bmi
.bV5RedMask = 0x00FF0000;
    bmi
.bV5GreenMask = 0x0000FF00;
    bmi
.bV5BlueMask = 0x000000FF;
    bmi
.bV5AlphaMask = 0xFF000000;
    bmi
.bV5CSType = 0x73524742; // User32.LCS_WINDOWS_COLOR_SPACE;
    bmi
.bV5Endpoints.ciexyzBlue.ciexyzX = 0;
    bmi
.bV5Endpoints.ciexyzBlue.ciexyzY = 0;
    bmi
.bV5Endpoints.ciexyzBlue.ciexyzZ = 0;
    bmi
.bV5Endpoints.ciexyzGreen.ciexyzX = 0;
    bmi
.bV5Endpoints.ciexyzGreen.ciexyzY = 0;
    bmi
.bV5Endpoints.ciexyzGreen.ciexyzZ = 0;
    bmi
.bV5Endpoints.ciexyzRed.ciexyzX = 0;
    bmi
.bV5Endpoints.ciexyzRed.ciexyzY = 0;
    bmi
.bV5Endpoints.ciexyzRed.ciexyzZ = 0;
    bmi
.bV5GammaRed = 0;
    bmi
.bV5GammaGreen = 0;
    bmi
.bV5GammaBlue = 0;
    bmi
.bV5ProfileData = 0;
    bmi
.bV5ProfileSize = 0;
    bmi
.bV5Reserved = 0;
    bmi
.bV5Intent = User32.LCS_GM_IMAGES;
   
Marshal.StructureToPtr(bmi, packedDIBV5, false);

   
long offsetBits = bmi.bV5Size;
   
IntPtr bits = (IntPtr)(packedDIBV5.ToInt32() + offsetBits);
   
for (int y = 0; y < bmData.Height; y++)
   
{
       
IntPtr DstDib = (IntPtr)(bits.ToInt32() + (y * bmData.Stride));
       
IntPtr SrcDib = (IntPtr)(bmData.Scan0.ToInt32() + ((bmData.Height - 1 - y) * bmData.Stride));
       
for (int x = 0; x < bmData.Width; x++)
       
{
           
Marshal.WriteInt32(DstDib, Marshal.ReadInt32(SrcDib));
           
DstDib = (IntPtr)(DstDib.ToInt32() + 4);
           
SrcDib = (IntPtr)(SrcDib.ToInt32() + 4);
       
}
   
}

    bitmap
.UnlockBits(bmData);
   
Kernel32.NativeMethods.GlobalUnlock(hMem);
   
return hMem;
}

With the utility method at hand, adding an image to the clipboard using CF_DIBV5 (Format17) formatting is as easy as:

public static void Copy32BppBitmapToClipboard(this Image image)
{
   
using (var bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))
   
{
       
using (var bitmapGraphics = Graphics.FromImage(bitmap))
       
{
            bitmapGraphics
.DrawImage(image, 0, 0, image.Width, image.Height);
       
}

       
var packedDIBV5 = CreatePackedDIBV5(bitmap);
       
User32.NativeMethods.OpenClipboard(IntPtr.Zero);
       
User32.NativeMethods.EmptyClipboard();
       
User32.NativeMethods.SetClipboardData(User32.CF_DIBV5, packedDIBV5);
       
User32.NativeMethods.CloseClipboard();
   
}
}

Bringing it home

I consider the 32bpp CF_DIBV5 format to be a lot of work, considering the poor support of the format offered by so many applications. I've found that taking a pragmatic approach, aiming for PNG transparency where supported, and accepting the background color of my choice otherwise, made for a manageable codebase with decent application compatibility. I use the following extension method to add images to the clipboard:

public static void CopyMultiFormatBitmapToClipboard(this Image image)
{
   
using (var opaque = image.CreateOpaqueBitmap(Color.White))
   
using (var stream = new MemoryStream())
   
{
        image
.Save(stream, ImageFormat.Png);

       
Clipboard.Clear();
       
var data = new DataObject();
        data
.SetData(DataFormats.Bitmap, true, opaque);
        data
.SetData("PNG", true, stream);
       
Clipboard.SetDataObject(data, true);
   
}
}

The results are fairly decent. Here are a few of the applications I tried:

  • GIMP: transparency supported
  • Fireworks: transparency supported
  • PhotoScape: white background
  • Paint.NET: white background
  • MS PowerPoint: transparency supported
  • MS Word: white background
  • MS Paint: white background

Happy coding!


Noc.Demo.Clipboard.zip (163.36 KB)


 
Categories: C# | Extension Methods

Welcome to part 3 in the Powerful Extension Methods series. This article takes a look at a common class in ASP.NET, the System.Web.UI.WebControls.ListItemCollection. The ListItemCollection is used in many places: the ListBox, DropDownList, CheckBoxList, and RadioButtonList all store their items in this type of collection.

ListItemCollection implements IEnumerable, but not the strongly typed IEnumerable<ListItem>. Many collections throughout the base class libraries are that way. One of the disadvantages of implementing only IEnumerable is that when you want to process the collection using LINQ, you must first cast the collection to the desired type. Something like this:

items.Cast<ListItem>()

The Cast<TResult>() function gets called implicitly in LINQ expressions such as this:

var selectedItems = from ListItem item in items
                    where item.Selected
                    select item;

The query feels slightly less elegant when written using the LINQ methods directly.

var selectedItems = items.Cast<TResult>().Where(item => item.Selected);

Adding a quick extension method like the one below allows calls to the Where<TResult>() method without including the inelegant call to Cast<TResult>().

/// <summary>
/// Filters a <c>ListItemCollection</c> based on a predicate.
/// </summary>
/// <param name="items">The <c>ListItemCollection</c> to filter.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <returns>An enumerable set of list items filtered by the predicate.</returns>
public static IEnumerable<ListItem> Where(this ListItemCollection items, Func<ListItem, bool>
                                          predicate)
{
  return items.Cast<ListItem>().Where(predicate);
}

This allows the simpler call:

var selectedItems = items.Where(item => item.Selected);

The ASP.NET ListItemCollection does not ship with a SelectedItems or SelectedIndices property. We can elegantly compensate for the missing property with two short extension methods.

/// <summary>
/// Filters a <c>ListItemCollection</c> based on whether the item is selected.
/// </summary>
/// <param name="items">The <c>ListItemCollection</c> to filter.</param>
/// <returns>An enumerable set of list items filtered by whether the item is selected.</returns>
public static IEnumerable<ListItem> WhereSelected(this ListItemCollection items)
{
  return items.Cast<ListItem>().Where(i => i.Selected);
}

/// <summary>
/// Filters a <c>ListItemCollection</c> based on whether the item is not selected.
/// </summary>
/// <param name="items">The <c>ListItemCollection</c> to filter.</param>
/// <returns>An enumerable set of list items filtered by whether the item is not selected.</returns>
public static IEnumerable<ListItem> WhereNotSelected(this ListItemCollection items)
{
  return items.Cast<ListItem>().Where(i => !i.Selected);
}

Often times, it is not the list items themselves that we are interested in, but only their values. A few brief extension methods make for an elegant way to retrieve SelectedValues.

/// <summary>
/// Filters a <c>ListItemCollection</c> based on whether the item is selected, and retrieves each
value.
/// </summary>
/// <param name="items">The <c>ListItemCollection</c> to filter.</param>
/// <returns>An enumerable set of list items filtered by whether the item is selected.</returns>
public static IEnumerable<string> ValuesWhereSelected(this ListItemCollection items)
{
  return items.Cast<ListItem>().Where(i => i.Selected).Select(i => i.Value);
}

/// <summary>
/// Filters a <c>ListItemCollection</c> based on whether the item is not selected, and retrieves
each value.
/// </summary>
/// <param name="items">The <c>ListItemCollection</c> to filter.</param>
/// <returns>An enumerable set of list items filtered by whether the item is not selected.</returns>
public static IEnumerable<string> ValuesWhereNotSelected(this ListItemCollection items)
{
  return items.Cast<ListItem>().Where(i => !i.Selected).Select(i => i.Value);
}

Collecting selected values is helpful, but setting selected values is also helpful. The next two extension methods enable selecting multiple items provided a list of values or a Lambda expression predicate.

/// <summary>
/// Sets each element in the collection as selected based on whether the item is contained in the
set of values.
/// </summary>
/// <param name="items">The items to update.</param>
/// <param name="values">The values to select. All other items will be deselected.</param>
public static void SetAllSelectedByValue(this ListItemCollection items, IEnumerable<string> values)
{
  var hashValues = new HashSet<string>(values);
  if (values == null)
  {
    items.SetAllSelectedIf(i => false);
  }
  else
  {
    items.SetAllSelectedIf(i => hashValues.Contains(i.Value));
  }
}

/// <summary>
/// Sets each element in the collection as selected based on a predicate.
/// </summary>
/// <param name="items">The items to update.</param>
/// <param name="predicate">A function to test each element for a condition, and update the selected
                status of the element to the test result.</param>
public static void SetAllSelectedIf(this ListItemCollection items, Func<ListItem, bool> predicate)
{
  foreach (ListItem item in items)
  {
    item.Selected = predicate(item);
  }
}

These few extension methods don't perform any earth-shaking operations, but they do provide a clean, elegant way to operate on ListItemCollection objects.

Happy Coding!


 
Categories: ASP.NET | C# | Extension Methods

Welcome to part 2 of the Powerful Extension Methods series. Today, we take a look at XML serialization. If you have ever used the .NET XmlSerializer class, you know how powerful it is. Decorate your class with appropriate attributes, and you can generate or parse complex XML structures without having to write any XML parsing code.

To find out more about .NET and XML serialization, check out the documentation here. If you want to see excellent examples of the XmlSerializer in action, check out the code of DasBlog and look at what they do with RSS and Atom feeds. It's pretty neat.

It doesn't take long, working with the XmlSerializer, before the good ol' DRY principle drives us to create serialization helper classes, like Andrew Gunn created. Utility classes are usually perfect candidates for extension methods.

So here we go: one extension method for serializing any object (if it is not serializable, expect an exception), and a generic method each for deserializing streams, strings, and XmlNodes.

/// <summary>
/// This class provides extension methods related to serialization.
/// </summary>
public static class SerializationExtensions
{
  /// <summary>
  /// Serializes an object as XML.
  /// </summary>
  /// <param name="value">The object to serialize.</param>
  /// <returns>An XML string representing the serialized object.</returns>
  public static string SerializeAsXml(this object value)
  {
      var ser = new XmlSerializer(value.GetType());
      using (var stream = new MemoryStream())
      using (var xmlwriter = new XmlTextWriter(stream, Encoding.UTF8))
      {
          ser.Serialize(xmlwriter, value);
          var buffer = stream.GetBuffer();

          // skip the byte order mask
          return Encoding.UTF8.GetString(buffer, 3, buffer.Length - 3);
      }
  }

  /// <summary>
  /// Deserializes the specified string using an XML serializer.
  /// </summary>
  /// <typeparam name="T">The type of object to deserialize.</typeparam>
  /// <param name="stream">The stream to deserialize.</param>
  /// <returns>A deserialized object of the specified type.</returns>
  public static T Deserialize<T>(this Stream stream)
  {
    using (var reader = new XmlTextReader(reader))
    {
      var ser = new XmlSerializer(typeof(T));
      return (T)ser.Deserialize(reader);
    }
  }

  /// <summary>
  /// Deserializes the specified string using an XML serializer.
  /// </summary>
  /// <typeparam name="T">The type of object to deserialize.</typeparam>
  /// <param name="xml">The XML to deserialize.</param>
  /// <returns>A deserialized object of the specified type.</returns>
  public static T Deserialize<T>(this string xml)
  {
    using (var reader = new StringReader(xml))
    {
      var ser = new XmlSerializer(typeof(T));
      return (T)ser.Deserialize(reader);
    }
  }

  /// <summary>
  /// Deserializes the specified node using an XML serializer.
  /// </summary>
  /// <typeparam name="T">The type of object to deserialize.</typeparam>
  /// <param name="node">The node containing XML to deserialize.</param>
  /// <returns>A deserialized object of the specified type.</returns>
  public static T Deserialize<T>(this XmlNode node)
  {
    using (var reader = new StringReader(node.OuterXml))
    {
      var ser = new XmlSerializer(typeof(T));
      return (T)ser.Deserialize(reader);
    }
  }
}

Happy Coding!


 
Categories: C# | Extension Methods

Welcome to part 1 of the Powerful Extension Methods series. The extension method concept is an excellent feature of the latest breeds of the .NET framework. They allow us to abstract away static utility classes in a way that makes the utility methods appear to belong to the object they operate upon. Beginners can check things out here and here for a good introduction.

I do WinForms programming from time to time. In any Windows application, whether through traditional WinForms or through WPF, managing event handling in the face of threading is critical. Exceptions are thrown when code updates any UI Control property from any thread except the thread that created the control. This problem surfaces when some background thread needs to update the UI.

This led to a lot of creative solutions involving InvokeRequired and Invoke. One solution involves creating an event on the threaded object which the UI can subscribe to. The OnMyEvent method of the object handles invoking each event handler methods on the thread from which they subscribed. The full idea is described here.

It only took me an event handler or two before the DRY principle screamed for attention. Enter, the SafeInvoke extension method:

/// <summary>
/// Raises the event asynchronously.
/// </summary>
/// <param name="handler">The handler.</param>
/// <param name="source">The source.</param>
/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
public static void SafeInvoke(this EventHandler handler, object source, EventArgs args)
{
  if (handler != null)
  {
    foreach (EventHandler singleCast in handler.GetInvocationList())
    {
      var syncInvoke = singleCast.Target as ISynchronizeInvoke;
      try
      {
        if (syncInvoke != null && syncInvoke.InvokeRequired)
        {
          syncInvoke.Invoke(singleCast, new object[] { source, args });
        }
        else
        {
          singleCast(source, args);
        }
      }
      catch
      {
        // Do nothing. The event handler may have been detached asynchronously.
      }
    }
  }
}

With this extension method, we can construct our threaded object to look something like this:

public class MyWorker
{
  public event EventHandler SomeEvent;

  protected virtual void OnSomeEvent(EventArgs e)
  {
    this.SomeEvent.SafeInvoke(this, e);
  }
}

You can see that using this pattern, the event will manage on its own the process of ensuring the event is handled on the subscribing threads. No more threading exceptions when updating the UI from a background worker!

Another common event delegate that deserves a similar extension method is the generic EventHandler<T> class. The model of the function is no surprise; but, here it is in full.

/// <summary>
/// Raises the event asynchronously.
/// </summary>
/// <typeparam name="T">The type of the event handler arguments</typeparam>
/// <param name="handler">The handler.</param>
/// <param name="source">The source.</param>
/// <param name="args">The arguments containing the event data.</param>
public static void SafeInvoke<T>(this EventHandler<T> handler, object source, T args)
where T : EventArgs { if (handler != null) { foreach (EventHandler<T> singleCast in handler.GetInvocationList()) { var syncInvoke = singleCast.Target as ISynchronizeInvoke; try { if (syncInvoke != null && syncInvoke.InvokeRequired) { syncInvoke.Invoke(singleCast, new object[] { source, args }); } else { singleCast(source, args); } } catch { // Do nothing. The event handler may have been detached asynchronously. } } } }

Happy Coding!


 
Categories: C# | Extension Methods