ExtensionMethods.cs (8336B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // The Command & Conquer Map Editor and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // The Command & Conquer Map Editor and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 using System; 16 using System.Collections.Generic; 17 using System.ComponentModel; 18 using System.Drawing; 19 using System.Drawing.Imaging; 20 using System.Linq; 21 using System.Reflection; 22 using System.Runtime.InteropServices; 23 24 namespace MobiusEditor.Utility 25 { 26 public static class ExtensionMethods 27 { 28 public static float ToLinear(this float v) 29 { 30 return (v < 0.04045f) ? (v * 25.0f / 323.0f) : (float)Math.Pow(((200.0f * v) + 11.0f) / 211.0f, 12.0f / 5.0f); 31 } 32 33 public static float ToLinear(this byte v) 34 { 35 return (v / 255.0f).ToLinear(); 36 } 37 38 public static float ToSRGB(this float v) 39 { 40 return (v < 0.0031308) ? (v * 323.0f / 25.0f) : ((((float)Math.Pow(v, 5.0f / 12.0f) * 211.0f) - 11.0f) / 200.0f); 41 } 42 43 public static void SetDefault<T>(this T data) 44 { 45 var properties = data.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetSetMethod() != null); 46 foreach (var property in properties) 47 { 48 if (property.GetCustomAttribute(typeof(DefaultValueAttribute)) is DefaultValueAttribute defaultValueAttr) 49 { 50 property.SetValue(data, defaultValueAttr.Value); 51 } 52 } 53 } 54 55 public static void CopyTo<T>(this T data, T other) 56 { 57 var properties = data.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => (p.GetSetMethod() != null) && (p.GetGetMethod() != null)); 58 foreach (var property in properties) 59 { 60 var defaultValueAttr = property.GetCustomAttribute(typeof(DefaultValueAttribute)) as DefaultValueAttribute; 61 property.SetValue(other, property.GetValue(data)); 62 } 63 } 64 65 public static IEnumerable<Point> Points(this Rectangle rectangle) 66 { 67 for (var y = rectangle.Top; y < rectangle.Bottom; ++y) 68 { 69 for (var x = rectangle.Left; x < rectangle.Right; ++x) 70 { 71 yield return new Point(x, y); 72 } 73 } 74 } 75 76 public static IEnumerable<T> Yield<T>(this T item) 77 { 78 yield return item; 79 } 80 81 public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null) 82 { 83 return new HashSet<T>(source, comparer); 84 } 85 86 public static IEnumerable<byte[]> Split(this byte[] bytes, int length) 87 { 88 for (int i = 0; i < bytes.Length; i += length) 89 { 90 yield return bytes.Skip(i).Take(Math.Min(length, bytes.Length - i)).ToArray(); 91 } 92 } 93 94 public static IEnumerable<string> Split(this string str, int length) 95 { 96 for (int i = 0; i < str.Length; i += length) 97 { 98 yield return str.Substring(i, Math.Min(length, str.Length - i)); 99 } 100 } 101 102 public static Font GetAdjustedFont(this Graphics graphics, string text, Font originalFont, int width, int minSize, int maxSize, bool smallestOnFail) 103 { 104 if (minSize > maxSize) 105 { 106 throw new ArgumentOutOfRangeException("minSize"); 107 } 108 109 for (var size = maxSize; size >= minSize; --size) 110 { 111 var font = new Font(originalFont.Name, size, originalFont.Style); 112 var textSize = graphics.MeasureString(text, font); 113 114 if (width > Convert.ToInt32(textSize.Width)) 115 { 116 return font; 117 } 118 } 119 120 return smallestOnFail ? new Font(originalFont.Name, minSize, originalFont.Style) : originalFont; 121 } 122 123 public static Bitmap Sharpen(this Bitmap bitmap, double strength) 124 { 125 var sharpenImage = bitmap.Clone() as Bitmap; 126 127 int width = bitmap.Width; 128 int height = bitmap.Height; 129 130 // Create sharpening filter. 131 const int filterSize = 5; 132 133 var filter = new double[,] 134 { 135 {-1, -1, -1, -1, -1}, 136 {-1, 2, 2, 2, -1}, 137 {-1, 2, 16, 2, -1}, 138 {-1, 2, 2, 2, -1}, 139 {-1, -1, -1, -1, -1} 140 }; 141 142 double bias = 1.0 - strength; 143 double factor = strength / 16.0; 144 145 const int s = filterSize / 2; 146 147 var result = new Color[bitmap.Width, bitmap.Height]; 148 149 // Lock image bits for read/write. 150 if (sharpenImage != null) 151 { 152 BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 153 154 // Declare an array to hold the bytes of the bitmap. 155 int bytes = pbits.Stride * height; 156 var rgbValues = new byte[bytes]; 157 158 // Copy the RGB values into the array. 159 Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes); 160 161 int rgb; 162 // Fill the color array with the new sharpened color values. 163 for (int x = s; x < width - s; x++) 164 { 165 for (int y = s; y < height - s; y++) 166 { 167 double red = 0.0, green = 0.0, blue = 0.0; 168 169 for (int filterX = 0; filterX < filterSize; filterX++) 170 { 171 for (int filterY = 0; filterY < filterSize; filterY++) 172 { 173 int imageX = (x - s + filterX + width) % width; 174 int imageY = (y - s + filterY + height) % height; 175 176 rgb = imageY * pbits.Stride + 3 * imageX; 177 178 red += rgbValues[rgb + 2] * filter[filterX, filterY]; 179 green += rgbValues[rgb + 1] * filter[filterX, filterY]; 180 blue += rgbValues[rgb + 0] * filter[filterX, filterY]; 181 } 182 183 rgb = y * pbits.Stride + 3 * x; 184 185 int r = Math.Min(Math.Max((int)(factor * red + (bias * rgbValues[rgb + 2])), 0), 255); 186 int g = Math.Min(Math.Max((int)(factor * green + (bias * rgbValues[rgb + 1])), 0), 255); 187 int b = Math.Min(Math.Max((int)(factor * blue + (bias * rgbValues[rgb + 0])), 0), 255); 188 189 result[x, y] = Color.FromArgb(r, g, b); 190 } 191 } 192 } 193 194 // Update the image with the sharpened pixels. 195 for (int x = s; x < width - s; x++) 196 { 197 for (int y = s; y < height - s; y++) 198 { 199 rgb = y * pbits.Stride + 3 * x; 200 201 rgbValues[rgb + 2] = result[x, y].R; 202 rgbValues[rgb + 1] = result[x, y].G; 203 rgbValues[rgb + 0] = result[x, y].B; 204 } 205 } 206 207 // Copy the RGB values back to the bitmap. 208 Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes); 209 // Release image bits. 210 sharpenImage.UnlockBits(pbits); 211 } 212 213 return sharpenImage; 214 } 215 } 216 }