-
-
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; | |
} | |
} |
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.
VB.Net version
''' <summary>
''' Public function convertToIcon converts a bitmap image to a icon image stream with all the sizes windows likes.
''' </summary>
Public Class imagingHelper
''' <summary>
''' Adapted from this gist: https://gist.github.com/darkfall/1656050
''' VB.Net version by me, EvertKuijpers of The Netherlands, also known as EAHMK, on october 19, 2024
''' Based on the CS.Net version by mdiller on Mar 10, 2018
''' Visual Basic .Net Compatible Version
'''
''' This work is licensed under CC BY-SA 4.0, https://creativecommons.org/licenses/by-sa/4.0/.
'''
''' I do not use imports (System.Drawing, System.Drawing.Drawing2D, System.Drawing.Imaging and System.IO),
''' because I am convinced using full names of objects makes code easier to read.
''' This way there is no doubt about the namespace that an object stems from.
''' </summary>
Private commentsLocation As Boolean
''' <summary>
''' Converts a bitmap image to a icon image stream with all the sizes windows likes.
''' </summary>
''' <param name="inputBitmap">The input bitmap.</param>
''' <param name="output">The output stream.</param>
''' <returns>Whether or not the icon was succesfully generated.</returns>
Public Function convertToIcon(inputBitmap As Drawing.Bitmap, ByRef output As IO.Stream) As Boolean
If inputBitmap Is Nothing Then
Return False
End If
Dim sizes As Int32() = {256, 48, 32, 16}
Do ' Generate bitmaps for all the sizes and toss them in streams
Dim imageStreams As New List(Of IO.MemoryStream)
For Each size As Int32 In sizes
Dim newBitmap As Drawing.Bitmap = Me.resizeImage(image:=inputBitmap, width:=size, height:=size)
If newBitmap Is Nothing Then
Return False
End If
Dim memoryStream As New IO.MemoryStream
Call newBitmap.Save(stream:=memoryStream, format:=Drawing.Imaging.ImageFormat.Png)
Call imageStreams.Add(item:=memoryStream)
Next
Dim iconWriter As New IO.BinaryWriter(output:=output)
If output Is Nothing _
Or iconWriter Is Nothing Then
Return False
End If
Dim offset As Int32 = 0
' 0-1 reserved, 0
Call iconWriter.Write(value:=CByte(0)) ' 8 bits
Call iconWriter.Write(value:=CByte(0))
' 2-3 image type, 1 = icon, 2 = cursor
Call iconWriter.Write(value:=CShort(1)) ' 16 bits
' 4-5 number of images
Call iconWriter.Write(value:=CShort(sizes.Length))
offset += 6 + (16 * sizes.Length)
For i As Int32 = 0 To sizes.Length - 1 Step 1
' image entry 1
Dim sizeToWrite As Int32 = sizes(i)
If sizeToWrite > 255 Then
sizeToWrite = 0 ' Stands for 256
End If
' 0 image width
Call iconWriter.Write(value:=CByte(sizeToWrite))
' 1 image height
Call iconWriter.Write(value:=CByte(sizeToWrite))
' 2 number of colors
Call iconWriter.Write(value:=CByte(0))
' 3 reserved
Call iconWriter.Write(value:=CByte(0))
' 4-5 color planes
Call iconWriter.Write(value:=CShort(0))
' 6-7 bits per pixel
Call iconWriter.Write(value:=CShort(32))
' 8-11 size of image data
Call iconWriter.Write(value:=CInt(imageStreams(index:=i).Length)) ' 32 bits
' 12-15 offset of image data
Call iconWriter.Write(value:=CInt(offset))
offset += imageStreams(index:=i).Length
Next
For i As Int32 = 0 To sizes.Length - 1 Step 1
' write image data
' png data must contain the whole png data file
Call iconWriter.Write(imageStreams(index:=i).ToArray)
Call imageStreams(index:=i).Close()
Next
Call iconWriter.Flush()
Exit Do
Loop
Return True
End Function
''' <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>
Private Function resizeImage(image As Drawing.Image, width As Int32, height As Int32) As Drawing.Bitmap
Dim destRect As New Drawing.Rectangle(0, 0, width, height)
Dim destImage As New Drawing.Bitmap(width, height)
Call destImage.SetResolution(xDpi:=image.HorizontalResolution, yDpi:=image.VerticalResolution)
Using graphics As Drawing.Graphics = Drawing.Graphics.FromImage(destImage)
graphics.CompositingMode = Drawing.Drawing2D.CompositingMode.SourceCopy
graphics.CompositingQuality = Drawing.Drawing2D.CompositingQuality.HighQuality
graphics.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
graphics.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality
graphics.PixelOffsetMode = Drawing.Drawing2D.PixelOffsetMode.HighQuality
Using WrapMode As New Drawing.Imaging.ImageAttributes
Call WrapMode.SetWrapMode(mode:=Drawing.Drawing2D.WrapMode.TileFlipXY)
Call graphics.DrawImage(image:=image, destRect:=destRect, srcX:=0, srcY:=0, srcWidth:=image.Width, srcHeight:=image.Height, srcUnit:=Drawing.GraphicsUnit.Pixel, imageAttr:=WrapMode)
End Using
End Using
Return destImage
End Function
''' <summary>
''' Converts a bitmap stream to a icon image stream.
''' </summary>
''' <param name="input">The input stream.</param>
''' <param name="output">The output stream.</param>
''' <returns>Whether or not the icon was succesfully generated.</returns>
Public Function convertToIcon(input As IO.Stream, ByRef output As IO.Stream) As Boolean
Dim inputBitmap As Drawing.Bitmap = Drawing.Bitmap.FromStream(stream:=input)
Return Me.convertToIcon(inputBitmap:=inputBitmap, output:=output)
End Function
''' <summary>
''' Converts a bitmap file to a icon file of type ico.
''' </summary>
''' <param name="inputPath">The input path.</param>
''' <param name="outputPath">The output path.</param>
''' <returns>Whether or not the icon was succesfully generated.</returns>
Public Function convertToIcon(inputPath As String, ByRef outputPath As String) As Boolean
Using inputStream As New IO.FileStream(path:=inputPath, mode:=IO.FileMode.Open)
Using outputStream As New IO.FileStream(path:=outputPath, mode:=IO.FileMode.OpenOrCreate)
Return Me.convertToIcon(input:=inputStream, output:=outputStream)
End Using
End Using
End Function
''' <summary>
''' Converts an image to a icon image stream.
''' </summary>
''' <param name="inputImage">The input image.</param>
''' <param name="outputPath">The output path.</param>
''' <returns>Whether Or Not the icon was succesfully generated.</returns>
Public Function convertToIcon(inputImage As Drawing.Image, outputPath As String)
Using outputStream As New IO.FileStream(path:=outputPath, mode:=IO.FileMode.OpenOrCreate)
Return Me.convertToIcon(inputBitmap:=New Drawing.Bitmap(original:=inputImage), output:=outputStream)
End Using
End Function
End Class
@EvertKuijpers Your VB.NET version works excellently; however (with Option Strick On), I had to fix three errors and several naming rule violations.
Added "As Boolean" to the last function.
Changed "offset += imageStreams(index:=i).Length" to "offset += CInt(imageStreams(index:=i).Length)".
Changed "Dim inputBitmap As Drawing.Bitmap = Drawing.Bitmap.FromStream(stream:=input)" to "Dim inputBitmap As Drawing.Bitmap = CType(Drawing.Bitmap.FromStream(stream:=input), Drawing.Bitmap)".
@Amerigoware1 The missing "As Boolean" is an error for sure. Thank you for finding this. Greetz from Tilburg in The Netherlands.
Sure!