From 59cd8575b1cce2e479fcbb9bb26b7e485ac00189 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sat, 8 Apr 2023 22:34:44 +0200 Subject: [PATCH] Fix wrong spelling of 'Extentions' to 'Extensions' and Add blending to 'ImageExtension' --- PCK-Studio/Classes/Extensions/BlendMode.cs | 12 ++ .../EnumerableExtensions.cs} | 4 +- .../ImageExtensions.cs} | 120 +++++++++++++++--- PCK-Studio/Forms/Editor/Animation.cs | 4 +- PCK-Studio/Forms/Editor/AnimationEditor.cs | 8 +- .../Forms/Utilities/AnimationResources.cs | 5 +- .../Forms/Utilities/BehaviourResources.cs | 4 +- .../Forms/Utilities/MaterialResources.cs | 2 +- PCK-Studio/Forms/Utilities/ModelsResources.cs | 2 +- PCK-Studio/Forms/Utilities/pckCenterOpen.cs | 4 +- PCK-Studio/PckStudio.csproj | 5 +- 11 files changed, 133 insertions(+), 37 deletions(-) create mode 100644 PCK-Studio/Classes/Extensions/BlendMode.cs rename PCK-Studio/Classes/{Extentions/EnumerableExtentions.cs => Extensions/EnumerableExtensions.cs} (79%) rename PCK-Studio/Classes/{Extentions/ImageExtentions.cs => Extensions/ImageExtensions.cs} (50%) diff --git a/PCK-Studio/Classes/Extensions/BlendMode.cs b/PCK-Studio/Classes/Extensions/BlendMode.cs new file mode 100644 index 00000000..96cfc36e --- /dev/null +++ b/PCK-Studio/Classes/Extensions/BlendMode.cs @@ -0,0 +1,12 @@ +namespace PckStudio.Extensions +{ + public enum BlendMode + { + Add, + Subtract, + Multiply, + Average, + DescendingOrder, + AscendingOrder + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/Extentions/EnumerableExtentions.cs b/PCK-Studio/Classes/Extensions/EnumerableExtensions.cs similarity index 79% rename from PCK-Studio/Classes/Extentions/EnumerableExtentions.cs rename to PCK-Studio/Classes/Extensions/EnumerableExtensions.cs index cda71bba..ed95e29f 100644 --- a/PCK-Studio/Classes/Extentions/EnumerableExtentions.cs +++ b/PCK-Studio/Classes/Extensions/EnumerableExtensions.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -namespace PckStudio.Classes.Extentions +namespace PckStudio.Extensions { - internal static class EnumerableExtentions + internal static class EnumerableExtensions { public static IEnumerable<(int index, T type)>enumerate(this IEnumerable array) { diff --git a/PCK-Studio/Classes/Extentions/ImageExtentions.cs b/PCK-Studio/Classes/Extensions/ImageExtensions.cs similarity index 50% rename from PCK-Studio/Classes/Extentions/ImageExtentions.cs rename to PCK-Studio/Classes/Extensions/ImageExtensions.cs index 6743d1de..6313801d 100644 --- a/PCK-Studio/Classes/Extentions/ImageExtentions.cs +++ b/PCK-Studio/Classes/Extensions/ImageExtensions.cs @@ -4,11 +4,14 @@ using System.Drawing; using System.Diagnostics; using System; using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System.Windows.Media.Media3D; +using System.Web; -namespace PckStudio.Classes.Extentions +namespace PckStudio.Extensions { - internal static class ImageExtentions - { + internal static class ImageExtensions + { public enum ImageLayoutDirection { Horizontal, @@ -31,15 +34,15 @@ namespace PckStudio.Classes.Extentions } } - private static Image GetTileImage(Image source, Rectangle area, Size size, GraphicsUnit unit = GraphicsUnit.Pixel) + public static Image GetArea(this Image source, Rectangle area, GraphicsUnit unit = GraphicsUnit.Pixel) { - Image tileImage = new Bitmap(size.Width, size.Height); + Image tileImage = new Bitmap(area.Width, area.Height); using (Graphics gfx = Graphics.FromImage(tileImage)) { gfx.SmoothingMode = SmoothingMode.None; gfx.InterpolationMode = InterpolationMode.NearestNeighbor; gfx.PixelOffsetMode = PixelOffsetMode.HighQuality; - gfx.DrawImage(source, new Rectangle(Point.Empty, size), area, unit); + gfx.DrawImage(source, new Rectangle(Point.Empty, area.Size), area, unit); } return tileImage; } @@ -54,7 +57,7 @@ namespace PckStudio.Classes.Extentions int row = i / img_row_count; int column = i % img_row_count; Rectangle tileArea = new Rectangle(new Point(column * size.Height, row * size.Width), size); - yield return GetTileImage(source, tileArea, size); + yield return source.GetArea(tileArea); } yield break; } @@ -70,7 +73,7 @@ namespace PckStudio.Classes.Extentions { ImageLayoutInfo locationInfo = new ImageLayoutInfo(source.Width, source.Height, i, layoutDirection); Rectangle tileArea = new Rectangle(locationInfo.SectionPoint, locationInfo.SectionSize); - yield return GetTileImage(source, tileArea, locationInfo.SectionSize); + yield return source.GetArea(tileArea); } yield break; } @@ -112,8 +115,18 @@ namespace PckStudio.Classes.Extentions public CompositingMode CompositingMode { get; set; } public CompositingQuality CompositingQuality { get; set; } public InterpolationMode InterpolationMode { get; set; } - public SmoothingMode SmoothingMode {get; set; } + public SmoothingMode SmoothingMode { get; set; } public PixelOffsetMode PixelOffsetMode { get; set; } + + public void Apply(Graphics graphics) + { + graphics.CompositingMode = CompositingMode; + graphics.CompositingQuality = CompositingQuality; + graphics.InterpolationMode = InterpolationMode; + graphics.SmoothingMode = SmoothingMode; + graphics.PixelOffsetMode = PixelOffsetMode; + } + } public static Image ResizeImage(this Image image, int width, int height, GraphicsConfig graphicsConfig) @@ -125,12 +138,7 @@ namespace PckStudio.Classes.Extentions using (var graphics = Graphics.FromImage(destImage)) { - graphics.CompositingMode = graphicsConfig.CompositingMode; - graphics.CompositingQuality = graphicsConfig.CompositingQuality; - graphics.InterpolationMode = graphicsConfig.InterpolationMode; - graphics.SmoothingMode = graphicsConfig.SmoothingMode; - graphics.PixelOffsetMode = graphicsConfig.PixelOffsetMode; - + graphicsConfig.Apply(graphics); using (var wrapMode = new ImageAttributes()) { wrapMode.SetWrapMode(WrapMode.TileFlipXY); @@ -139,5 +147,87 @@ namespace PckStudio.Classes.Extentions } return destImage; } + + public static Image Fill(this Image image, Color color) + { + using (var g = Graphics.FromImage(image)) + { + using (SolidBrush brush = new SolidBrush(color)) + { + g.FillRectangle(brush, new Rectangle(Point.Empty, image.Size)); + } + } + return image; + } + + public static Image Blend(this Image bg, Color foregroundColor, BlendMode mode) + { + Bitmap bitmap = new Bitmap(bg); + bitmap.Fill(foregroundColor); + return bg.Blend(bitmap, mode); + } + + public static Image Blend(this Image image, Image overlay, BlendMode mode) + { + Stopwatch stopwatch = Stopwatch.StartNew(); + if (image is not Bitmap baseImage || overlay is not Bitmap overlayImage) + return image; + BitmapData baseImageData = baseImage.LockBits(new Rectangle(Point.Empty, baseImage.Size), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + byte[] baseImageBuffer = new byte[baseImageData.Stride * baseImageData.Height]; + + Marshal.Copy(baseImageData.Scan0, baseImageBuffer, 0, baseImageBuffer.Length); + + BitmapData overlayImageData = overlayImage.LockBits(new Rectangle(Point.Empty, overlayImage.Size), + ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + byte[] overlayImageBuffer = new byte[overlayImageData.Stride * overlayImageData.Height]; + + Marshal.Copy(overlayImageData.Scan0, overlayImageBuffer, 0, overlayImageBuffer.Length); + + for (int k = 0; k < baseImageBuffer.Length && k < overlayImageBuffer.Length; k += 4) + { + baseImageBuffer[k + 0] = CalculateColorComponentBlendValue(baseImageBuffer[k + 0] / 255f, overlayImageBuffer[k + 0] / 255f, mode); + baseImageBuffer[k + 1] = CalculateColorComponentBlendValue(baseImageBuffer[k + 1] / 255f, overlayImageBuffer[k + 1] / 255f, mode); + baseImageBuffer[k + 2] = CalculateColorComponentBlendValue(baseImageBuffer[k + 2] / 255f, overlayImageBuffer[k + 2] / 255f, mode); + } + + Bitmap bitmapResult = new Bitmap(baseImage.Width, baseImage.Height, PixelFormat.Format32bppArgb); + BitmapData resultImageData = bitmapResult.LockBits(new Rectangle(Point.Empty, bitmapResult.Size), + ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + + Marshal.Copy(baseImageBuffer, 0, resultImageData.Scan0, baseImageBuffer.Length); + + bitmapResult.UnlockBits(resultImageData); + baseImage.UnlockBits(baseImageData); + overlayImage.UnlockBits(overlayImageData); + stopwatch.Stop(); + Debug.WriteLine($"{nameof(ImageExtensions.Blend)} took {stopwatch.ElapsedMilliseconds}ms"); + return bitmapResult; + } + + private static T Clamp(T value, T min, T max) where T : IComparable + { + if (value.CompareTo(min) < 0) return min; + else if (value.CompareTo(max) > 0) return max; + else return value; + } + + private static byte CalculateColorComponentBlendValue(float source, float overlay, BlendMode blendType) + { + source = Clamp(source, 0.0f, 1.0f); + overlay = Clamp(overlay, 0.0f, 1.0f); + + float resultValue = blendType switch + { + BlendMode.Add => source + overlay, + BlendMode.Subtract => source - overlay, + BlendMode.Multiply => source * overlay, + BlendMode.Average => (source + overlay) / 2.0f, + BlendMode.AscendingOrder => source > overlay ? overlay : source, + BlendMode.DescendingOrder => source < overlay ? overlay : source, + _ => 0.0f + }; + return (byte)Clamp(resultValue * 255, 0, 255); + } } } diff --git a/PCK-Studio/Forms/Editor/Animation.cs b/PCK-Studio/Forms/Editor/Animation.cs index ad8a1ccd..7aa20194 100644 --- a/PCK-Studio/Forms/Editor/Animation.cs +++ b/PCK-Studio/Forms/Editor/Animation.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Drawing; -using PckStudio.Classes.Extentions; +using PckStudio.Extensions; using System.Text; @@ -140,7 +140,7 @@ namespace PckStudio.Forms.Editor var textures = isClockOrCompass ? linearImages : frameTextures; - return ImageExtentions.ImageFromImageArray(textures.ToArray(), ImageExtentions.ImageLayoutDirection.Vertical); + return ImageExtensions.ImageFromImageArray(textures.ToArray(), ImageExtensions.ImageLayoutDirection.Vertical); } } } diff --git a/PCK-Studio/Forms/Editor/AnimationEditor.cs b/PCK-Studio/Forms/Editor/AnimationEditor.cs index 7f921db2..7ddcdc7e 100644 --- a/PCK-Studio/Forms/Editor/AnimationEditor.cs +++ b/PCK-Studio/Forms/Editor/AnimationEditor.cs @@ -3,15 +3,13 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Drawing; -using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Windows.Forms; -using PckStudio.Classes.FileTypes; using PckStudio.Forms.Additional_Popups.Animation; using PckStudio.Forms.Utilities; -using PckStudio.Classes.Extentions; +using PckStudio.Extensions; using OMI.Formats.Pck; namespace PckStudio.Forms.Editor @@ -51,7 +49,7 @@ namespace PckStudio.Forms.Editor using MemoryStream textureMem = new MemoryStream(animationFile.Data); var texture = new Bitmap(textureMem); - var frameTextures = texture.CreateImageList(ImageExtentions.ImageLayoutDirection.Horizontal); + var frameTextures = texture.CreateImageList(ImageExtensions.ImageLayoutDirection.Horizontal); currentAnimation = animationFile.Properties.HasProperty("ANIM") ? new Animation(frameTextures, animationFile.Properties.GetPropertyValue("ANIM")) @@ -296,7 +294,7 @@ namespace PckStudio.Forms.Editor return; } using MemoryStream textureMem = new MemoryStream(File.ReadAllBytes(textureFile)); - var textures = Image.FromStream(textureMem).CreateImageList(ImageExtentions.ImageLayoutDirection.Horizontal); + var textures = Image.FromStream(textureMem).CreateImageList(ImageExtensions.ImageLayoutDirection.Horizontal); var new_animation = new Animation(textures); try { diff --git a/PCK-Studio/Forms/Utilities/AnimationResources.cs b/PCK-Studio/Forms/Utilities/AnimationResources.cs index 4d8c1f4a..237d153a 100644 --- a/PCK-Studio/Forms/Utilities/AnimationResources.cs +++ b/PCK-Studio/Forms/Utilities/AnimationResources.cs @@ -1,12 +1,9 @@ using Newtonsoft.Json.Linq; using System.Drawing; using System.Linq; -using System.IO; using PckStudio.Properties; -using System.Drawing.Imaging; -using PckStudio.Classes.Extentions; -using OMI.Formats.Pck; +using PckStudio.Extensions; namespace PckStudio.Forms.Utilities { diff --git a/PCK-Studio/Forms/Utilities/BehaviourResources.cs b/PCK-Studio/Forms/Utilities/BehaviourResources.cs index 763c4e71..8eed8e50 100644 --- a/PCK-Studio/Forms/Utilities/BehaviourResources.cs +++ b/PCK-Studio/Forms/Utilities/BehaviourResources.cs @@ -4,11 +4,9 @@ using System.Linq; using System.IO; using PckStudio.Properties; -using PckStudio.Classes.Extentions; +using PckStudio.Extensions; using OMI.Formats.Behaviour; using OMI.Workers.Behaviour; -using OMI.Formats.Pck; -using System; namespace PckStudio.Forms.Utilities { diff --git a/PCK-Studio/Forms/Utilities/MaterialResources.cs b/PCK-Studio/Forms/Utilities/MaterialResources.cs index 7d27eda1..94cd2e4a 100644 --- a/PCK-Studio/Forms/Utilities/MaterialResources.cs +++ b/PCK-Studio/Forms/Utilities/MaterialResources.cs @@ -4,7 +4,7 @@ using System.Linq; using System.IO; using PckStudio.Properties; -using PckStudio.Classes.Extentions; +using PckStudio.Extensions; using OMI.Formats.Pck; using OMI.Formats.Material; using OMI.Workers.Material; diff --git a/PCK-Studio/Forms/Utilities/ModelsResources.cs b/PCK-Studio/Forms/Utilities/ModelsResources.cs index cdf91454..f61e6ee1 100644 --- a/PCK-Studio/Forms/Utilities/ModelsResources.cs +++ b/PCK-Studio/Forms/Utilities/ModelsResources.cs @@ -4,7 +4,7 @@ using System.Linq; using System.IO; using PckStudio.Properties; -using PckStudio.Classes.Extentions; +using PckStudio.Extensions; using OMI.Formats.Model; using OMI.Formats.Pck; using OMI.Workers.Model; diff --git a/PCK-Studio/Forms/Utilities/pckCenterOpen.cs b/PCK-Studio/Forms/Utilities/pckCenterOpen.cs index c16ab9a7..b1ba4635 100644 --- a/PCK-Studio/Forms/Utilities/pckCenterOpen.cs +++ b/PCK-Studio/Forms/Utilities/pckCenterOpen.cs @@ -19,7 +19,7 @@ using PckStudio.Classes.FileTypes; using PckStudio.Classes.IO.PCK; using OMI.Formats.Pck; using OMI.Workers.Pck; -using PckStudio.Classes.Extentions; +using PckStudio.Extensions; namespace PckStudio.Forms { @@ -1027,7 +1027,7 @@ namespace PckStudio.Forms { var ms = new MemoryStream(skinTexture.Data); Bitmap saveSkin = new Bitmap(Image.FromStream(ms)); - var config = new ImageExtentions.GraphicsConfig() + var config = new ImageExtensions.GraphicsConfig() { CompositingMode = CompositingMode.SourceCopy, CompositingQuality = CompositingQuality.HighQuality, diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index 0433db82..96fbce83 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -170,7 +170,8 @@ - + + @@ -185,7 +186,7 @@ - +