0

I have a WPF control in my PowerPoint add-in that hosts an image that I want to be able to drag & drop onto the active slide. I can get the image to appear on the slide, but the transparent areas are rendered in black.

My code to initialize the drag from my attached behavior:

var targetBitmap = new RenderTargetBitmap(
    (int) MyWpfControl.ActualWidth,
    (int) MyWpfControl.ActualHeight,
    96d, 96d, PixelFormats.Default);

targetBitmap.Render(MyWpfControl);

var dataObject = new DataObject(
    DataFormats.Bitmap, 
    targetBitmap);

DragDrop.DoDragDrop(MyWpfControl, dataObject, DragDropEffects.Copy)

Thinking that maybe I needed to pass a System.Drawing.Image, I attempted this modification, which only resulted in the transparent areas being rendered in gray:

var targetBitmap = new RenderTargetBitmap(
    (int) MyWpfControl.ActualWidth,
    (int) MyWpfControl.ActualHeight,
    96d, 96d, PixelFormats.Default);

targetBitmap.Render(MyWpfControl);

var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(targetBitmap));

var ms = new MemoryStream();
encoder.Save(ms);

var dataObject = new DataObject(DataFormats.Bitmap, Image.FromStream(ms, true))
DragDrop.DoDragDrop(MyWpfControl, dataObject, DragDropEffects.Copy)

I did a test where I replaced the memory stream with a file stream, and the image that was written did indeed have the correct transparency.

So what am I missing here? How can I maintain transparency?

Todd
  • 620
  • 4
  • 13

1 Answers1

1

I was able to resolve this by following the instructions in this blog post. The solution was to use the EnhancedMetafile DataFormat in my DataObject.

Edit:

Here’s the code that initiates the drag operation.

private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Bitmap bitmap = ImageToBitmap(e.Source as System.Windows.Controls.Image);

    DataObject data = new DataObject(DataFormats.EnhancedMetafile, MakeMetafileStream(bitmap));

    DragDrop.DoDragDrop((DependencyObject)e.Source, data, DragDropEffects.Copy);
}

This makes use of a utility function to convert the Image to a Bitmap:

private Bitmap ImageToBitmap(System.Windows.Controls.Image image)
{
    RenderTargetBitmap rtBmp = new RenderTargetBitmap((int)image.ActualWidth, (int)image.ActualHeight,
        96.0, 96.0, PixelFormats.Pbgra32);

    image.Measure(new System.Windows.Size((int)image.ActualWidth, (int)image.ActualHeight));
    image.Arrange(new Rect(new System.Windows.Size((int)image.ActualWidth, (int)image.ActualHeight)));

    rtBmp.Render(image);

    PngBitmapEncoder encoder = new PngBitmapEncoder();
    MemoryStream stream = new MemoryStream();
    encoder.Frames.Add(BitmapFrame.Create(rtBmp));

    // Save to memory stream and create Bitamp from stream
    encoder.Save(stream);

    return new System.Drawing.Bitmap(stream);
}

This also requires a utility function that converts a Bitmap to a stream containing a Metafile, taken from Stack Overflow.

// From Convert an image into WMF with .NET?

private MemoryStream MakeMetafileStream(Bitmap image)
{
    Graphics graphics = null;
    Metafile metafile = null;
    var stream = new MemoryStream();
    try
    {
        using (graphics = Graphics.FromImage(image))
        {
            var hdc = graphics.GetHdc();
            metafile = new Metafile(stream, hdc);
            graphics.ReleaseHdc(hdc);
        }
        using (graphics = Graphics.FromImage(metafile))
        { graphics.DrawImage(image, 0, 0); }
    }
    finally
    {
        if (graphics != null)
        { graphics.Dispose(); }
        if (metafile != null)
        { metafile.Dispose(); }
    }
    return stream;
}
Community
  • 1
  • 1
Todd
  • 620
  • 4
  • 13