CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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 }