Private/Imaging.ps1
Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName PresentationFramework function IsIcoConvertableFile($filePath) { $supportedExtensions = @( ".png", ".bmp", ".tif", ".tiff" ".gif", ".jpg" ) $ext = [System.IO.Path]::GetExtension($filePath) $supportedExtensions.Contains($ext) } function ConvertImageToIco($sourceImagePath, $icoPath) { $sourceImage = [Drawing.Image]::FromFile($sourceImagePath) $icon = CreateIconFromImage $sourceImage $fileStream = [IO.File]::Create($icoPath) $icon.Save($fileStream) $fileStream.Close() $icon.Dispose() } # https://docs.microsoft.com/en-us/previous-versions/ms997538(v=msdn.10)?redirectedfrom=MSDN function CreateIconFromImage($image) { $memoryStream = New-Object System.IO.MemoryStream $writer = New-Object System.IO.BinaryWriter($memoryStream); # ICONDIR $writer.Write([Int16]0) # reserved $writer.Write([Int16]1) # resource type 1 for icons $writer.Write([Int16]1); # number of images # ICONDIRENTRY $w = $image.Width if ($w -ge 256) { $w = 0 # 0 means 256 pixel } $writer.Write([Byte]$w) $h = $image.Height; if ($h -ge 256) { $h = 0 } $writer.Write([Byte]$h) $writer.Write([Byte]0) #Number of colors in image (0 if >=8bpp) $writer.Write([Byte]0) # Reserved ( must be 0) $writer.Write([Int16]0) # Color Planes $writer.Write([Int16]0) # Bits per pixel $imageSizePos = $memoryStream.Position $writer.Write([Int]0) # How many bytes in this resource? $imageStart = [Int]$memoryStream.Position + 4 $writer.Write([Int]$imageStart) # Where in the file is this image? # Image data $image.Save($memoryStream, [System.Drawing.Imaging.ImageFormat]::Png) $imageSize = [Int]$memoryStream.Position - $imageStart $memoryStream.Seek($imageSizePos, [System.IO.SeekOrigin]::Begin) | Out-Null $writer.Write([Int]$imageSize) $memoryStream.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null return New-Object System.Drawing.Icon($memoryStream); } # https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-deleteobject Add-Type -MemberDefinition @" [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); "@ -Namespace PoshTaskbarItem -Name Win32DeleteObject # https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-extracticonexa Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; namespace PoshTaskbarItem { public class IconExtractor { [DllImport("Shell32.dll", CharSet = CharSet.Unicode)] private static extern uint ExtractIconEx( string lpszFile, int nIconIndex, IntPtr phiconLarge, out IntPtr phiconSmall, uint nIcons ); public static IntPtr ExtractSmallIcon(string filePath, int iconIndex) { IntPtr smallIconHandle; uint extractedIconCount = ExtractIconEx(filePath, iconIndex, IntPtr.Zero, out smallIconHandle, 1); if (extractedIconCount == 1) { return smallIconHandle; } else { return IntPtr.Zero; } } } } "@ function CreateBitmapSourceFromIconResource($filePath, $iconIndex) { $hIcon = [PoshTaskbarItem.IconExtractor]::ExtractSmallIcon($filePath, $iconIndex) if ($hIcon -eq 0) { return $null } $icon = [System.Drawing.Icon]::FromHandle($hIcon) $bitmap = $icon.ToBitmap() $hBitmap = $bitmap.GetHbitmap() $bitmapSource = [System.Windows.Interop.Imaging]::CreateBitmapSourceFromHBitmap( $hBitmap, [System.IntPtr]::Zero, [System.Windows.Int32Rect]::Empty, [System.Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions()) [PoshTaskbarItem.Win32DeleteObject]::DeleteObject($hBitmap) | Out-Null $bitmapSource } function GetImageSource($iconResourcePath, $iconResourceIndex) { if (-not $iconResourcePath) { return } $iconApplications = @(Get-Command -Type Application $iconResourcePath) if ($iconApplications) { $iconResourceFullPath = $iconApplications[0].Source $iconResource = CreateBitmapSourceFromIconResource $iconResourceFullPath $iconResourceIndex if ($iconResource) { # exe, dll or ico file return $iconResource } } # other image files $pathInfo = Resolve-Path $iconResourcePath if ($pathInfo) { $iconResourceFullPath = $pathInfo.Path $bitmap = New-Object System.Windows.Media.Imaging.BitmapImage $bitmap.BeginInit() $bitmap.UriSource = New-Object System.Uri($iconResourceFullPath, [System.UriKind]::RelativeOrAbsolute) $bitmap.EndInit() return $bitmap } } function GetIconResourceFullPath($iconResourcePath) { $iconResourceFullPath = $null if (IsIcoConvertableFile $iconResourcePath) { # Handle image files here as they have to be converted to .ico $pathInfo = Resolve-Path $iconResourcePath if ($pathInfo) { $iconResourceFullPath = $pathInfo.Path $icoPath = [System.IO.Path]::ChangeExtension($iconResourceFullPath, ".ico") if (Test-Path $icoPath) { # .ico file already exists } else { ConvertImageToIco $iconResourceFullPath $icoPath } $iconResourceFullPath = $icoPath } } else { # Support relative paths, full paths and files under $env:Path $iconApplications = @(Get-Command -Type Application $IconResourcePath) if ($iconApplications) { $iconResourceFullPath = $iconApplications[0].Source } } $iconResourceFullPath } |