| File: System\Windows\Forms\SystemDrawingExtensions.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Primitives\src\System.Windows.Forms.Primitives.csproj (System.Windows.Forms.Primitives) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.CompilerServices; using Microsoft.Win32; namespace System.Windows.Forms; internal static class SystemDrawingExtensions { internal static HBITMAP GetHBITMAP(this Bitmap bitmap) => (HBITMAP)bitmap.GetHbitmap(); internal static HFONT ToHFONT(this Font font) => (HFONT)font.ToHfont(); /// <summary> /// Similar to <see cref="Graphics.GetNearestColor(Color)"/>, but this retains the original color if the color /// didn't actually change. This retains the state of the color. /// </summary> /// <remarks> /// <para> /// This is important as the color only changes if <paramref name="graphics"/> has a very low color depth. This /// is extremely rare for the normal case of HDC backed Graphics objects. Keeping the original color keeps the /// state that would otherwise be stripped, notably things like <see cref="Color.IsKnownColor"/> which allows /// us to later pull from a the various caches that <see cref="Drawing"/> maintains (saving allocations). /// </para> /// <para> /// Ideally we'd drop checking at all and just support full color drawing to improve performance for the /// expected normal case (more than 8 BITSPIXEL for the HDC). /// </para> /// </remarks> internal static Color FindNearestColor(this Graphics graphics, Color color) { Color newColor = graphics.GetNearestColor(color); return newColor.ToArgb() == color.ToArgb() ? color : newColor; } /// <summary> /// Returns true if the color has any transparency. If false, the color is fully opaque. /// </summary> internal static bool HasTransparency(this Color color) => color.A != byte.MaxValue; /// <summary> /// Returns true if the color is fully transparent. /// </summary> internal static bool IsFullyTransparent(this Color color) => color.A == 0; /// <summary> /// Draws lines with the <paramref name="pen"/> using points defined in <paramref name="lines"/>. /// </summary> /// <param name="lines"> /// MUST be a multiple of 4. Each group of 4 represents x1, y1, x2, y2. /// </param> internal static void DrawLines(this Graphics graphics, Pen pen, ReadOnlySpan<int> lines) { Debug.Assert((lines.Length % 4) == 0); for (int i = 0; i < lines.Length; i += 4) { graphics.DrawLine(pen, lines[i], lines[i + 1], lines[i + 2], lines[i + 3]); } } /// <summary> /// Mixes two colors. /// </summary> [SkipLocalsInit] internal static Color MixColor(this Color color1, Color color2) { // Some colors look up their values on every property access so we'll get the value out ARGB argb1 = color1; ARGB argb2 = color2; return Color.FromArgb( (argb1.A + argb2.A) / 2, (argb1.R + argb2.R) / 2, (argb1.G + argb2.G) / 2, (argb1.B + argb2.B) / 2); } /// <summary> /// Inverts the color. /// </summary> internal static Color InvertColor(this Color color) { ARGB argb = color; return Color.FromArgb(argb.A, (byte)~argb.R, (byte)~argb.G, (byte)~argb.B); } /// <summary> /// Creates a <see cref="Pen"/>. If <paramref name="color"/> is a system color, makes a static copy of the /// current color value to avoid having the pen hook itself against <see cref="SystemEvents"/>. /// </summary> internal static Pen CreateStaticPen(this Color color, DashStyle dashStyle) { if (dashStyle == DashStyle.Solid) { // Solid is the default and faster than setting the property return color.IsSystemColor ? new Pen((ARGB)color) : new Pen(color); } return color.IsSystemColor ? new Pen(Color.FromArgb(color.ToArgb())) { DashStyle = dashStyle } : new Pen(color) { DashStyle = dashStyle }; } /// <summary> /// Not strictly needed (yet), but allows using the same pattern for all pens. /// </summary> internal static Pen CreateStaticPen(this Brush brush, float width = 1.0f) => new(brush, width); /// <summary> /// Creates a <see cref="SolidBrush"/>. If <paramref name="color"/> is a system color, makes a static copy of /// the current color value to avoid having the pen hook itself against <see cref="SystemEvents"/>. /// </summary> internal static SolidBrush CreateStaticBrush(this Color color) => color.IsSystemColor ? new SolidBrush(Color.FromArgb(color.ToArgb())) : new SolidBrush(color); }