# Clipboard with transparency

After reading this question I have determined that

Rasterize[Graphics[Circle[]], "Image", Background -> None]


allows you to do Save As on the Image and the keep the transparency. But if you use the the menus Edit->Copy As->Bitmap or Edit->Copy As->Metafile I have noticed that graphics fail to keep their transparency when pasting into other applications.

Now I can Export an image and copy and paste it back into Mathematica(or another application) and everything works just fine, therefore the clipboard can hold references to transparent images.

Doing some further investigation, here is an image of ClipSpy showing how CF_HDROP and FileNameW(FileName doesn't seem to contain the entire piece of text) contain the location of the png file, allowing you to paste it into other applications.

When working with lots of images, exporting every image becomes quite tedious. It seems like their should be some way to automatically have Mathematica export the file and store a reference of it in the clipboard to retain the image transparency.

So how do I patch or extend Mathematica's clipboard functionality to work with transparent images? Possible useful links for myself and others 1 2 3 4

EDIT: It appears a handful of applications like Inkscape and Powerpoint don't allow you to paste with only a CF_DROP reference. Instead it seems to be better to store the actual image as a PNG on the clipboard.

-
What program are you trying to paste into? –  0xFE May 30 '13 at 3:09
I'm not sure what you are trying to do - if you really have a lot of images, then exporting them as files can be done en masse. It seems to me that dealing with each individual image separately via the clipboard is the definition of tedious. –  bill s May 30 '13 at 3:32
@0xFE sometimes Gimp, sometimes Inkscape, or Powerpoint, it depends on what I'm doing. I have looked at the Clipboard with ClipSpy and Mathematica doesn't appear to be storing inside the Clipboard a file type that supports transparency. It definitely appears to be Mathematica needs to patched to support such a feature. –  Liam William May 30 '13 at 4:46
@bill I wish I could automate believe me :) , but each image depends on the previous images and must be manual customized before being re-imported into Mathmatica to be used in the next Image. I don't have a list of Images, the Images are slowly created based on previous Mathematica images. I'm using this to create visual representations of equations (which is more an art, then an automated script). Either way API's exist in Windows to store transparent images, and Mathematica has built in .NET support, so there must be a way :-) –  Liam William May 30 '13 at 4:55

Here is a considerable simplification of Liam's accepted answer. It avoids the need to create and compile a C# program. This is basically just a small modification to Simon Woods' answer, so that it writes directly to the clipboard instead of creating a temporary file on disk. This avoids the need to clean up the file afterward.

Needs["NETLink"]

WriteToClipboardTransparent[g_] :=
Module[{png, strm, dataObject},
InstallNET[];
png = ExportString[Rasterize[g, "Image", Background->None], "PNG"];
NETBlock[
strm = NETNew["System.IO.MemoryStream", ToCharacterCode[png]];
dataObject = NETNew["System.Windows.Forms.DataObject"];
dataObject@SetData["PNG", strm];
ClipboardSetDataObject[dataObject]
]
]


The button and menu commands would then simply call WriteToClipboardTransparent[NotebookRead[InputNotebook]].

-
Awesome! How did you get bye without having to use [STAThread]? According to stackoverflow.com/questions/5944605/c-sharp-clipboard-gettext/… I think you need to run under an a STAThread. I couldn't get the code to run consistently without such an attribute. I mean if it works, it works :) –  Liam William Jul 8 '13 at 19:12
You do need the [STAThread] attribute when writing a standalone program, but the .NET/Link thread that handles calls from Mathematica already has that attribute. If you're curious, you can see this property being set in line 79 of Reader.cs in the .NET/Link source code. –  Todd Gayley Jul 8 '13 at 20:33
Could this same technique be used to create an .exe file for Snagit? This article has a similar problem, but didn't cover the transparency issue. dc-abaper.blogspot.com/2011/07/… –  Glen Lipka Jul 15 '13 at 17:40
@GlenLipka Yes I believe so athlough I'm not entirely sure of the best way to do such. –  Liam William Mar 1 at 20:53

Something like this? It does just what you suggested: export the file and then place a FileDrop reference to it on the clipboard.

Needs["NETLink"];
InstallNET[];

