Just Clip it


There was a question presented on StackOverflow about how do you pull an image from the Clipboard.  This article is about how this was done with two separate functions.

The first function Export-ClipItem is a function that detects what type of item is in the Clipboard.  To perform this function the built in cmdlets with powershell 5.1 work nicely.  This script however, is written assuming that an older version of Powershell maybe required.

The first thing that needs to be done is to get a windows form object:


Add-Type -AssemblyName System.Windows.Forms

$clipboard = [System.Windows.Forms.Clipboard]::GetDataObject()

The the Windows Forms object added the clipboard is now accessible.  If the $clipboard object is inspected:


$clipboard | get-member

TypeName: System.Windows.Forms.DataObject

Name MemberType Definition 
---- ---------- ---------- 
ContainsAudio Method bool ContainsAudio() 
ContainsFileDropList Method bool ContainsFileDropList() 
ContainsImage Method bool ContainsImage() 
ContainsText Method bool ContainsText(), bool ContainsText(System.Windows.Forms.TextDataFormat format) 

.....

GetAudioStream Method System.IO.Stream GetAudioStream() 
GetCanonicalFormatEtc Method int IDataObject.GetCanonicalFormatEtc([ref] GetFileDropList Method System.Collections.Specialized.StringCollection GetFileDropList() 

.....

GetImage Method System.Drawing.Image GetImage() 
GetText Method string GetText(), string GetText(System.Windows.Forms.TextDataFormat format) 

Based upon inspection there are several items that can be tested for with (Contains) and then items can be retrieved from the clipboard with (Get) methods.

Starting with Text it can be tested with ContainsText(). Retrieval of the Text can then be done with GetText()

 

if($clipboard.ContainsText())
{

$clipboard.GetText() | Out-File -FilePath "c:\temp\temp.txt"

}

ContainsImage() is a little bit trickier. Using getImage() the type of object it contains can be seen with gettype()


$clipboard.getimage().gettype()

IsPublic IsSerial Name BaseType 
-------- -------- ---- -------- 
True True Bitmap System.Drawing.Image

Since the Image retrieved from the clipboard is aready a System.Drawing.Image type.  That library has a Save() function.  it requires the path to save the image to and a type to save the image as.


$clipboard.getimage().save("c:\temp\clip.png",[System.Drawing.Imaging.ImageFormat]::Png)

Inspection of the Class for System.Drawing.Imaging.ImageFormat demonstrates there are a number of image formats that can be saved:


[System.Drawing.Imaging.ImageFormat].getproperties().Name
Png
Guid
MemoryBmp
Bmp
Emf
Wmf
Gif
Jpeg
Tiff
Exif
Icon

There are two other types of data that can be retrieved from the clipboard.

  1. ContainsFileDropList()

A file drop list is a collection of strings containing path information for files. The return from GetFileDropList is a StringCollection.  For this blog post it was chosen to just save the contents of the return as a txt file.


if($clipboard.ContainsFileDropList())

{

$clipboard.GetFileDropList()| Out-File -FilePath "c:\temp\temp.txt"

}

2. AudioFile

The last type that can be retrieved from the clipboard is an Audio file.  Performing the Export of the Audio will be presented in the next Blog post on this topic.


if($clipboard.ContainsAudio())
{
$clipboard.GetAudioStream()

#perform stream function to file ()
}

Now that we have the different types of output Text, Images, FileDropList, and at a later Date audio.  Now exploration of the File name function can be explored.  For this Script it was decided to write out a single file for each Clipboard operation.  This next explanation demonstrates how this was done.


function new-fileobject
{ param([string]$path, [string]$ext)

if(!(test-path $path -PathType Leaf -ErrorAction Ignore))
{
if([system.io.path]::GetExtension($path))
{
$filename = [system.io.path]::GetFileNameWithoutExtension([system.io.path]::GetFileName($path))
$path = [System.IO.Path]::GetDirectoryName($Path)
if(!(test-path $path -ErrorAction Ignore))
{new-item $path -Force}
}
else
{
$filename = [system.io.path]::getfilename($path)
$path = [system.io.path]::getdirectoryname($path)
if(!(test-path $path -ErrorAction Ignore))
{new-item $path -Force}
}
}
else
{
$filename = [system.io.path]::GetFileNameWithoutExtension([system.io.path]::GetFileName($path))
$path = [System.IO.Path]::GetDirectoryName($Path)
}
if([string]::IsNullOrEmpty($filename))
{
$filename = 'clip'
}
if(test-path "$path\$filename*")
{
[int]$lastFilenameNumber=((gi -path "$path\$filename*").BaseName | select-string '^\D+\d*$' | select -Last 1) -replace '^\D+',''
if($lastFilenameNumber)
{
$filename = "$filename$($lastFilenameNumber + 1)"
}
elseif(get-item "$path\$filename$($ext)")
{
$filename = "$filename$($lastFilenameNumber + 1)"
}
}
[pscustomobject]@{'filename' = $filename; 'path' = $path; 'ext' = $ext; 'fullpath' = "$path\$filename$($ext)"}
}

The object of this function was to take a file path ($Path) and an extension ($ext).

  1. Determine if the file & path exists. If path nor file exists create one or both.
  2. Determine if the file is already there. If it is present detect the current number of the file and add one.
  3. Return the filename, path, extension and fullpath.

With that function in place the script is now complete:


param([string]$path)

function export-clipItem
{
param($path)
Add-Type -AssemblyName System.Windows.Forms
#get the file extension and path

$clipboard = [System.Windows.Forms.Clipboard]::GetDataObject()

if ($clipboard.ContainsImage())
{ $ext = '.png'
$fileobject = new-fileobject $path $ext
[System.Drawing.Bitmap]$clipboard.getimage().Save("$($fileobject.fullpath)", [System.Drawing.Imaging.ImageFormat]::Png)
#https://social.msdn.microsoft.com/Forums/vstudio/en-US/9c2a05de-c680-4515-898a-e92f28eddbf9/retrieve-image-from-clipboard-and-save-it-in-different-formats
}
elseif($clipboard.ContainsText())
{
$ext = '.txt'
$fileobject = new-fileobject $path $ext
$clipboard.GetText() | Out-File -FilePath "$($fileobject.fullpath)"
}
elseif($clipboard.ContainsAudio())
{
$ext = '.wav'
$fileobject = new-fileobject $path $ext
$clipboard.GetAudioStream() #| out-file -FilePath "$($fileobject.fullpath)"
#create stream and output to file goes here.
}
elseif($clipboard.ContainsFileDropList())
{
$ext = '.txt'
$fileobject = new-fileobject $path $ext
$clipboard.GetFileDropList()| Out-File -FilePath "$($fileobject.fullpath)"
}
Write-Output "$($fileobject.fullpath)"
}

function new-fileobject
{ param([string]$path, [string]$ext)

if(!(test-path $path -PathType Leaf -ErrorAction Ignore))
{
if([system.io.path]::GetExtension($path))
{
$filename = [system.io.path]::GetFileNameWithoutExtension([system.io.path]::GetFileName($path))
$path = [System.IO.Path]::GetDirectoryName($Path)
if(!(test-path $path -ErrorAction Ignore))
{new-item $path -Force}
}
else
{
$filename = [system.io.path]::getfilename($path)
$path = [system.io.path]::getdirectoryname($path)
if(!(test-path $path -ErrorAction Ignore))
{new-item $path -Force}
}
}
else
{
$filename = [system.io.path]::GetFileNameWithoutExtension([system.io.path]::GetFileName($path))
$path = [System.IO.Path]::GetDirectoryName($Path)
}
if([string]::IsNullOrEmpty($filename))
{
$filename = 'clip'
}
if(test-path "$path\$filename*")
{
[int]$lastFilenameNumber=((gi -path "$path\$filename*").BaseName | select-string '^\D+\d*$' | select -Last 1) -replace '^\D+',''
if($lastFilenameNumber)
{
$filename = "$filename$($lastFilenameNumber + 1)"
}
elseif(get-item "$path\$filename$($ext)")
{
$filename = "$filename$($lastFilenameNumber + 1)"
}
}
[pscustomobject]@{'filename' = $filename; 'path' = $path; 'ext' = $ext; 'fullpath' = "$path\$filename$($ext)"}
}
export-clipItem $path

I hope this helps Someone

 

Until then

 

Keep Scripting

 

thom

 

 

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s