From f833599a084faa4528f6d8ce4d1e1b72fe18df02 Mon Sep 17 00:00:00 2001 From: Freon Date: Mon, 19 Dec 2016 17:40:20 +1000 Subject: [PATCH] Added ability to separate channels and merge them back together. Seems to work. --- CSharpImageLibrary/ImageEngine.cs | 44 +++++- CSharpImageLibrary/ImageEngineImage.cs | 15 +- UI_Project/MergeChannelsImage.cs | 99 +++++++++++++ UI_Project/NewMainWindow.xaml | 117 ++++++++++++++- UI_Project/NewMainWindow.xaml.cs | 195 +++++++++++++++++++++++++ UI_Project/NewViewModel.cs | 94 +++++++++++- UI_Project/UI_Project.csproj | 6 +- UI_Project/packages.config | 3 +- 8 files changed, 561 insertions(+), 12 deletions(-) create mode 100644 UI_Project/MergeChannelsImage.cs diff --git a/CSharpImageLibrary/ImageEngine.cs b/CSharpImageLibrary/ImageEngine.cs index 478d444..8029b09 100644 --- a/CSharpImageLibrary/ImageEngine.cs +++ b/CSharpImageLibrary/ImageEngine.cs @@ -196,6 +196,48 @@ internal static AbstractHeader LoadHeader(Stream stream) return header; } + internal static void SplitChannels(MipMap mip, string savePath) + { + char[] channels = new char[] { 'B', 'G', 'R', 'A' }; + for (int i = 0; i < 4; i++) + { + // Extract channel into grayscale image + var grayChannel = BuildGrayscaleFromChannel(mip.Pixels, i); + + // Save channel + var gray = UsefulThings.WPF.Images.CreateWriteableBitmap(grayChannel, mip.Width, mip.Height); + PngBitmapEncoder encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(gray)); + byte[] bytes = null; + using (MemoryStream ms = new MemoryStream(grayChannel.Length)) + { + encoder.Save(ms); + bytes = ms.ToArray(); + } + + if (bytes == null) + throw new InvalidDataException("Failed to save channel. Reason unknown."); + + string tempPath = Path.GetFileNameWithoutExtension(savePath) + "_" + channels[i] + ".png"; + string channelPath = Path.Combine(Path.GetDirectoryName(savePath), UsefulThings.General.FindValidNewFileName(tempPath)); + File.WriteAllBytes(channelPath, bytes); + } + } + + static byte[] BuildGrayscaleFromChannel(byte[] pixels, int channel) + { + byte[] destination = new byte[pixels.Length]; + int count = 0; + for (int i = channel; i < pixels.Length; i+=4) + { + for (int j = 0; j < 3; j++) + destination[count++] = pixels[i]; + destination[count++] = 0xFF; + } + + return destination; + } + /// /// Save mipmaps as given format to stream. @@ -295,7 +337,7 @@ internal static byte[] Save(List MipMaps, ImageEngineFormat format, MipH internal static MipMap Resize(MipMap mipMap, double scale, bool preserveAspect = true) { if (preserveAspect) - return Resize(mipMap, scale, 0); // Could be either scale dimension, doesn't matter. + return Resize(mipMap, scale, scale); // Could be either scale dimension, doesn't matter. else return Resize(mipMap, scale, scale); } diff --git a/CSharpImageLibrary/ImageEngineImage.cs b/CSharpImageLibrary/ImageEngineImage.cs index da429a7..6e00414 100644 --- a/CSharpImageLibrary/ImageEngineImage.cs +++ b/CSharpImageLibrary/ImageEngineImage.cs @@ -143,6 +143,8 @@ public ImageEngineImage(byte[] imageData, int maxDimension = 0) /// Mipmap to use as source. public ImageEngineImage(MipMap mip) { + if (MipMaps == null) + MipMaps = new List(); MipMaps.Add(mip); } @@ -190,6 +192,16 @@ public async Task Save(string destination, ImageEngineFormat format, MipHandling await fs.WriteAsync(data, 0, data.Length); } + + /// + /// Saves each channel separately incl Alpha. + /// + /// General save path. Appends channel name too. + public void SplitChannels(string savePath) + { + ImageEngine.SplitChannels(MipMaps[0], savePath); + } + /// /// Saves image in specified format to stream. /// Stream position not reset before or after. @@ -238,8 +250,7 @@ public byte[] Save(ImageEngineFormat format, MipHandling GenerateMips, int desir /// public void Dispose() { - if (MipMaps == null) - return; + // Nothing for now I guess... } /// diff --git a/UI_Project/MergeChannelsImage.cs b/UI_Project/MergeChannelsImage.cs new file mode 100644 index 0000000..a317a4a --- /dev/null +++ b/UI_Project/MergeChannelsImage.cs @@ -0,0 +1,99 @@ +using CSharpImageLibrary; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; +using UsefulThings.WPF; + +namespace UI_Project +{ + public class MergeChannelsImage : ViewModelBase + { + #region Properties + public byte[] Pixels { get; private set; } + public string FilePath { get; private set; } + + public string DisplayName + { + get + { + return Path.GetFileNameWithoutExtension(FilePath); + } + } + + bool isRed = false; + public bool IsRed + { + get + { + return isRed; + } + set + { + SetProperty(ref isRed, value); + } + } + + bool isGreen = false; + public bool IsGreen + { + get + { + return isGreen; + } + set + { + SetProperty(ref isGreen, value); + } + } + + bool isBlue = false; + public bool IsBlue + { + get + { + return isBlue; + } + set + { + SetProperty(ref isBlue, value); + } + } + + bool isAlpha = false; + public bool IsAlpha + { + get + { + return isAlpha; + } + set + { + SetProperty(ref isAlpha, value); + } + } + + public BitmapSource Thumbnail { get; private set; } + + public int Height { get; private set; } + public int Width { get; private set; } + #endregion Properties + + + public MergeChannelsImage(string mainPath) + { + FilePath = mainPath; + + using (var img = new ImageEngineImage(mainPath)) + { + Thumbnail = img.GetWPFBitmap(128); + Width = img.Width; + Height = img.Height; + Pixels = img.MipMaps[0].Pixels; + } + } + } +} diff --git a/UI_Project/NewMainWindow.xaml b/UI_Project/NewMainWindow.xaml index 0ab3a9f..3f7fffe 100644 --- a/UI_Project/NewMainWindow.xaml +++ b/UI_Project/NewMainWindow.xaml @@ -487,6 +487,10 @@ Visibility="{Binding SettingsPanelOpen, Converter={StaticResource BoolToVisConverter}, ConverterParameter={StaticResource TrueValue}}"/> + + + + + + + + + + + + + + + + +