Search code examples
c#winformsclipboardoffice-interopclipboard-interaction

Copy multiple (e.g. image and text) things to the Clipboard for pasting into MS office C# Winform


I want to copy multiple things to the clipboard:

Clipboard.SetImage(Image);
Clipboard.SetText(ImageCaption);  

However I notice all the Clipboard.Set* functions clear the clipboard first. So in the above example you only get the text. Is there any "add" equivalent?

At the very least I would like to be able to add a bitmap and some text onto the clipboard so they can be pasted together into an application like Microsoft Office.

I cheekily tried:

    [Serializable]
    public class ImageAndText
    {
        public readonly string text;
        public readonly Bitmap image;

        public ImageAndText(string text, Bitmap image)
        {
            this.text = text;
            this.image = image;
        }
    }
    private void CopyToClipBoard()
    {

        Clipboard.SetData(DataFormats.Rtf , new ImageAndText(NewLayer.RecursionLog, rootLayer.GetBitmapTrueRes()));
    }

But just got the "to string" of imageandtext which makes sense. There must be a data format I can use to tell MS that its getting an image and text? Is it secret?


Solution

  • Currently I have this working using RTF, but it does seem overkill for what I wanted to achieve...

    I grabbed this nice little RTF library off code project, Thank you Dima for sharing this with the world :)

    And I modified it, adding one extra function to write to the clipboard (i'm sure the extra function could have been added better but it works)('cough' hacky'cough')

    The code to copy my image and text to the clipboard became:

    private void CopyDetailToClipBoard(string caption, Image image)
    {
    
        //using rtf data format, put a bunch of data onto the clipboard
        RtfDocument rtf = new RtfDocument();
        RtfParagraph rtfTextBlock = new RtfParagraph();             
        const int captionFontSize = 22;
    
    
       //add main image to rtf text
        RtfImage image = new RtfImage(image, RtfImageFormat.Png);
        rtfTextBlock.AppendParagraph(image);
    
        //add caption
        RtfFormattedText Caption = new RtfFormattedText(caption,
            RtfCharacterFormatting.Underline | RtfCharacterFormatting.Bold,
            1,
            captionFontSize);      
    
        rtfTextBlock.AppendParagraph(Caption);
    
        rtf.Contents.Add(rtfTextBlock);
    
        //write the rtf to the clipboard
        RtfWriter rtfWriter = new RtfWriter();
        rtfWriter.WriteToClipBoard(rtf);
    }
    

    And the extra function I added to the RTF library was "WriteToClipbard" which I added to RtfWriter.cs and was simply a C&P of the write function but instead of writing the string to file it writes to the clipboard (it would be nicer if I had modified RtfDocument to simply had a "tostring" that could be used in either scenario)

    //Where rtfWriter.WriteToClipBoard is a modified version of the "Write" function:
    public void WriteToClipBoard(RtfDocument document)
    {
        _encoding = Encoding.GetEncoding((int)document.CodePage);
    
        sb = new StringBuilder();
    
        Reflect(document);
    
        Clipboard.SetData(DataFormats.Rtf, sb.ToString());
    }
    

    I am still hoping there is a "lighter" solution then this, but this works for copying from my application to Word/any rtf application and it has the nice bonus that I can do fancy formatting etc.

    p.s.

    A word of warning, if your just adding text to an image (or vice-versa) just for the hell of it, don't, because the caveat is adding just a bitmap to the clipboard is recognized by more applications (e.g. paint), equally RTF into say notepad isn't very clean :p.

    So your actually limiting the potential cross-over(see below for update) of your application's data by going the RTF route. For me, the text is actually more then just a "caption" it's a whole host of data explaining how the image was created (hence why the fancy formatting is actually quite useful but I have simplified all that for brevity).I actually found myself adding this as a "cntrl+shift+c" option and keeping "ctnrl+c" as adding a good old bitmap to the clipboard.

    --UPDATE---

    Turns out you can copy and paste RTF files into word. So you can skip the extra write to clipboard part and create the file and then add the file to the clipboard. This actually allows you to have multiple image+text items, the draw back is it gets pasted into word as an embedded doc but this was actually better for what I wanted.

    Also turns out you can work around the application limit issue as you can add multiple types to the clipboard in parallel. So I currently add it to the clipboard as both an RTF file and a bitmap. doing the "setimage" does not overwrite the "setfile"

    This way when I paste into word, I get the RTF, with the image and the bitmap.

    When I paste into paint I paste just the image :) (in fact when I add to the bitmap clipboard I use GDI to write the caption on)

    Its actually very cool how it works for various programs. Interestingly different office programs have different default "choices". Word seems to pick the RTF, whereas Powerpoint will pick the bitmap.