From ae7bb095e2c54c2d895a9d1795624330bce8b93c Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Tue, 19 Apr 2022 21:12:00 +1200 Subject: [PATCH] Revamped display layout image shortcut generation Made many changes to simplify the configuration and make the profile display layout image generation faster and more reliable. --- DisplayMagician/ImageUtils.cs | 8 +- DisplayMagician/Properties/AssemblyInfo.cs | 4 +- DisplayMagician/ShortcutItem.cs | 4 +- DisplayMagicianShared/ProfileIcon.cs | 120 +++++++++++++++------ DisplayMagicianShared/ProfileItem.cs | 3 +- 5 files changed, 98 insertions(+), 41 deletions(-) diff --git a/DisplayMagician/ImageUtils.cs b/DisplayMagician/ImageUtils.cs index b02b3dd..b725fc3 100644 --- a/DisplayMagician/ImageUtils.cs +++ b/DisplayMagician/ImageUtils.cs @@ -407,7 +407,8 @@ namespace DisplayMagician return string.Equals(image164, image264); } - public static Bitmap ToBitmapOverlay(Bitmap originalBitmap, Bitmap overlayBitmap, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb) + + public static Bitmap MakeBitmapOverlay(Bitmap originalBitmap, Bitmap overlayBitmap, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb) { if (originalBitmap == null) { @@ -468,6 +469,8 @@ namespace DisplayMagician 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); + // Now we need to adjust that slightly up and in a bit + overlayBitmapNewLocation.Offset(0, -5); 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); @@ -482,6 +485,7 @@ namespace DisplayMagician } +/* #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 @@ -534,7 +538,7 @@ namespace DisplayMagician 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); diff --git a/DisplayMagician/Properties/AssemblyInfo.cs b/DisplayMagician/Properties/AssemblyInfo.cs index 3725b09..1414e69 100644 --- a/DisplayMagician/Properties/AssemblyInfo.cs +++ b/DisplayMagician/Properties/AssemblyInfo.cs @@ -26,8 +26,8 @@ using System.Resources; [assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")] // Version information -[assembly: AssemblyVersion("2.3.1.28")] -[assembly: AssemblyFileVersion("2.3.1.28")] +[assembly: AssemblyVersion("2.3.1.40")] +[assembly: AssemblyFileVersion("2.3.1.40")] [assembly: NeutralResourcesLanguageAttribute( "en" )] [assembly: CLSCompliant(true)] diff --git a/DisplayMagician/ShortcutItem.cs b/DisplayMagician/ShortcutItem.cs index 088c6c9..b8c2a77 100644 --- a/DisplayMagician/ShortcutItem.cs +++ b/DisplayMagician/ShortcutItem.cs @@ -938,7 +938,7 @@ namespace DisplayMagician // We create the Bitmaps for the game _originalBitmap = selectedImage.Image; // Now we use the originalBitmap or userBitmap, and create the shortcutBitmap from it - _shortcutBitmap = ImageUtils.ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ImageUtils.MakeBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); // Empty out the unused shortcut data _executableNameAndPath = ""; @@ -1017,7 +1017,7 @@ namespace DisplayMagician // We create the Bitmaps for the executable _originalBitmap = selectedImage.Image; // Now we use the originalBitmap or userBitmap, and create the shortcutBitmap from it - _shortcutBitmap = ImageUtils.ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); + _shortcutBitmap = ImageUtils.MakeBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256); // Empty out the unused shortcut data _gameAppId = ""; diff --git a/DisplayMagicianShared/ProfileIcon.cs b/DisplayMagicianShared/ProfileIcon.cs index 2e15c2c..9db2d68 100644 --- a/DisplayMagicianShared/ProfileIcon.cs +++ b/DisplayMagicianShared/ProfileIcon.cs @@ -36,6 +36,12 @@ namespace DisplayMagicianShared var minY = 0; var maxY = 0; + // If there aren't any screens provided then return a blank rectangle + if (screens.Count == 0) + { + return new RectangleF(0, 0, 0, 0); + } + foreach (var screen in screens) { //var res = GetLargestResolution(screens); @@ -49,11 +55,18 @@ namespace DisplayMagicianShared { minX -= outsidePaddingSides; maxX += outsidePaddingSides; + } + + if (outsidePaddingTopBottom != 0) + { minY -= outsidePaddingTopBottom; maxY += outsidePaddingTopBottom; } - var size = new SizeF(Math.Abs(minX) + maxX, Math.Abs(minY) + maxY); + var width = Math.Abs(maxX - minX); + var height = Math.Abs(maxY - minY); + + var size = new SizeF(width, height); var rect = new RectangleF(new PointF(minX, minY), size); return rect; @@ -107,15 +120,39 @@ namespace DisplayMagicianShared using (var g = Graphics.FromImage(bitmap)) { g.SmoothingMode = SmoothingMode.HighQuality; - DrawView(g, width, height); + DrawDisplayLayout(g, width, height); } return bitmap; } - public Bitmap ToTightestBitmap(int width = 256, int height = 256, PixelFormat format = PixelFormat.Format32bppArgb) + public Bitmap ToTightestBitmap(PixelFormat format = PixelFormat.Format32bppArgb) { + if (_profile.Screens.Count == 0) + { + return new Bitmap(0, 0); + } + var viewSize = CalculateViewSize(_profile.Screens, 0, 0); + + var bitmap = new Bitmap((int)viewSize.Width, (int)viewSize.Height, format); + bitmap.MakeTransparent(); + + using (var g = Graphics.FromImage(bitmap)) + { + g.SmoothingMode = SmoothingMode.HighQuality; + DrawDisplayLayout(g, (int)viewSize.Width, (int)viewSize.Height, false); + } + + return bitmap; + } + + public Bitmap ToTightestBitmap(int width, int height, PixelFormat format = PixelFormat.Format32bppArgb) + { + if (_profile.Screens.Count == 0) + { + return new Bitmap(0, 0); + } var bitmap = new Bitmap(width, height, format); bitmap.MakeTransparent(); @@ -123,14 +160,19 @@ namespace DisplayMagicianShared using (var g = Graphics.FromImage(bitmap)) { g.SmoothingMode = SmoothingMode.HighQuality; - DrawView(g, width, height); + DrawDisplayLayout(g, width, height, false); } return bitmap; } - public Bitmap ToBitmapOverlay(Bitmap bitmap) + /*public Bitmap ToBitmapOverlay(Bitmap bitmap) { + if (_profile.Screens.Count == 0) + { + return new Bitmap(0, 0); + } + var viewSize = CalculateViewSize(_profile.Screens, PaddingX, PaddingY); var width = bitmap.Width * 0.7f; var height = width / viewSize.Width * viewSize.Height; @@ -139,11 +181,11 @@ namespace DisplayMagicianShared { g.SmoothingMode = SmoothingMode.HighQuality; g.TranslateTransform(bitmap.Width - width, bitmap.Height - height * 1.1f); - DrawView(g, width, height); + DrawDisplayLayout(g, width, height); } return bitmap; - } + }*/ public MultiIcon ToIcon() { @@ -174,7 +216,7 @@ namespace DisplayMagicianShared return multiIcon; } - public MultiIcon ToIconOverlay(string iconAddress) + /*public MultiIcon ToIconOverlay(string iconAddress) { var multiIcon = new MultiIcon(); var icon = multiIcon.Add("Icon1"); @@ -232,48 +274,58 @@ namespace DisplayMagicianShared multiIcon.SelectedIndex = 0; return multiIcon; - } + }*/ - private void DrawView(Graphics g, float width, float height) + private void DrawDisplayLayout(Graphics g, float maxWidth, float maxHeight, bool drawStand = true) { + // If we don't have any screens, then we can't draw them! + if (_profile.Screens.Count == 0) + { + return; + } + // Figure out the sizes we need based on the total size of the screens - var viewSize = ProfileIcon.CalculateViewSize(_profile.Screens, PaddingX, PaddingY); - var standPadding = height * 0.005f; - height -= standPadding * 8; - var factor = Math.Min((width - 2 * standPadding - 1) / viewSize.Width, - (height - 2 * standPadding - 1) / viewSize.Height); + var viewSize = ProfileIcon.CalculateViewSize(_profile.Screens, PaddingX, PaddingY); + + var standPadding = maxHeight * 0.005f; + maxHeight -= standPadding * 8; + var factor = Math.Min((maxWidth - 2 * standPadding - 1) / viewSize.Width, + (maxHeight - 2 * standPadding - 1) / viewSize.Height); g.ScaleTransform(factor, factor); // Make space for the stand - var xOffset = ((width - 1) / factor - viewSize.Width) / 2f; - var yOffset = ((height - 1) / factor - viewSize.Height) / 2f; + var xOffset = ((maxWidth - 1) / factor - viewSize.Width) / 2f; + var yOffset = ((maxHeight - 1) / factor - viewSize.Height) / 2f; g.TranslateTransform(-viewSize.X + xOffset, -viewSize.Y + yOffset); // How wide the Bezel is on the screen graphics int screenBezel = 60; //int screenWordBuffer = 30; - // Draw the stand - if (standPadding * 6 >= 1) + // Draw the stand if needed + if (drawStand) { - using ( - var boundRect = - RoundedRect( - new RectangleF(viewSize.Width * 0.375f + viewSize.X, - viewSize.Height + standPadding / factor, - viewSize.Width / 4, standPadding * 7 / factor), 2 * standPadding / factor)) + if (standPadding * 6 >= 1) { - g.FillPath(new SolidBrush(Color.FromArgb(250, 50, 50, 50)), boundRect); - g.DrawPath(new Pen(Color.FromArgb(50, 255, 255, 255), 2 / factor), boundRect); + using ( + var boundRect = + RoundedRect( + new RectangleF(viewSize.Width * 0.375f + viewSize.X, + viewSize.Height + standPadding / factor, + viewSize.Width / 4, standPadding * 7 / factor), 2 * standPadding / factor)) + { + g.FillPath(new SolidBrush(Color.FromArgb(250, 50, 50, 50)), boundRect); + g.DrawPath(new Pen(Color.FromArgb(50, 255, 255, 255), 2 / factor), boundRect); + } } - } - else - { - g.FillRectangle(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), viewSize); - g.DrawRectangle(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding / factor), viewSize.X, viewSize.Y, - viewSize.Width, viewSize.Height); - } + else + { + g.FillRectangle(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), viewSize); + g.DrawRectangle(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding / factor), viewSize.X, viewSize.Y, + viewSize.Width, viewSize.Height); + } + } // Now go through and draw the screens foreach (ScreenPosition screen in _profile.Screens) diff --git a/DisplayMagicianShared/ProfileItem.cs b/DisplayMagicianShared/ProfileItem.cs index e5e4cb0..8fa1e83 100644 --- a/DisplayMagicianShared/ProfileItem.cs +++ b/DisplayMagicianShared/ProfileItem.cs @@ -357,7 +357,8 @@ namespace DisplayMagicianShared return _profileShortcutBitmap; else { - _profileShortcutBitmap = this.ProfileIcon.ToTightestBitmap(256, 256); + //_profileShortcutBitmap = this.ProfileIcon.ToTightestBitmap(); + _profileShortcutBitmap = this.ProfileIcon.ToTightestBitmap(); return _profileShortcutBitmap; } }