exportToClipboard[graphics_] := Module[{dob, file},
file = FileNameJoin[{$TemporaryDirectory, "mmaClipboard.png"}]; Export[file, graphics]; NETBlock[ dob = NETNew["System.Windows.Forms.DataObject"]; dob @ SetData[DataFormatsFileDrop, True, {file}]; ClipboardSetDataObject[dob]]];  e.g. image = Rasterize[Graphics[Circle[]], "Image", Background -> None]; exportToClipboard[image]  Paste into Powerpoint... - Can you use ExportString to avoid dumping to a file? – Ajasja May 31 '13 at 19:12 @Ajasja, with this method only the file name goes onto the clipboard, not the contents. It's using the same mechanism as if you "copy" a file on the desktop and paste it into an application, the application just receives the file path and imports the file itself. You can put image data onto the clipboard but it has to be converted to a specific bitmap format. This way is easier! – Simon Woods May 31 '13 at 20:11 I do love the simpleness of this. I was orignally trying to use C APIs this is better. @Ajasja I have noticed that this solution doesn't work with a select number of apps(Inkscape) while it works great with others like Photoshop. I am looking into copying the image as a PNG to the clipboard. I believe it involves something like MemoryStream ms = new MemoryStream(); bitmap.Save(ms, ImageFormat.Png); IDataObject dataObject = new DataObject(); dataObject.SetData("PNG", false, ms); System.Windows.Forms.Clipboard.Clear(); System.Windows.Forms.Clipboard.SetDataObject(dataObject, false); – Liam William May 31 '13 at 20:18 @Ajasja It appears dragging and dropping the png file works fine in most any application, while pasting only sometimes works, I am going to try and create a pop up window that opens and stays on top of other windows temporarily while you drag the image into another application. – Liam William May 31 '13 at 20:26 For anyone using this regularly, I would advise replacing Directory[] with $TemporaryDirectory to avoid putting pictures in random places across your system. My Directory[] location changes depending on the script and what files I might be working on. –  Liam William Jun 11 '13 at 18:43

The following code copies the actua PNG image to the clipboard with transparency. This varies from the other answer in that it actual stores the entire image instead of a reference to the file. This code will likely work with more applications then the one above. It currently uses the Ctrl+Shift+C to copy with transparency. The code takes a while to run currently because the program gets recompiled and rerun each time you hit the keyboard shortcut. Please suggest any modifications to help make it more portable or faster :)

To test that it is working run.

   WriteToClipboard["PNG", ExportString[
Rasterize[
Graphics[{Circle[]}]
, "Image", Background -> None], {"Base64", "PNG"}]]


The following prints a Button that copy the selected Graphic as a PNG, and sets the keyboard shortcut Ctrl + Shift + C.

(* Construct Button *)
Print[Button["Copy Image",
If[
MessageDialog["You must select a Graphic."];
Return[];
];
MessageDialog[AbsoluteTiming[
WriteToClipboard["PNG",
ExportString[
Background -> None], {"Base64", "PNG"}]];
]]
]
]
(* Set up keyboard shortcut *)
FrontEndExecute[
MenuItem["ClipboardWithPNG", FrontEndKernelExecute[Function[

WriteToClipboard["PNG", ExportString[
Rasterize[
, "Image", Background -> None], {"Base64", "PNG"}]]

][]
], MenuKey["c", Modifiers -> {"Control", "Shift"}],


And the needed code and functions.

Module[{temp, t2, CopyFileOverwrite, csfile, exefile, file, NRun},
temp  = FileNameJoin[{$TemporaryDirectory, "ClipboardTransparency314241234"}]; NRun[s_] := (str = OpenWrite[FileNameJoin[{temp, "temp.bat"}]]; WriteString[str, s]; Import["!" <> Close[str], "Text"];); If[DirectoryQ[temp], t2 = Directory[]; SetDirectory[temp]; Map[Function[DeleteFile[#]], FileNames[]]; SetDirectory[t2]; DeleteDirectory[temp, DeleteContents -> True]; , Null ]; CreateDirectory[temp]; CopyFile[ FileNameJoin[{$InstallationDirectory, "SystemFiles", "Links",
];

csfile = FileNameJoin[{temp, "File.cs"}];
exefile = FileNameJoin[{temp, "File.exe"}];
file = OpenWrite[csfile];
WriteString[file, "using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;

public class File{
public static void Main(String[] args) {
string input = System.Console.In.ReadToEnd();
byte[] bytes = Convert.FromBase64String(input);
Stream stream = new MemoryStream(bytes);
IDataObject dataObject = new DataObject();
dataObject.SetData(args[0], stream);
Clipboard.SetDataObject(dataObject, true);
}
}"];
Close[file];
NRun ["cd " <> temp  "
C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe  \

WriteToClipboard[type_, data_] := (
dataloc = FileNameJoin[{temp, "data.txt"}];
datafile = OpenWrite[dataloc];
WriteString[datafile, data];
Close[datafile];
NRun["type " <> dataloc <> " | " <> exefile <> " " <> type];
);
]


To help measure timing I have been using this modified code with this function.

Time[code_] := (
absolute = AbsoluteTiming[ReleaseHold[code]];
(* Print[ToString[absolute[[1]]]<>" | "<>ToString[code] ]; *)
absolute[[2]]
)
Time[HoldForm[Print["test"]]]


Old Code: To help users understand the evolution of the code, here is the old technique. It re compiles the program each time WriteToCliboard is run, therefore it will likely much slower.

-