DisplayMagician/DisplayMagicianShared/ProfileIcon.cs

521 lines
19 KiB
C#
Raw Normal View History

2017-02-26 19:23:31 +00:00
using System;
using System.Collections.Generic;
2017-02-26 19:23:31 +00:00
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.IconLib;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using DisplayMagicianShared.Topology;
//using static DisplayMagicianShared.ProfileItem;
2017-02-26 19:23:31 +00:00
namespace DisplayMagicianShared
2017-02-26 19:23:31 +00:00
{
public class ProfileIcon
{
private ProfileItem _profile;
public ProfileIcon(ProfileItem profile, int paddingX = 100, int paddingY = 100)
2017-02-26 19:23:31 +00:00
{
_profile = profile;
2017-02-26 19:23:31 +00:00
PaddingX = paddingX;
PaddingY = paddingY;
}
public int PaddingX { get; }
public int PaddingY { get; }
//public Profile Profile { get; }
2017-02-26 19:23:31 +00:00
2018-10-20 00:08:30 +00:00
// ReSharper disable once TooManyArguments
2017-02-26 19:23:31 +00:00
public static RectangleF CalculateViewSize(
List<ScreenPosition> screens,
int outsidePaddingSides = 0,
int outsidePaddingTopBottom = 0)
2017-02-26 19:23:31 +00:00
{
var minX = 0;
var maxX = 0;
var minY = 0;
var maxY = 0;
2018-10-20 00:27:25 +00:00
foreach (var screen in screens)
2017-02-26 19:23:31 +00:00
{
//var res = GetLargestResolution(screens);
minX = Math.Min(minX, screen.ScreenX);
maxX = Math.Max(maxX, screen.ScreenX + screen.ScreenWidth);
minY = Math.Min(minY, screen.ScreenY);
maxY = Math.Max(maxY, screen.ScreenY + screen.ScreenHeight);
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
if (outsidePaddingSides != 0)
2017-02-26 19:23:31 +00:00
{
minX -= outsidePaddingSides;
maxX += outsidePaddingSides;
minY -= outsidePaddingTopBottom;
maxY += outsidePaddingTopBottom;
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
var size = new SizeF(Math.Abs(minX) + maxX, Math.Abs(minY) + maxY);
var rect = new RectangleF(new PointF(minX, minY), size);
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
return rect;
}
/*public static Size GetLargestResolution(List<ScreenPosition> screens)
2017-02-26 19:23:31 +00:00
{
Size largest = Size.Empty;
2018-10-20 00:27:25 +00:00
foreach (ScreenPosition screen in screens)
2017-02-26 19:23:31 +00:00
{
if ((ulong)screen.ScreenWidth * (ulong)screen.ScreenHeight > (ulong)largest.Width * (ulong)largest.Height)
2018-10-20 00:27:25 +00:00
{
largest = new Size(screen.ScreenWidth, screen.ScreenHeight);
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
return largest;
}*/
2017-02-26 19:23:31 +00:00
/// <summary>
/// Creates a rounded rectangle path
/// By @taffer
/// https://stackoverflow.com/questions/33853434/how-to-draw-a-rounded-rectangle-in-c-sharp
/// </summary>
public static GraphicsPath RoundedRect(RectangleF bounds, float radius)
{
2018-10-20 00:27:25 +00:00
var diameter = radius * 2;
2017-02-26 19:23:31 +00:00
var size = new SizeF(diameter, diameter);
var arc = new RectangleF(bounds.Location, size);
var path = new GraphicsPath();
if (radius < 0.01)
{
path.AddRectangle(bounds);
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
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();
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
return path;
}
public Bitmap ToBitmap(int width = 256, int height = 256, PixelFormat format = PixelFormat.Format32bppArgb)
2017-02-26 19:23:31 +00:00
{
var bitmap = new Bitmap(width, height, format);
bitmap.MakeTransparent();
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
using (var g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = SmoothingMode.HighQuality;
DrawView(g, width, height);
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
return bitmap;
}
public Bitmap ToTightestBitmap(int width = 256, int height = 0, PixelFormat format = PixelFormat.Format32bppArgb)
2017-02-26 19:23:31 +00:00
{
var viewSize = CalculateViewSize(_profile.Screens, 0, 0);
int viewSizeRatio = Convert.ToInt32(viewSize.Width / viewSize.Height);
if (height == 0)
height = width / viewSizeRatio;
var bitmap = new Bitmap(width, height, format);
bitmap.MakeTransparent();
using (var g = Graphics.FromImage(bitmap))
2017-02-26 19:23:31 +00:00
{
g.SmoothingMode = SmoothingMode.HighQuality;
DrawView(g, width, height);
}
return bitmap;
}
public Bitmap ToBitmapOverlay(Bitmap bitmap)
{
/* if (width == 0)
width = bitmap.Width;
if (height == 0)
height = bitmap.Height;
var viewSize = CalculateViewSize(_profile.Viewports, true, PaddingX, PaddingY);
int viewSizeRatio = (int) Math.Round(viewSize.Width / viewSize.Height);
int overlayWidth = (int) Math.Round(width * 0.7f,0);
int overlayHeight = overlayWidth / viewSizeRatio;
int overlayX = width - overlayWidth;
int overlayY = height - overlayHeight;
Point overlayPosition = new Point(overlayX, overlayY);
Size overlaySize = new Size(overlayWidth, overlayHeight);
Rectangle overlayRect = new Rectangle(overlayPosition, overlaySize);
//var width = bitmap.Width * 0.7f;
//var height = width / viewSize.Width * viewSize.Height;
var combinedBitmap = new Bitmap(width, height, format);
combinedBitmap.MakeTransparent();
using (var g = Graphics.FromImage(combinedBitmap))
{
g.SmoothingMode = SmoothingMode.HighQuality;
//g.DrawImage(bitmap, 0, 0, width, height);
g.TranslateTransform(overlayX, overlayY);
//Rectangle compressionRectangle = new Rectangle(300, 10,
//myBitmap.Width / 2, myBitmap.Height / 2);
g.DrawRectangle(new Pen(Color.FromArgb(125, 50, 50, 50), 2f), overlayRect);
DrawView(g, overlayWidth, overlayHeight);
}
return bitmap;*/
var viewSize = CalculateViewSize(_profile.Screens, PaddingX, PaddingY);
var width = bitmap.Width * 0.7f;
var height = width / viewSize.Width * viewSize.Height;
using (var g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.TranslateTransform(bitmap.Width - width, bitmap.Height - height * 1.1f);
DrawView(g, width, height);
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
return bitmap;
}
public MultiIcon ToIcon()
{
var 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)
};
var multiIcon = new MultiIcon();
var icon = multiIcon.Add("Icon1");
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
foreach (var size in iconSizes)
{
icon.Add(ToBitmap(size.Width, size.Height));
2018-10-20 00:27:25 +00:00
if (size.Width >= 256 && size.Height >= 256)
{
2017-02-26 19:23:31 +00:00
icon[icon.Count - 1].IconImageFormat = IconImageFormat.PNG;
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
multiIcon.SelectedIndex = 0;
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
return multiIcon;
}
public MultiIcon ToIconOverlay(string iconAddress)
2017-02-26 19:23:31 +00:00
{
var multiIcon = new MultiIcon();
var icon = multiIcon.Add("Icon1");
var mainIcon = new MultiIcon();
mainIcon.Load(iconAddress);
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
foreach (var singleIcon in mainIcon[0].Where(image =>
2018-10-20 00:27:25 +00:00
image.PixelFormat == PixelFormat.Format16bppRgb565 ||
image.PixelFormat == PixelFormat.Format24bppRgb ||
image.PixelFormat == PixelFormat.Format32bppArgb)
2017-02-26 19:23:31 +00:00
.OrderByDescending(
image =>
image.PixelFormat == PixelFormat.Format16bppRgb565
? 1
2018-10-20 00:27:25 +00:00
: image.PixelFormat == PixelFormat.Format24bppRgb
? 2
: 3)
.ThenByDescending(image => image.Size.Width * image.Size.Height))
2017-02-26 19:23:31 +00:00
{
2018-10-20 00:27:25 +00:00
if (!icon.All(i => singleIcon.Size != i.Size || singleIcon.PixelFormat != i.PixelFormat))
{
2017-02-26 19:23:31 +00:00
continue;
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
var bitmap = singleIcon.Icon.ToBitmap();
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
if (bitmap.PixelFormat != singleIcon.PixelFormat)
{
var clone = new Bitmap(bitmap.Width, bitmap.Height, singleIcon.PixelFormat);
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
using (var gr = Graphics.FromImage(clone))
{
gr.DrawImage(bitmap, new Rectangle(0, 0, clone.Width, clone.Height));
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
bitmap.Dispose();
bitmap = clone;
}
2018-10-20 00:27:25 +00:00
icon.Add(singleIcon.Size.Height * singleIcon.Size.Width < 24 * 24 ? bitmap : ToBitmapOverlay(bitmap));
2018-10-20 00:27:25 +00:00
if (singleIcon.Size.Width >= 256 && singleIcon.Size.Height >= 256)
{
2017-02-26 19:23:31 +00:00
icon[icon.Count - 1].IconImageFormat = IconImageFormat.PNG;
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
bitmap.Dispose();
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
if (icon.Count == 0)
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
throw new ArgumentException();
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
multiIcon.SelectedIndex = 0;
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
return multiIcon;
}
/*private void DrawSingleScreen(Graphics g, ScreenPosition screen)
2017-02-26 19:23:31 +00:00
{
//var res = NormalizeResolution(screen);
Rectangle rect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
int rows = rect.Width < rect.Height ? path.TargetDisplays.Length : 1;
int cols = rect.Width >= rect.Height ? path.TargetDisplays.Length : 1;
2018-10-20 00:27:25 +00:00
2020-05-12 10:46:23 +00:00
for (var i = 0; i < path.TargetDisplays.Length; i++)
2018-10-20 00:27:25 +00:00
{
DrawTarget(g, screen, path.TargetDisplays[i],
new Rectangle(
rect.X + PaddingX,
rect.Y + PaddingY,
rect.Width - 2 * PaddingX,
rect.Height - 2 * PaddingY),
rows > 1 ? i : 0, cols > 1 ? i : 0, rows, cols);
}
}*/
/*private void DrawScreen(Graphics g, ScreenPosition screen)
{
//var res = NormalizeResolution(screen);
Rectangle rect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
int rows = rect.Width < rect.Height ? screen.SpannedScreens.Count : 1;
int cols = rect.Width >= rect.Height ? screen.SpannedScreens.Count : 1;
for(var i = 0; i < screen.SpannedScreens.Count ; i++)
{
DrawTarget(g, screen,
2017-02-26 19:23:31 +00:00
new Rectangle(
rect.X + PaddingX,
rect.Y + PaddingY,
2018-10-20 00:27:25 +00:00
rect.Width - 2 * PaddingX,
rect.Height - 2 * PaddingY),
2017-02-26 19:23:31 +00:00
rows > 1 ? i : 0, cols > 1 ? i : 0, rows, cols);
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:08:30 +00:00
// ReSharper disable once TooManyArguments
2018-10-20 00:27:25 +00:00
private void DrawTarget(
Graphics g,
ScreenPosition screen,
2018-10-20 00:27:25 +00:00
Rectangle rect,
int row,
int col,
int rows,
2017-02-26 19:23:31 +00:00
int cols)
{
2018-10-20 00:27:25 +00:00
var targetSize = new Size(rect.Width / cols, rect.Height / rows);
var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y);
2017-02-26 19:23:31 +00:00
var targetRect = new Rectangle(targetPosition, targetSize);
if (screen.IsSpanned)
2018-10-20 00:27:25 +00:00
{
g.FillRectangle(new SolidBrush(screen.Colour), targetRect);
2018-10-20 00:27:25 +00:00
}
else if (screen.SpannedScreens.Count > 1)
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 255, 97, 27)), targetRect);
2018-10-20 00:27:25 +00:00
}
else if (!screen.IsSpanned)
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 0, 174, 241)), targetRect);
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
else
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 155, 155, 155)), targetRect);
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
g.DrawRectangle(new Pen(Color.FromArgb(125, 50, 50, 50), 2f), targetRect);
}
private void DrawView(Graphics g, float width, float height)
{
var viewSize = CalculateViewSize(_profile.Screens, PaddingX, PaddingY);
2018-10-20 00:27:25 +00:00
var standPadding = height * 0.005f;
height -= standPadding * 8;
var factor = Math.Min((width - 2 * standPadding - 1) / viewSize.Width,
(height - 2 * standPadding - 1) / viewSize.Height);
2017-02-26 19:23:31 +00:00
g.ScaleTransform(factor, factor);
2018-10-20 00:27:25 +00:00
var xOffset = ((width - 1) / factor - viewSize.Width) / 2f;
var yOffset = ((height - 1) / factor - viewSize.Height) / 2f;
2017-02-26 19:23:31 +00:00
g.TranslateTransform(-viewSize.X + xOffset, -viewSize.Y + yOffset);
2018-10-20 00:27:25 +00:00
if (standPadding * 6 >= 1)
2017-02-26 19:23:31 +00:00
{
2018-10-20 00:27:25 +00:00
using (var boundRect = RoundedRect(viewSize, 2 * standPadding / factor))
2017-02-26 19:23:31 +00:00
{
g.FillPath(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), boundRect);
2018-10-20 00:27:25 +00:00
g.DrawPath(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding / factor), boundRect);
2017-02-26 19:23:31 +00:00
}
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
using (
var boundRect =
RoundedRect(
2018-10-20 00:27:25 +00:00
new RectangleF(viewSize.Width * 0.375f + viewSize.X,
viewSize.Height + standPadding / factor,
viewSize.Width / 4, standPadding * 7 / factor), 2 * standPadding / factor))
2017-02-26 19:23:31 +00:00
{
g.FillPath(new SolidBrush(Color.FromArgb(250, 50, 50, 50)), boundRect);
2018-10-20 00:27:25 +00:00
g.DrawPath(new Pen(Color.FromArgb(50, 255, 255, 255), 2 / factor), boundRect);
2017-02-26 19:23:31 +00:00
}
}
else
{
g.FillRectangle(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), viewSize);
2018-10-20 00:27:25 +00:00
g.DrawRectangle(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding / factor), viewSize.X, viewSize.Y,
2017-02-26 19:23:31 +00:00
viewSize.Width, viewSize.Height);
}
foreach (ScreenPosition screen in _profile.Screens)
2018-10-20 00:27:25 +00:00
{
DrawScreen(g, screen);
2018-10-20 00:27:25 +00:00
}
}*/
private void DrawView(Graphics g, float width, float height)
{
// 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);
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;
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)
{
using (var boundRect = RoundedRect(viewSize, 2 * standPadding / factor))
{
g.FillPath(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), boundRect);
g.DrawPath(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding / 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);
}
// Now go through and draw the screens
foreach (ScreenPosition screen in _profile.Screens)
{
Color screenBgColour;
Color lightTextColour = Color.White;
Color darkTextColour = Color.Black;
// draw the screen
if (screen.IsSpanned)
{
//g.FillRectangle(new SolidBrush(Color.FromArgb(150, 106, 185, 0)), targetRect);
}
else
{
// Draw the outline of the monitor
Rectangle outlineRect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 33, 33, 33)), outlineRect);
g.DrawRectangle(Pens.Black, outlineRect);
// Draw the screen of the monitor
Rectangle screenRect = new Rectangle(screen.ScreenX + screenBezel, screen.ScreenY + screenBezel, screen.ScreenWidth - (screenBezel * 2), screen.ScreenHeight - (screenBezel * 2));
if (screen.Colour != null)
{
screenBgColour = screen.Colour;
}
else
{
screenBgColour = Color.FromArgb(255, 155, 155, 155);
}
g.FillRectangle(new SolidBrush(screenBgColour), screenRect);
g.DrawRectangle(Pens.Black, screenRect);
}
}
}
private Color pickTextColorBasedOnBgColour(Color bgColour, Color lightColour, Color darkColour)
{
if ((bgColour.R * 0.299 + bgColour.G * 0.587 + bgColour.B * 0.114) > 186)
{
return darkColour;
}
else
{
return lightColour;
}
}
private Bitmap pickBitmapBasedOnBgColour(Color bgColour, Bitmap lightBitmap, Bitmap darkBitmap)
{
if ((bgColour.R * 0.299 + bgColour.G * 0.587 + bgColour.B * 0.114) > 186)
{
return darkBitmap;
}
else
{
return lightBitmap;
}
2017-02-26 19:23:31 +00:00
}
}
}