-
-
Save darkfall/1656050 to your computer and use it in GitHub Desktop.
class PngIconConverter | |
{ | |
/* input image with width = height is suggested to get the best result */ | |
/* png support in icon was introduced in Windows Vista */ | |
public static bool Convert(System.IO.Stream input_stream, System.IO.Stream output_stream, int size, bool keep_aspect_ratio = false) | |
{ | |
System.Drawing.Bitmap input_bit = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(input_stream); | |
if (input_bit != null) | |
{ | |
int width, height; | |
if (keep_aspect_ratio) | |
{ | |
width = size; | |
height = input_bit.Height / input_bit.Width * size; | |
} | |
else | |
{ | |
width = height = size; | |
} | |
System.Drawing.Bitmap new_bit = new System.Drawing.Bitmap(input_bit, new System.Drawing.Size(width, height)); | |
if (new_bit != null) | |
{ | |
// save the resized png into a memory stream for future use | |
System.IO.MemoryStream mem_data = new System.IO.MemoryStream(); | |
new_bit.Save(mem_data, System.Drawing.Imaging.ImageFormat.Png); | |
System.IO.BinaryWriter icon_writer = new System.IO.BinaryWriter(output_stream); | |
if (output_stream != null && icon_writer != null) | |
{ | |
// 0-1 reserved, 0 | |
icon_writer.Write((byte)0); | |
icon_writer.Write((byte)0); | |
// 2-3 image type, 1 = icon, 2 = cursor | |
icon_writer.Write((short)1); | |
// 4-5 number of images | |
icon_writer.Write((short)1); | |
// image entry 1 | |
// 0 image width | |
icon_writer.Write((byte)width); | |
// 1 image height | |
icon_writer.Write((byte)height); | |
// 2 number of colors | |
icon_writer.Write((byte)0); | |
// 3 reserved | |
icon_writer.Write((byte)0); | |
// 4-5 color planes | |
icon_writer.Write((short)0); | |
// 6-7 bits per pixel | |
icon_writer.Write((short)32); | |
// 8-11 size of image data | |
icon_writer.Write((int)mem_data.Length); | |
// 12-15 offset of image data | |
icon_writer.Write((int)(6 + 16)); | |
// write image data | |
// png data must contain the whole png data file | |
icon_writer.Write(mem_data.ToArray()); | |
icon_writer.Flush(); | |
return true; | |
} | |
} | |
return false; | |
} | |
return false; | |
} | |
public static bool Convert(string input_image, string output_icon, int size, bool keep_aspect_ratio = false) | |
{ | |
System.IO.FileStream input_stream = new System.IO.FileStream(input_image, System.IO.FileMode.Open); | |
System.IO.FileStream output_stream = new System.IO.FileStream(output_icon, System.IO.FileMode.OpenOrCreate); | |
bool result = Convert(input_stream, output_stream, size, keep_aspect_ratio); | |
input_stream.Close(); | |
output_stream.Close(); | |
return result; | |
} | |
} |
PowerShell Compatible Version
Although @lextm ported the code to PowerShell (many props, Sir), they did not include all the functionality added later by other contributors such as @kipusoep, @bananbl, and @mdiller.
Here is a usable version with the additional modifications and adapted to work with PowerShell.
I didn't have time to convert all the code to PowerShell syntax like @lextm did, so I added it as a custom type and included the required dependencies and command syntax that can be difficult to figure out with PowerShell. After adding the custom type, I wrapped it in a PowerShell function inspired by @lextm.
Parameters/Parameter Sets should be added later to take full advantage of all the constructors and for adjusting other things like size, etc.
The Preserve Aspect Ratio from @ChuckSavage wasn't included in the other C# code (possibly they accounted for it in another way), so I didn't end up adding it here yet, but maybe later; or someone else could do it.
Compatibility
OS Version | PowerShell Version | .NET Version | ❔ ✔️ ❌ |
---|---|---|---|
Windows 10, ver. 2004, build 19041.572 | Windows PowerShell 5.1 | 4.8 | ✔️ |
License
As per @darkfall, this work is licensed under CC BY-SA 4.0
Code
$TypeDefinition = @'
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
/// <summary>
/// Adapted from this gist: https://gist.github.com/darkfall/1656050
/// Provides helper methods for imaging
/// </summary>
public static class ImagingHelper
{
/// <summary>
/// Converts a PNG image to a icon (ico) with all the sizes windows likes
/// </summary>
/// <param name="inputBitmap">The input bitmap</param>
/// <param name="output">The output stream</param>
/// <returns>Wether or not the icon was succesfully generated</returns>
public static bool ConvertToIcon(Bitmap inputBitmap, Stream output)
{
if (inputBitmap == null)
return false;
int[] sizes = new int[] { 256, 48, 32, 16 };
// Generate bitmaps for all the sizes and toss them in streams
List<MemoryStream> imageStreams = new List<MemoryStream>();
foreach (int size in sizes)
{
Bitmap newBitmap = ResizeImage(inputBitmap, size, size);
if (newBitmap == null)
return false;
MemoryStream memoryStream = new MemoryStream();
newBitmap.Save(memoryStream, ImageFormat.Png);
imageStreams.Add(memoryStream);
}
BinaryWriter iconWriter = new BinaryWriter(output);
if (output == null || iconWriter == null)
return false;
int offset = 0;
// 0-1 reserved, 0
iconWriter.Write((byte)0);
iconWriter.Write((byte)0);
// 2-3 image type, 1 = icon, 2 = cursor
iconWriter.Write((short)1);
// 4-5 number of images
iconWriter.Write((short)sizes.Length);
offset += 6 + (16 * sizes.Length);
for (int i = 0; i < sizes.Length; i++)
{
// image entry 1
// 0 image width
iconWriter.Write((byte)sizes[i]);
// 1 image height
iconWriter.Write((byte)sizes[i]);
// 2 number of colors
iconWriter.Write((byte)0);
// 3 reserved
iconWriter.Write((byte)0);
// 4-5 color planes
iconWriter.Write((short)0);
// 6-7 bits per pixel
iconWriter.Write((short)32);
// 8-11 size of image data
iconWriter.Write((int)imageStreams[i].Length);
// 12-15 offset of image data
iconWriter.Write((int)offset);
offset += (int)imageStreams[i].Length;
}
for (int i = 0; i < sizes.Length; i++)
{
// write image data
// png data must contain the whole png data file
iconWriter.Write(imageStreams[i].ToArray());
imageStreams[i].Close();
}
iconWriter.Flush();
return true;
}
/// <summary>
/// Converts a PNG image to a icon (ico)
/// </summary>
/// <param name="input">The input stream</param>
/// <param name="output">The output stream</param
/// <returns>Wether or not the icon was succesfully generated</returns>
public static bool ConvertToIcon(Stream input, Stream output)
{
Bitmap inputBitmap = (Bitmap)Bitmap.FromStream(input);
return ConvertToIcon(inputBitmap, output);
}
/// <summary>
/// Converts a PNG image to a icon (ico)
/// </summary>
/// <param name="inputPath">The input path</param>
/// <param name="outputPath">The output path</param>
/// <returns>Wether or not the icon was succesfully generated</returns>
public static bool ConvertToIcon(string inputPath, string outputPath)
{
using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
{
return ConvertToIcon(inputStream, outputStream);
}
}
/// <summary>
/// Converts an image to a icon (ico)
/// </summary>
/// <param name="inputImage">The input image</param>
/// <param name="outputPath">The output path</param>
/// <returns>Wether or not the icon was succesfully generated</returns>
public static bool ConvertToIcon(Image inputImage, string outputPath)
{
using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
{
return ConvertToIcon(new Bitmap(inputImage), outputStream);
}
}
/// <summary>
/// Resize the image to the specified width and height.
/// Found on stackoverflow: https://stackoverflow.com/questions/1922040/resize-an-image-c-sharp
/// </summary>
/// <param name="image">The image to resize.</param>
/// <param name="width">The width to resize to.</param>
/// <param name="height">The height to resize to.</param>
/// <returns>The resized image.</returns>
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
}
'@
Add-Type -TypeDefinition $TypeDefinition -ReferencedAssemblies 'System.Drawing','System.IO','System.Collections'
<#
.Synopsis
Converts .PNG images to icons
.Description
Converts a .PNG image to an icon
.Example
ConvertTo-Icon -Path .\Logo.png -Destination .\Favicon.ico
#>
Function ConvertTo-Icon
{
[CmdletBinding()]
param(
# The file
[Parameter(Mandatory=$true, Position=0,ValueFromPipelineByPropertyName=$true)]
[Alias('Fullname','File')]
[string]$Path,
# If provided, will output the icon to a location
[Parameter(Position=1, ValueFromPipelineByPropertyName=$true)]
[Alias('OutputFile')]
[string]$Destination
)
Begin
{
If (-Not 'ImagingHelper' -as [Type])
{
Throw 'The custom "ImagingHelper" type is not loaded'
}
}
Process
{
#region Resolve Path
$ResolvedFile = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path)
If (-not $ResolvedFile)
{
return
}
#endregion
[ImagingHelper]::ConvertToIcon($ResolvedFile[0].Path,$Destination)
}
End
{
}
}
Sure!
great, thx, here is btw the respondity for the DLL: CSBeginnerHelp
Thanks for this!
If you get EndOfStreamException
when using the Stream output
do this before using it:
output.Position = 0;
Unfortunately this cannot be used on Powershell Core, System.Drawing.Bitmap
is not available.
this is great TY