mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
This should help if a user has a really complicated shortcut and they want to make a copy to have two of them with slightly different tweaks.
684 lines
30 KiB
C#
684 lines
30 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Imaging;
|
|
using System.Linq;
|
|
using System.Drawing.IconLib;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using TsudaKageyu;
|
|
using DisplayMagicianShared;
|
|
using MintPlayer.IconUtils;
|
|
using System.Runtime.InteropServices;
|
|
using System.IO;
|
|
|
|
namespace DisplayMagician
|
|
{
|
|
public static class ImageUtils
|
|
{
|
|
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
|
|
|
public static Image RoundCorners(Image StartImage, int CornerRadius)
|
|
{
|
|
if (StartImage == null)
|
|
{
|
|
throw new ArgumentNullException("StartImage");
|
|
}
|
|
|
|
CornerRadius *= 2;
|
|
Bitmap RoundedImage = new Bitmap(StartImage.Width, StartImage.Height);
|
|
using (Graphics g = Graphics.FromImage(RoundedImage))
|
|
{
|
|
g.Clear(Color.Transparent);
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
Brush brush = new TextureBrush(StartImage);
|
|
GraphicsPath gp = new GraphicsPath();
|
|
gp.AddArc(0, 0, CornerRadius, CornerRadius, 180, 90);
|
|
gp.AddArc(0 + RoundedImage.Width - CornerRadius, 0, CornerRadius, CornerRadius, 270, 90);
|
|
gp.AddArc(0 + RoundedImage.Width - CornerRadius, 0 + RoundedImage.Height - CornerRadius, CornerRadius, CornerRadius, 0, 90);
|
|
gp.AddArc(0, 0 + RoundedImage.Height - CornerRadius, CornerRadius, CornerRadius, 90, 90);
|
|
g.FillPath(brush, gp);
|
|
return RoundedImage;
|
|
}
|
|
}
|
|
|
|
public static void DrawRoundedRectangle(Graphics graphics, Pen pen, Rectangle bounds, int cornerRadius)
|
|
{
|
|
if (graphics == null)
|
|
throw new ArgumentNullException("graphics");
|
|
if (pen == null)
|
|
throw new ArgumentNullException("pen");
|
|
|
|
using (GraphicsPath path = RoundedRect(bounds, cornerRadius))
|
|
{
|
|
graphics.DrawPath(pen, path);
|
|
}
|
|
}
|
|
|
|
public static void FillRoundedRectangle(Graphics graphics, Brush brush, Rectangle bounds, int cornerRadius)
|
|
{
|
|
if (graphics == null)
|
|
throw new ArgumentNullException("graphics");
|
|
if (brush == null)
|
|
throw new ArgumentNullException("brush");
|
|
|
|
using (GraphicsPath path = RoundedRect(bounds, cornerRadius))
|
|
{
|
|
graphics.FillPath(brush, path);
|
|
}
|
|
}
|
|
|
|
public static GraphicsPath RoundedRect(Rectangle bounds, int radius)
|
|
{
|
|
int diameter = radius * 2;
|
|
Size size = new Size(diameter, diameter);
|
|
Rectangle arc = new Rectangle(bounds.Location, size);
|
|
GraphicsPath path = new GraphicsPath();
|
|
|
|
if (radius == 0)
|
|
{
|
|
path.AddRectangle(bounds);
|
|
return path;
|
|
}
|
|
|
|
// top left arc
|
|
path.AddArc(arc, 180, 90);
|
|
|
|
// top right arc
|
|
arc.X = bounds.Right - diameter;
|
|
path.AddArc(arc, 270, 90);
|
|
|
|
// bottom right arc
|
|
arc.Y = bounds.Bottom - diameter;
|
|
path.AddArc(arc, 0, 90);
|
|
|
|
// bottom left arc
|
|
arc.X = bounds.Left;
|
|
path.AddArc(arc, 90, 90);
|
|
|
|
path.CloseFigure();
|
|
return path;
|
|
}
|
|
|
|
public static Image MakeGrayscale(Image original)
|
|
{
|
|
if (original == null)
|
|
{
|
|
throw new ArgumentNullException("original");
|
|
}
|
|
|
|
//create a blank bitmap the same size as original
|
|
Image newBitmap = new Bitmap(original.Width, original.Height);
|
|
|
|
//get a graphics object from the new image
|
|
using (Graphics g = Graphics.FromImage(newBitmap))
|
|
{
|
|
|
|
//create the grayscale ColorMatrix
|
|
ColorMatrix colorMatrix = new ColorMatrix(
|
|
new float[][]
|
|
{
|
|
new float[] {.3f, .3f, .3f, 0, 0},
|
|
new float[] {.59f, .59f, .59f, 0, 0},
|
|
new float[] {.11f, .11f, .11f, 0, 0},
|
|
new float[] {0, 0, 0, 1, 0},
|
|
new float[] {0, 0, 0, 0, 1}
|
|
});
|
|
|
|
//create some image attributes
|
|
using (ImageAttributes attributes = new ImageAttributes())
|
|
{
|
|
|
|
//set the color matrix attribute
|
|
attributes.SetColorMatrix(colorMatrix);
|
|
|
|
//draw the original image on the new image
|
|
//using the grayscale color matrix
|
|
g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
|
|
0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
|
|
}
|
|
}
|
|
return newBitmap;
|
|
}
|
|
|
|
public static List<ShortcutBitmap> GetMeAllBitmapsFromFile(string fileNameAndPath)
|
|
{
|
|
if (String.IsNullOrWhiteSpace(fileNameAndPath))
|
|
{
|
|
logger.Warn($"ShortcutItem/GetMeAllBitmapsFromFile: Bitmap fileNameAndPath is empty! Unable to get the bitmaps from the file.");
|
|
return new List<ShortcutBitmap>();
|
|
}
|
|
|
|
Icon myIcon = null;
|
|
List<ShortcutBitmap> bmList = new List<ShortcutBitmap>();
|
|
int bmCount = 0;
|
|
string fileNameOnly = Path.GetFileName(fileNameAndPath);
|
|
|
|
if (fileNameAndPath.EndsWith(".jpg") || fileNameAndPath.EndsWith(".gif") || fileNameAndPath.EndsWith(".tif") || fileNameAndPath.EndsWith(".png") || fileNameAndPath.EndsWith(".bmp") ||
|
|
fileNameAndPath.EndsWith(".jpeg") || fileNameAndPath.EndsWith(".tiff"))
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: The file we want to get the image from is an image file. Attempting to extract the image from {fileNameAndPath}.");
|
|
|
|
Bitmap bmap = new Bitmap(fileNameAndPath);
|
|
ShortcutBitmap bm = CreateShortcutBitmap(bmap, fileNameOnly, fileNameAndPath, bmCount++);
|
|
// Add the shortcutbitmap to the list
|
|
bmList.Add(bm);
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: Added new bitmap from the image file {fileNameAndPath} using standard bitmap decoder access method.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/GetMeABitmapFromFile: Exception while trying to extract the bitmap from an image ({fileNameAndPath})using standard bitmap decoder tools.");
|
|
}
|
|
}
|
|
else if (fileNameAndPath.EndsWith(".ico"))
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: The file we want to get the image from is an icon file. Attempting to extract the icon file from {fileNameAndPath}.");
|
|
|
|
myIcon = new Icon(fileNameAndPath, 256, 256);
|
|
//Icon myIcon = Icon.ExtractAssociatedIcon(fileNameAndPath);
|
|
ShortcutBitmap bm = CreateShortcutBitmap(myIcon.ToBitmap(), fileNameOnly, fileNameAndPath, bmCount++);
|
|
// Add the shortcutbitmap to the list
|
|
bmList.Add(bm);
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: Added new bitmap from the icon file {fileNameAndPath} using standard Icon access method.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/GetMeABitmapFromFile: Exception while trying to extract the icon from a *.ico using Standard Icon tools.");
|
|
}
|
|
|
|
try
|
|
{
|
|
MultiIcon myMultiIcon = new MultiIcon();
|
|
SingleIcon mySingleIcon = myMultiIcon.Add("Icon1");
|
|
mySingleIcon.Load(fileNameAndPath);
|
|
foreach (IconImage myIconImage in mySingleIcon)
|
|
{
|
|
ShortcutBitmap bm = CreateShortcutBitmap(myIconImage.Image, fileNameOnly, fileNameAndPath, bmCount++);
|
|
// Add the shortcutbitmap to the list
|
|
bmList.Add(bm);
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: Added new bitmap from the icon file {fileNameAndPath} using MultiIcon access method.");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/GetMeABitmapFromFile: Exception while trying to extract the icon from a *.ico using MultiIcon tools.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
/*try
|
|
{
|
|
List<Icon> myIcons = ImageUtils.ExtractIconsFromExe(fileNameAndPath, true);
|
|
if (myIcons != null && myIcons.Count > 0)
|
|
{
|
|
foreach (Icon myExtractedIcon in myIcons)
|
|
{
|
|
bm = myExtractedIcon.ToBitmap();
|
|
|
|
if (bm.Width > bmToReturn.Width && bm.Height > bmToReturn.Height)
|
|
{
|
|
bmToReturn = bm;
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: This new bitmap from the icon file {fileNameAndPath} is larger than the previous one at {bm.Width} x {bm.Height}, so using that instead.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/GetMeABitmapFromFile: Exception while trying to extract the icon from an *.exe or *.dll using ImageUtils.ExtractIconsFromExe.");
|
|
}*/
|
|
|
|
try
|
|
{
|
|
var ie = new TsudaKageyu.IconExtractor(fileNameAndPath);
|
|
Icon[] allIcons = ie.GetAllIcons();
|
|
foreach (Icon myExtractedIcon in allIcons)
|
|
{
|
|
ShortcutBitmap bm = CreateShortcutBitmap(myExtractedIcon.ToBitmap(), fileNameOnly, fileNameAndPath, bmCount++);
|
|
// Add the shortcutbitmap to the list
|
|
bmList.Add(bm);
|
|
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: Add new bitmap from the exe file {fileNameAndPath} using TsudaKageyu.IconExtractor access method.");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/GetMeABitmapFromFile: Exception while trying to extract the icon from an *.exe or *.dll using TsudaKageyu.IconExtractor.");
|
|
}
|
|
|
|
}
|
|
|
|
try
|
|
{
|
|
|
|
List<Icon> myExtractedIcons = MintPlayer.IconUtils.IconExtractor.Split(fileNameAndPath);
|
|
Size largeSize = new Size(256, 256);
|
|
foreach (Icon myExtractedIcon in myExtractedIcons)
|
|
{
|
|
|
|
try
|
|
{
|
|
myIcon = (Icon)IconUtil.TryGetIcon(myExtractedIcon, largeSize, 32, true, true);
|
|
}
|
|
catch (ArgumentNullException nullex)
|
|
{
|
|
logger.Debug(nullex, $"ShortcutItem/GetMeABitmapFromFile: There was a faulty icon image within this icon that we couldn't test, so skipping it.");
|
|
continue;
|
|
}
|
|
|
|
if (myIcon != null)
|
|
{
|
|
ShortcutBitmap bm = CreateShortcutBitmap(myIcon.ToBitmap(),fileNameOnly,fileNameAndPath,bmCount++);
|
|
// Add the shortcutbitmap to the list
|
|
bmList.Add(bm);
|
|
|
|
logger.Trace($"ShortcutItem/GetMeABitmapFromFile: Added new bitmap from the file {fileNameAndPath} using MintPlayer.IconUtils.IconExtractor access method.");
|
|
}
|
|
else
|
|
{
|
|
logger.Warn($"ShortcutItem/GetMeABitmapFromFile: Couldn't extract an Icon from the file {fileNameAndPath} using MintPlayer.IconUtils.IconExtractor access method, so can't try to get the Icon using IconUtils.TryGetIcon.");
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/GetMeABitmapFromFile: Exception while trying to Split the icon using MintPlayer IconExtractor! ");
|
|
}
|
|
|
|
|
|
return bmList;
|
|
|
|
}
|
|
|
|
public static List<ShortcutBitmap> GetMeAllBitmapsFromFile(ArrayList fileNamesAndPaths)
|
|
{
|
|
List<ShortcutBitmap> bmToReturn = null;
|
|
|
|
if (fileNamesAndPaths.Count == 0)
|
|
{
|
|
logger.Warn($"ShortcutItem/GetMeAllBitmapsFromFile: The fileNamesAndPaths list is empty! Can't get the bitmap from the files.");
|
|
return null;
|
|
}
|
|
logger.Trace($"ShortcutItem/GetMeAllBitmapsFromFile: We have {fileNamesAndPaths.Count} files to try and extract a bitmap from.");
|
|
foreach (string fileNameAndPath in fileNamesAndPaths)
|
|
{
|
|
logger.Trace($"ShortcutItem/GetMeAllBitmapsFromFile: Getting a bitmap from {fileNameAndPath} by running GetMeABitmapFromFile.");
|
|
bmToReturn.AddRange(GetMeAllBitmapsFromFile(fileNameAndPath));
|
|
}
|
|
|
|
return bmToReturn;
|
|
|
|
}
|
|
|
|
public static ShortcutBitmap GetMeLargestAvailableBitmap(List<ShortcutBitmap> shortcutBitmaps)
|
|
{
|
|
// Returns the first ShortcutBitmap with the largest size
|
|
|
|
ShortcutBitmap scToReturn = new ShortcutBitmap();
|
|
|
|
logger.Trace($"ShortcutItem/GetMeLargestAvailableBitmap: We have {shortcutBitmaps.Count} bitmaps to find the largest one within.");
|
|
foreach (ShortcutBitmap sc in shortcutBitmaps)
|
|
{
|
|
if (sc.Size.Width > scToReturn.Size.Width && sc.Size.Height > scToReturn.Size.Height)
|
|
{
|
|
scToReturn = sc;
|
|
}
|
|
}
|
|
|
|
return scToReturn;
|
|
|
|
}
|
|
|
|
public static ShortcutBitmap CreateShortcutBitmap(Bitmap bitmap, string name = "", string source = "", int order = 0)
|
|
{
|
|
ShortcutBitmap sc = new ShortcutBitmap();
|
|
sc.UUID = Guid.NewGuid().ToString("D");
|
|
sc.Name = name;
|
|
sc.Order = order;
|
|
sc.Source = source;
|
|
sc.Image = bitmap;
|
|
sc.Size = new Size(sc.Image.Width, sc.Image.Height);
|
|
return sc;
|
|
}
|
|
|
|
public static List<ShortcutBitmap> ShortcutBitmapClone(List<ShortcutBitmap> shortcutBitmaps)
|
|
{
|
|
// Clones the List<ShortcutBitmap>
|
|
|
|
List<ShortcutBitmap> scListToReturn = new List<ShortcutBitmap>();
|
|
foreach (ShortcutBitmap sc in shortcutBitmaps)
|
|
{
|
|
scListToReturn.Add(ImageUtils.ShortcutBitmapClone(sc));
|
|
}
|
|
|
|
return scListToReturn;
|
|
}
|
|
|
|
public static ShortcutBitmap ShortcutBitmapClone(ShortcutBitmap shortcutBitmap)
|
|
{
|
|
// Clones the ShortcutBitmap
|
|
|
|
ShortcutBitmap scToReturn = new ShortcutBitmap();
|
|
scToReturn.UUID = Guid.NewGuid().ToString("D");
|
|
scToReturn.Image = (Bitmap)shortcutBitmap.Image.Clone();
|
|
scToReturn.Name = shortcutBitmap.Name;
|
|
scToReturn.Order = shortcutBitmap.Order;
|
|
scToReturn.Size = shortcutBitmap.Size;
|
|
scToReturn.Source = shortcutBitmap.Source;
|
|
|
|
return scToReturn;
|
|
}
|
|
|
|
public static bool ImagesAreEqual(Bitmap imageA, Bitmap imageB)
|
|
{
|
|
byte[] image1Bytes;
|
|
byte[] image2Bytes;
|
|
|
|
if (imageA == null || imageB == null)
|
|
return false;
|
|
|
|
using (var mstream = new MemoryStream())
|
|
{
|
|
imageA.Save(mstream,ImageFormat.Bmp);
|
|
image1Bytes = mstream.ToArray();
|
|
}
|
|
|
|
using (var mstream = new MemoryStream())
|
|
{
|
|
imageB.Save(mstream, ImageFormat.Bmp);
|
|
image2Bytes = mstream.ToArray();
|
|
}
|
|
|
|
var image164 = Convert.ToBase64String(image1Bytes);
|
|
var image264 = Convert.ToBase64String(image2Bytes);
|
|
|
|
return string.Equals(image164, image264);
|
|
}
|
|
|
|
public static Bitmap ToBitmapOverlay(Bitmap originalBitmap, Bitmap overlayBitmap, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb)
|
|
{
|
|
if (originalBitmap == null)
|
|
{
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: OriginalBitmap is null, so we'll try to make the BitmapOverlay using GameLibrary Icon.");
|
|
return null;
|
|
}
|
|
|
|
if (overlayBitmap == null)
|
|
{
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: overlayBitmap is null, so we'll just return the original bitmap without a profile overlay.");
|
|
return originalBitmap;
|
|
}
|
|
|
|
if (width <= 0 || width > 256)
|
|
{
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Width is out of range so setting to 256.");
|
|
width = 256;
|
|
}
|
|
|
|
if (height <= 0 || height > 256)
|
|
{
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Height is out of range so setting to 256.");
|
|
height = 256;
|
|
}
|
|
|
|
// Figure out sizes and positions
|
|
try
|
|
{
|
|
Size targetSize = new Size(width, height);
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: TargetSize is {targetSize.Width}px x {targetSize.Height}px.");
|
|
Size originalBitmapCurrentSize = new Size(originalBitmap.Width, originalBitmap.Height);
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: originalBitmapCurrentSize is {originalBitmapCurrentSize.Width}px x {originalBitmapCurrentSize.Height}px.");
|
|
Size overlaylBitmapCurrentSize = new Size(overlayBitmap.Width, overlayBitmap.Height);
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: overlaylBitmapCurrentSize is {overlaylBitmapCurrentSize.Width}px x {overlaylBitmapCurrentSize.Height}px.");
|
|
|
|
// Make a new empty bitmap of the wanted size
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Making a new combined bitmap as the base for the image.");
|
|
var combinedBitmap = new Bitmap(targetSize.Width, targetSize.Height, format);
|
|
combinedBitmap.MakeTransparent();
|
|
|
|
using (var g = Graphics.FromImage(combinedBitmap))
|
|
{
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Setting smoothing mode, Interpolation mode, pixel offset mode and compositing quality.");
|
|
g.SmoothingMode = SmoothingMode.None;
|
|
g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
|
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
g.CompositingQuality = CompositingQuality.AssumeLinear;
|
|
|
|
// Resize the originalBitmap if needed then draw it
|
|
Size originalBitmapNewSize = ResizeDrawing.FitWithin(originalBitmapCurrentSize, targetSize);
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Resizing the original bitmap to fit in the new combined bitmap. Size is now {originalBitmapNewSize.Width}px x {originalBitmapNewSize.Height}px");
|
|
Point originalBitmapNewLocation = ResizeDrawing.AlignCenter(originalBitmapNewSize, targetSize);
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Drawing the original bitmap into the new combined bitmap at position {originalBitmapNewLocation.X},{originalBitmapNewLocation.Y}..");
|
|
g.DrawImage(originalBitmap, originalBitmapNewLocation.X, originalBitmapNewLocation.Y, originalBitmapNewSize.Width, originalBitmapNewSize.Height);
|
|
|
|
// Resize the overlayBitmap if needed then draw it in the bottom-right corner
|
|
Size overlayBitmapMaxSize = ResizeDrawing.FitWithin(overlaylBitmapCurrentSize, targetSize);
|
|
Size overlayBitmapNewSize = ResizeDrawing.MakeSmaller(overlayBitmapMaxSize, 70);
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Resize the overlay bitmap to fit in the bottom right corner of the new combined bitmap. Size is now {overlayBitmapNewSize.Width}px x {overlayBitmapNewSize.Height}px");
|
|
Point overlayBitmapNewLocation = ResizeDrawing.AlignBottomRight(overlayBitmapNewSize, targetSize);
|
|
logger.Trace($"ShortcutItem/ToBitmapOverlay: Drawing the overlay bitmap into the new combined bitmap at position {overlayBitmapNewLocation.X},{overlayBitmapNewLocation.Y}.");
|
|
g.DrawImage(overlayBitmap, overlayBitmapNewLocation.X, overlayBitmapNewLocation.Y, overlayBitmapNewSize.Width, overlayBitmapNewSize.Height);
|
|
|
|
}
|
|
return combinedBitmap;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/ToBitmapOverlay: Exception while trying to add the overlay to the Bitmap. Returning null");
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
#pragma warning disable CS3002 // Return type is not CLS-compliant
|
|
public static MultiIcon ToIconOverlay(Bitmap originalBitmap, Bitmap overlayBitmap)
|
|
#pragma warning restore CS3002 // Return type is not CLS-compliant
|
|
{
|
|
try
|
|
{
|
|
Size[] iconSizes = new[]
|
|
{
|
|
new Size(256, 256),
|
|
new Size(64, 64),
|
|
new Size(48, 48),
|
|
new Size(32, 32),
|
|
new Size(24, 24),
|
|
new Size(16, 16)
|
|
};
|
|
logger.Trace($"ShortcutItem/ToIconOverlay: Creating the new Multi image Icon.");
|
|
MultiIcon multiIcon = new MultiIcon();
|
|
logger.Trace($"ShortcutItem/ToIconOverlay: Adding a single icon to the multi image icon.");
|
|
SingleIcon icon = multiIcon.Add("Icon1");
|
|
|
|
foreach (Size size in iconSizes)
|
|
{
|
|
logger.Trace($"ShortcutItem/ToIconOverlay: Creating a new image layer of size {size.Width}px x {size.Height}px.");
|
|
Bitmap bitmapOverlay = ToBitmapOverlay(originalBitmap, overlayBitmap, size.Width, size.Height);
|
|
if (bitmapOverlay == null)
|
|
{
|
|
logger.Warn($"ShortcutItem/ToIconOverlay: bitmapOverlay is null, so we can't turn it into an Icon Overlay. Returning null");
|
|
return null;
|
|
}
|
|
logger.Trace($"ShortcutItem/ToIconOverlay: Adding the new image layer of size {size.Width}px x {size.Height}px to the multi image icon.");
|
|
icon.Add(bitmapOverlay);
|
|
|
|
if (size.Width >= 256 && size.Height >= 256)
|
|
{
|
|
logger.Trace($"ShortcutItem/ToIconOverlay: The image is > 256px x 256px so making it a PNG layer in the icon file.");
|
|
icon[icon.Count - 1].IconImageFormat = IconImageFormat.PNG;
|
|
}
|
|
|
|
logger.Trace($"ShortcutItem/ToIconOverlay: Disposing of the Bitmap data we just used as the source (stops memory leaks).");
|
|
bitmapOverlay.Dispose();
|
|
}
|
|
|
|
logger.Trace($"ShortcutItem/ToIconOverlay: Make the top layer image of the Multi image icon the default one.");
|
|
multiIcon.SelectedIndex = 0;
|
|
|
|
return multiIcon;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Warn(ex, $"ShortcutItem/ToIconOverlay: Exeception occurred while trying to convert the Shortcut Bitmap to an Icon Overlay to store in the shortcut cache directory. Returning null");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
[DllImport("Shell32", CharSet = CharSet.Auto)]
|
|
private static extern int ExtractIconEx(string lpszFile, int nIconIndex, IntPtr[] phIconLarge, IntPtr[] phIconSmall, int nIcons);
|
|
|
|
[DllImport("user32.dll", EntryPoint = "DestroyIcon", SetLastError = true)]
|
|
private static extern int DestroyIcon(IntPtr hIcon);
|
|
|
|
public static List<Icon> ExtractIconsFromExe(string file, bool large)
|
|
{
|
|
int readIconCount = 0;
|
|
IntPtr[] hLargeIconEx = new IntPtr[] { IntPtr.Zero };
|
|
IntPtr[] hSmallIconEx = new IntPtr[] { IntPtr.Zero };
|
|
|
|
try
|
|
{
|
|
List<Icon> extractedIcons = new List<Icon>() { };
|
|
// First we get the total number of icons using ExtractIconEx
|
|
int totalIconCount = ExtractIconEx(file, -1, null, null, 0);
|
|
if (totalIconCount > 0)
|
|
{
|
|
for (int iconNum = 0; iconNum < totalIconCount; iconNum++)
|
|
{
|
|
hLargeIconEx = new IntPtr[] { IntPtr.Zero };
|
|
hSmallIconEx = new IntPtr[] { IntPtr.Zero };
|
|
//if (large)
|
|
//readIconCount = ExtractIconEx(file, 0, hIconEx, hDummy, 1);
|
|
// readIconCount = ExtractIconEx(file, iconNum, hIconEx, null, 1);
|
|
//else
|
|
//readIconCount = ExtractIconEx(file, 0, hDummy, hIconEx, 1);
|
|
// readIconCount = ExtractIconEx(file, iconNum, null, hIconEx, 1);
|
|
|
|
readIconCount = ExtractIconEx(file, iconNum, hLargeIconEx, hSmallIconEx, 1);
|
|
|
|
if (readIconCount > 0)
|
|
{
|
|
if (hLargeIconEx[0] != IntPtr.Zero)
|
|
{
|
|
Icon extractedIcon = (Icon)Icon.FromHandle(hLargeIconEx[0]).Clone();
|
|
extractedIcons.Add(extractedIcon);
|
|
}
|
|
else if (hSmallIconEx[0] != IntPtr.Zero)
|
|
{
|
|
Icon extractedIcon = (Icon)Icon.FromHandle(hSmallIconEx[0]).Clone();
|
|
extractedIcons.Add(extractedIcon);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*foreach (IntPtr ptr in hLargeIconEx)
|
|
if (ptr != IntPtr.Zero)
|
|
DestroyIcon(ptr);
|
|
|
|
foreach (IntPtr ptr in hSmallIconEx)
|
|
if (ptr != IntPtr.Zero)
|
|
DestroyIcon(ptr);*/
|
|
|
|
return extractedIcons;
|
|
}
|
|
else
|
|
return null;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
/* EXTRACT ICON ERROR */
|
|
|
|
// BUBBLE UP
|
|
throw new ApplicationException("Could not extract icon", ex);
|
|
}
|
|
finally
|
|
{
|
|
// RELEASE RESOURCES
|
|
foreach (IntPtr ptr in hLargeIconEx)
|
|
if (ptr != IntPtr.Zero)
|
|
DestroyIcon(ptr);
|
|
|
|
foreach (IntPtr ptr in hSmallIconEx)
|
|
if (ptr != IntPtr.Zero)
|
|
DestroyIcon(ptr);
|
|
}
|
|
|
|
}
|
|
|
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
private static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType,
|
|
int cxDesired, int cyDesired, uint fuLoad);
|
|
|
|
/*[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern int DestroyIcon(IntPtr hIcon);*/
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, LoadLibraryFlags dwFlags);
|
|
|
|
private enum LoadLibraryFlags : uint
|
|
{
|
|
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
|
|
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
|
|
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
|
|
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
|
|
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
|
|
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an icon of given size.
|
|
/// </summary>
|
|
/// <param name="path">Path to a file (.exe/.dll) that contains the icons.
|
|
/// Skip it or use <c>null</c> to use current application's file.</param>
|
|
/// <param name="resId">Name of the resource icon that should be loaded.
|
|
/// Skip it to use the default <c>#32512</c> (value of <c>IDI_APPLICATION</c>) to use
|
|
/// the application's icon.</param>
|
|
/// <param name="size">Size of the icon to load. If there is no such size available, a larger or smaller
|
|
/// sized-icon is scaled.</param>
|
|
/// <returns>List of all icons.</returns>
|
|
public static Icon GetIconFromExe(string path = null, int size = 256, string resId = "#32512")
|
|
{
|
|
// load module
|
|
IntPtr h;
|
|
if (path == null)
|
|
//h = Marshal.GetHINSTANCE(Assembly.GetEntryAssembly().GetModules()[0]);
|
|
return null;
|
|
else
|
|
{
|
|
h = LoadLibraryEx(path, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE);
|
|
if (h == IntPtr.Zero)
|
|
return null;
|
|
}
|
|
|
|
// 1 is IMAGE_ICON
|
|
IntPtr ptr = LoadImage(h, resId, 1, size, size, 0);
|
|
if (ptr != IntPtr.Zero)
|
|
{
|
|
try
|
|
{
|
|
Icon icon = (Icon)Icon.FromHandle(ptr).Clone();
|
|
return icon;
|
|
}
|
|
finally
|
|
{
|
|
DestroyIcon(ptr);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|