diff --git a/Yugen.Mosaic.Uwp/App.xaml.cs b/Yugen.Mosaic.Uwp/App.xaml.cs index af2d86b..8a4ace6 100644 --- a/Yugen.Mosaic.Uwp/App.xaml.cs +++ b/Yugen.Mosaic.Uwp/App.xaml.cs @@ -15,7 +15,7 @@ namespace Yugen.Mosaic.Uwp /// /// Provides application-specific behavior to supplement the default Application class. /// - sealed partial class App : Application + public sealed partial class App : Application { /// /// Initializes the singleton application object. This is the first line of authored code @@ -23,8 +23,8 @@ sealed partial class App : Application /// public App() { - this.InitializeComponent(); - this.Suspending += OnSuspending; + InitializeComponent(); + Suspending += OnSuspending; AppCenter.Start("7df4b441-69ae-49c5-b27d-5a532f33b554", typeof(Analytics), typeof(Crashes)); @@ -76,10 +76,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e) /// /// The Frame which failed navigation /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } + private void OnNavigationFailed(object sender, NavigationFailedEventArgs e) => throw new Exception("Failed to load Page " + e.SourcePageType.FullName); /// /// Invoked when application execution is being suspended. Application state is saved @@ -90,7 +87,7 @@ void OnNavigationFailed(object sender, NavigationFailedEventArgs e) /// Details about the suspend request. private void OnSuspending(object sender, SuspendingEventArgs e) { - var deferral = e.SuspendingOperation.GetDeferral(); + SuspendingDeferral deferral = e.SuspendingOperation.GetDeferral(); //TODO: Save application state and stop any background activity deferral.Complete(); } diff --git a/Yugen.Mosaic.Uwp/Controls/AlignmentGrid.cs b/Yugen.Mosaic.Uwp/Controls/AlignmentGrid.cs index 563fc4f..b71f013 100644 --- a/Yugen.Mosaic.Uwp/Controls/AlignmentGrid.cs +++ b/Yugen.Mosaic.Uwp/Controls/AlignmentGrid.cs @@ -60,8 +60,8 @@ private static void OnPropertyChanged(DependencyObject dependencyObject, Depende /// public Brush LineBrush { - get { return (Brush)GetValue(LineBrushProperty); } - set { SetValue(LineBrushProperty, value); } + get => (Brush)GetValue(LineBrushProperty); + set => SetValue(LineBrushProperty, value); } /// @@ -69,8 +69,8 @@ public Brush LineBrush /// public double HorizontalStep { - get { return (double)GetValue(HorizontalStepProperty); } - set { SetValue(HorizontalStepProperty, value); } + get => (double)GetValue(HorizontalStepProperty); + set => SetValue(HorizontalStepProperty, value); } /// @@ -78,8 +78,8 @@ public double HorizontalStep /// public double VerticalStep { - get { return (double)GetValue(VerticalStepProperty); } - set { SetValue(VerticalStepProperty, value); } + get => (double)GetValue(VerticalStepProperty); + set => SetValue(VerticalStepProperty, value); } /// @@ -87,8 +87,8 @@ public double VerticalStep /// public double ContainerWidth { - get { return (double)GetValue(ContainerWidthProperty); } - set { SetValue(ContainerWidthProperty, value); } + get => (double)GetValue(ContainerWidthProperty); + set => SetValue(ContainerWidthProperty, value); } /// @@ -96,8 +96,8 @@ public double ContainerWidth /// public double ContainerHeight { - get { return (double)GetValue(ContainerHeightProperty); } - set { SetValue(ContainerHeightProperty, value); } + get => (double)GetValue(ContainerHeightProperty); + set => SetValue(ContainerHeightProperty, value); } /// @@ -121,7 +121,7 @@ private void Rebuild() containerCanvas.Children.Clear(); var horizontalStep = HorizontalStep; var verticalStep = VerticalStep; - var brush = LineBrush ?? (Brush)Application.Current.Resources["ApplicationForegroundThemeBrush"]; + Brush brush = LineBrush ?? (Brush)Application.Current.Resources["ApplicationForegroundThemeBrush"]; if (horizontalStep > 0) { @@ -156,9 +156,6 @@ private void Rebuild() } } - private void AlignmentGrid_SizeChanged(object sender, SizeChangedEventArgs e) - { - Rebuild(); - } + private void AlignmentGrid_SizeChanged(object sender, SizeChangedEventArgs e) => Rebuild(); } } \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/Extensions/SettingsHelper.cs b/Yugen.Mosaic.Uwp/Extensions/SettingsHelper.cs index 8e617bb..e0f8512 100644 --- a/Yugen.Mosaic.Uwp/Extensions/SettingsHelper.cs +++ b/Yugen.Mosaic.Uwp/Extensions/SettingsHelper.cs @@ -21,18 +21,12 @@ public static void Write(string key, T value) LocalSettings.Values[key] = valueString; } - public static async Task ReadAsync(string key) - { - return LocalSettings.Values.TryGetValue(key, out object value) - ? await JsonProvider.ToObjectAsync((string) value) + public static async Task ReadAsync(string key) => LocalSettings.Values.TryGetValue(key, out var value) + ? await JsonProvider.ToObjectAsync((string)value) : default; - } - public static T Read(string key) - { - return LocalSettings.Values.TryGetValue(key, out object value) - ? JsonConvert.DeserializeObject((string) value) + public static T Read(string key) => LocalSettings.Values.TryGetValue(key, out var value) + ? JsonConvert.DeserializeObject((string)value) : default; - } } } \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/Helpers/ColorHelper.cs b/Yugen.Mosaic.Uwp/Helpers/ColorHelper.cs new file mode 100644 index 0000000..a74a028 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Helpers/ColorHelper.cs @@ -0,0 +1,53 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Threading.Tasks; + +namespace Yugen.Mosaic.Uwp.Helpers +{ + public static class ColorHelper + { + public static Rgba32 GetAverageColor(Image source, int x, int y, Size tileSize) => GetAverageColor(source, x * tileSize.Width, y * tileSize.Height, + tileSize.Width, tileSize.Height, x * tileSize.Width + tileSize.Width, y * tileSize.Height + tileSize.Height); + + public static Rgba32 GetAverageColor(Image source) => GetAverageColor(source, 0, 0, source.Width, source.Height, source.Width, source.Height); + + private static Rgba32 GetAverageColor(Image source, int startX, int startY, int width, int height, int endX, int endY) + { + long aR = 0; + long aG = 0; + long aB = 0; + + Parallel.For(startY, endY, h => + { + Span rowSpan = source.GetPixelRowSpan(h); + + for (var w = startX; w < endX; w++) + { + var pixel = new Rgba32(); + rowSpan[w].ToRgba32(ref pixel); + + aR += pixel.R; + aG += pixel.G; + aB += pixel.B; + } + }); + + aR /= width * height; + aG /= width * height; + aB /= width * height; + + return new Rgba32(Convert.ToByte(aR), Convert.ToByte(aG), Convert.ToByte(aB)); + } + + + public static int GetDifference(Rgba32 source, Rgba32 target) + { + var dR = Math.Abs(source.R - target.R); + var dG = Math.Abs(source.G - target.G); + var dB = Math.Abs(source.B - target.B); + var diff = Math.Max(dR, dG); + return Math.Max(diff, dB); + } + } +} diff --git a/Yugen.Mosaic.Uwp/Helpers/OnboardingHelper.cs b/Yugen.Mosaic.Uwp/Helpers/OnboardingHelper.cs index 960c771..899cc91 100644 --- a/Yugen.Mosaic.Uwp/Helpers/OnboardingHelper.cs +++ b/Yugen.Mosaic.Uwp/Helpers/OnboardingHelper.cs @@ -1,37 +1,9 @@ using Windows.UI.Xaml; using Yugen.Mosaic.Uwp.Extensions; +using Yugen.Mosaic.Uwp.Models; namespace Yugen.Mosaic.Uwp.Helpers { - public enum OnboardingStage - { - MasterImage, - AddTiles, - TileProperties, - MosaicType, - OutputProperties, - Generate, - Save - } - - public class OnboardingElement - { - public string Title { get; set; } - - public string Subtitle { get; set; } - - public FrameworkElement Target { get; set; } - - public OnboardingStage Stage { get; set; } - - public OnboardingElement(string title, string subtitle, FrameworkElement target, OnboardingStage stage) - { - Title = title; - Subtitle = subtitle; - Target = target; - Stage = stage; - } - } public static class OnboardingHelper { @@ -46,49 +18,39 @@ public static bool IsDisabled private static int _step; private static OnboardingElement[] _onboardingElements; - public static void Init(FrameworkElement[] frameworkElements) - { - var masterImageDescription = "Choose what image you want to use as the Matrix of the mosaic. " + - "Yugen Mosaic will create a mosaic as close as possible to the main image."; - - var addTilesDescription = "Add a list of Tile Images, Yugen Mosaic will use as tiles to build your mosaic"; - - var tilesPropertiesDescription = "After you created the Tile Images List, it is necessary to set all the parameters of the mosaic." + - "Here you can set the size of every single tile"; - - var mosaicTypeDescription = "Choose the tpe of mosaic."; - - var outputDescription = "Choose the size of the mosaic."; - - var generateDescription = "Create the mosaic."; - - var saveDescription = "The last step is to save the mosaic."; - - _onboardingElements = new OnboardingElement[] + public static void Init(FrameworkElement[] frameworkElements) => _onboardingElements = new OnboardingElement[] { - new OnboardingElement("Select the Main Image", masterImageDescription, - frameworkElements[0], OnboardingStage.MasterImage), - new OnboardingElement("Create a Tile Images List", addTilesDescription, - frameworkElements[1], OnboardingStage.AddTiles), - new OnboardingElement("TileProperties", tilesPropertiesDescription, - frameworkElements[2], OnboardingStage.TileProperties), - new OnboardingElement("MosaicType", mosaicTypeDescription, - frameworkElements[3], OnboardingStage.MosaicType), - new OnboardingElement("Set the parameters of the Mosaic", outputDescription, - frameworkElements[4], OnboardingStage.OutputProperties), - new OnboardingElement("Create the Mosaic", generateDescription, - frameworkElements[5], OnboardingStage.Generate), - new OnboardingElement("Save the Mosaic", saveDescription, - frameworkElements[6], OnboardingStage.Save), + new OnboardingElement( + frameworkElements[0], + OnboardingStage.MasterImage), + new OnboardingElement( + frameworkElements[1], + OnboardingStage.AddTiles), + new OnboardingElement( + frameworkElements[2], + OnboardingStage.TileProperties), + new OnboardingElement( + frameworkElements[3], + OnboardingStage.MosaicType), + new OnboardingElement( + frameworkElements[4], + OnboardingStage.OutputProperties), + new OnboardingElement( + frameworkElements[5], + OnboardingStage.Generate), + new OnboardingElement( + frameworkElements[6], + OnboardingStage.Save), }; - } public static OnboardingElement ShowTeachingTip() { OnboardingElement onboardingElement = null; if (_step < 0 || IsDisabled) + { return onboardingElement; + } if (_step < _onboardingElements.Length) { diff --git a/Yugen.Mosaic.Uwp/Helpers/RatioHelper.cs b/Yugen.Mosaic.Uwp/Helpers/RatioHelper.cs index 077d185..5f3e4c6 100644 --- a/Yugen.Mosaic.Uwp/Helpers/RatioHelper.cs +++ b/Yugen.Mosaic.Uwp/Helpers/RatioHelper.cs @@ -7,7 +7,7 @@ public static class RatioHelper public static Tuple Convert(int width, int height, int newHeight, int newWidth) { //calculate the ratio - double ratio = (double)width / (double)height; + var ratio = (double)width / (double)height; //set height of image to boxHeight and check if resulting width is less than boxWidth, //else set width of image to boxWidth and calculate new height diff --git a/Yugen.Mosaic.Uwp/Helpers/ResourceHelper.cs b/Yugen.Mosaic.Uwp/Helpers/ResourceHelper.cs new file mode 100644 index 0000000..cda2e33 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Helpers/ResourceHelper.cs @@ -0,0 +1,11 @@ +using Windows.ApplicationModel.Resources; + +namespace Yugen.Mosaic.Uwp.Helpers +{ + public static class ResourceHelper + { + private static readonly ResourceLoader _resourceLoader = _resourceLoader ?? new ResourceLoader(); + + public static string GetText(string key) => _resourceLoader.GetString(key); + } +} \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/Interfaces/IMosaicService.cs b/Yugen.Mosaic.Uwp/Interfaces/IMosaicService.cs new file mode 100644 index 0000000..deed307 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Interfaces/IMosaicService.cs @@ -0,0 +1,18 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System.IO; +using Windows.Storage.Streams; + +namespace Yugen.Mosaic.Uwp.Interfaces +{ + public interface IMosaicService + { + Image AddMasterImage(Stream stream); + Image AddTileImage(string name, Stream stream); + Image GenerateMosaic(Size outputSize, Size tileSize, int mosaicType); + Image GetResizedImage(Image image, int size); + InMemoryRandomAccessStream GetStream(Image image); + void RemoveTileImage(string name); + void Reset(); + } +} \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/Interfaces/ISearchAndReplaceService.cs b/Yugen.Mosaic.Uwp/Interfaces/ISearchAndReplaceService.cs new file mode 100644 index 0000000..022c4c8 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Interfaces/ISearchAndReplaceService.cs @@ -0,0 +1,7 @@ +namespace Yugen.Mosaic.Uwp.Interfaces +{ + public interface ISearchAndReplaceService + { + void SearchAndReplace(); + } +} \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/MainPage.xaml.cs b/Yugen.Mosaic.Uwp/MainPage.xaml.cs index 2a2009f..e01836b 100644 --- a/Yugen.Mosaic.Uwp/MainPage.xaml.cs +++ b/Yugen.Mosaic.Uwp/MainPage.xaml.cs @@ -14,13 +14,13 @@ public sealed partial class MainPage : Page public MainPage() { - this.InitializeComponent(); + InitializeComponent(); ExtendToTitleBar(); } private void ExtendToTitleBar() { - var coreTitleBar = CoreApplication.GetCurrentView().TitleBar; + CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar; coreTitleBar.ExtendViewIntoTitleBar = true; } diff --git a/Yugen.Mosaic.Uwp/Models/OnboardingElement.cs b/Yugen.Mosaic.Uwp/Models/OnboardingElement.cs new file mode 100644 index 0000000..1d7a3d4 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Models/OnboardingElement.cs @@ -0,0 +1,24 @@ +using Windows.UI.Xaml; +using Yugen.Mosaic.Uwp.Helpers; + +namespace Yugen.Mosaic.Uwp.Models +{ + public class OnboardingElement + { + public string Title { get; set; } + + public string Subtitle { get; set; } + + public FrameworkElement Target { get; set; } + + public OnboardingStage Stage { get; set; } + + public OnboardingElement(FrameworkElement target, OnboardingStage stage) + { + Title = ResourceHelper.GetText($"OnboardingStage{stage}Title"); + Subtitle = ResourceHelper.GetText($"OnboardingStage{stage}Description"); + Target = target; + Stage = stage; + } + } +} \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/Models/OnboardingStage.cs b/Yugen.Mosaic.Uwp/Models/OnboardingStage.cs new file mode 100644 index 0000000..db40c69 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Models/OnboardingStage.cs @@ -0,0 +1,13 @@ +namespace Yugen.Mosaic.Uwp.Models +{ + public enum OnboardingStage + { + MasterImage, + AddTiles, + TileProperties, + MosaicType, + OutputProperties, + Generate, + Save + } +} \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/Package.appxmanifest b/Yugen.Mosaic.Uwp/Package.appxmanifest index 00b24ed..c2d63b4 100644 --- a/Yugen.Mosaic.Uwp/Package.appxmanifest +++ b/Yugen.Mosaic.Uwp/Package.appxmanifest @@ -7,7 +7,7 @@ IgnorableNamespaces="uap mp"> diff --git a/Yugen.Mosaic.Uwp/Processors/AdjustHueProcessor.cs b/Yugen.Mosaic.Uwp/Processors/AdjustHueProcessor.cs index 9a03a40..6d65089 100644 --- a/Yugen.Mosaic.Uwp/Processors/AdjustHueProcessor.cs +++ b/Yugen.Mosaic.Uwp/Processors/AdjustHueProcessor.cs @@ -1,81 +1,80 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Primitives; -using System; -using System.Threading.Tasks; +//using SixLabors.ImageSharp; +//using SixLabors.ImageSharp.PixelFormats; +//using SixLabors.ImageSharp.Processing.Processors; +//using System; +//using System.Threading.Tasks; +//using Rectangle = SixLabors.ImageSharp.Rectangle; -namespace Yugen.Mosaic.Uwp.Processors -{ - public sealed class AdjustHueProcessor : IImageProcessor - { - public Image InputImage { get; } - public Rgba32 AverageColor { get; } +//namespace Yugen.Mosaic.Uwp.Processors +//{ +// public sealed class AdjustHueProcessor : IImageProcessor +// { +// public Image InputImage { get; } +// public Rgba32 AverageColor { get; } - public AdjustHueProcessor(Image inputImage, Rgba32 averageColor) - { - InputImage = inputImage; - AverageColor = averageColor; - } +// public AdjustHueProcessor(Image inputImage, Rgba32 averageColor) +// { +// InputImage = inputImage; +// AverageColor = averageColor; +// } - /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new AdjustHueProcessor(this, source, sourceRectangle); - } - } +// /// +// public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : unmanaged, IPixel +// { +// return new AdjustHueProcessor(configuration, this, source, sourceRectangle); +// } +// } - public class AdjustHueProcessor : IImageProcessor where TPixel : struct, IPixel - { - /// - /// The source instance to modify - /// - private readonly Image _source; - private readonly Image _inputImage; - private readonly Rgba32 _averageColor; +// public class AdjustHueProcessor : IImageProcessor where TPixel : unmanaged, IPixel +// { +// /// +// /// The source instance to modify +// /// +// private readonly Image _source; +// private readonly Image _inputImage; +// private readonly Rgba32 _averageColor; - /// - /// Initializes a new instance of the class - /// - /// The defining the processor parameters - /// The source for the current processor instance - /// The source area to process for the current processor instance - public AdjustHueProcessor(AdjustHueProcessor definition, Image source, Rectangle sourceRectangle) - { - _source = source; - _inputImage = definition.InputImage; - _averageColor = definition.AverageColor; - } +// /// +// /// Initializes a new instance of the class +// /// +// /// The defining the processor parameters +// /// The source for the current processor instance +// /// The source area to process for the current processor instance +// public AdjustHueProcessor(Configuration configuration, AdjustHueProcessor definition, Image source, Rectangle sourceRectangle) +// { +// _source = source; +// _inputImage = definition.InputImage; +// _averageColor = definition.AverageColor; +// } - /// - public void Apply() - { - //int width = Source.Width; - //Image source = Source; +// /// +// public void Execute() +// { +// //int width = Source.Width; +// //Image source = Source; - Parallel.For(0, _inputImage.Height, h => - { - var rowSpan = _inputImage.GetPixelRowSpan(h); +// Parallel.For(0, _inputImage.Height, h => +// { +// var rowSpan = _inputImage.GetPixelRowSpan(h); - for (int w = 0; w < _inputImage.Width; w++) - { - Rgba32 pixel = new Rgba32(); - rowSpan[w].ToRgba32(ref pixel); +// for (int w = 0; w < _inputImage.Width; w++) +// { +// Rgba32 pixel = new Rgba32(); +// rowSpan[w].ToRgba32(ref pixel); - int R = Math.Min(255, Math.Max(0, (pixel.R + _averageColor.R) / 2)); - int G = Math.Min(255, Math.Max(0, (pixel.G + _averageColor.G) / 2)); - int B = Math.Min(255, Math.Max(0, (pixel.B + _averageColor.B) / 2)); +// int R = Math.Min(255, Math.Max(0, (pixel.R + _averageColor.R) / 2)); +// int G = Math.Min(255, Math.Max(0, (pixel.G + _averageColor.G) / 2)); +// int B = Math.Min(255, Math.Max(0, (pixel.B + _averageColor.B) / 2)); - Color clAvg = new Rgba32(Convert.ToByte(R), Convert.ToByte(G), Convert.ToByte(B)); - - TPixel pixelColor = clAvg.ToPixel(); - _source[w, h] = pixelColor; - } - }); - } +// Color clAvg = new Rgba32(Convert.ToByte(R), Convert.ToByte(G), Convert.ToByte(B)); - /// - public void Dispose() { } - } -} +// TPixel pixelColor = clAvg.ToPixel(); +// _source[w, h] = pixelColor; +// } +// }); +// } + +// /// +// public void Dispose() { } +// } +//} diff --git a/Yugen.Mosaic.Uwp/Processors/ApplyTileFoundProcessor.cs b/Yugen.Mosaic.Uwp/Processors/ApplyTileFoundProcessor.cs index 1fb9632..a4a0c76 100644 --- a/Yugen.Mosaic.Uwp/Processors/ApplyTileFoundProcessor.cs +++ b/Yugen.Mosaic.Uwp/Processors/ApplyTileFoundProcessor.cs @@ -1,90 +1,87 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Primitives; -using System; -using System.Threading.Tasks; +//using SixLabors.ImageSharp; +//using SixLabors.ImageSharp.PixelFormats; +//using SixLabors.ImageSharp.Processing.Processors; +//using System.Threading.Tasks; +//using Rectangle = SixLabors.ImageSharp.Rectangle; -namespace Yugen.Mosaic.Uwp.Processors -{ - public sealed class ApplyTileFoundProcessor : IImageProcessor - { - public int X { get; } - public int Y { get; } - public int Width { get; } - public int Height { get; } +//namespace Yugen.Mosaic.Uwp.Processors +//{ +// public sealed class ApplyTileFoundProcessor : IImageProcessor +// { +// public int X { get; } +// public int Y { get; } +// public int Width { get; } +// public int Height { get; } - public Image OutputImage { get; } +// public Image OutputImage { get; } - public ApplyTileFoundProcessor(int x, int y, int width, int height, Image outputImage) - { - X = x; - Y = y; - Width = width; - Height = height; +// public ApplyTileFoundProcessor(int x, int y, int width, int height, Image outputImage) +// { +// X = x; +// Y = y; +// Width = width; +// Height = height; - OutputImage = outputImage; - } +// OutputImage = outputImage; +// } - /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new ApplyTileFoundProcessor(this, source, sourceRectangle); - } - } +// /// +// public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : unmanaged, IPixel +// { +// return new ApplyTileFoundProcessor(configuration, this, source, sourceRectangle); +// } +// } - public class ApplyTileFoundProcessor : IImageProcessor where TPixel : struct, IPixel - { - /// - /// The source instance to modify - /// - private readonly Image _source; +// public class ApplyTileFoundProcessor : IImageProcessor where TPixel : unmanaged, IPixel +// { +// /// +// /// The source instance to modify +// /// +// private readonly Image _source; - private readonly int _x; - private readonly int _y; - private readonly int _width; - private readonly int _height; +// private readonly int _x; +// private readonly int _y; +// private readonly int _width; +// private readonly int _height; - private readonly Image _outputImage; +// private readonly Image _outputImage; - /// - /// Initializes a new instance of the class - /// - /// The defining the processor parameters - /// The source for the current processor instance - /// The source area to process for the current processor instance - public ApplyTileFoundProcessor(ApplyTileFoundProcessor definition, Image source, Rectangle sourceRectangle) - { - _source = source; +// /// +// /// Initializes a new instance of the class +// /// +// /// The defining the processor parameters +// /// The source for the current processor instance +// /// The source area to process for the current processor instance +// public ApplyTileFoundProcessor(Configuration configuration, ApplyTileFoundProcessor definition, Image source, Rectangle sourceRectangle) +// { +// _source = source; - _x = definition.X; - _y = definition.Y; - _width = definition.Width; - _height = definition.Height; +// _x = definition.X; +// _y = definition.Y; +// _width = definition.Width; +// _height = definition.Height; - _outputImage = definition.OutputImage; - } - - /// - public void Apply() - { - Parallel.For(0, _height, h => - { - var rowSpan = _source.GetPixelRowSpan(h); +// _outputImage = definition.OutputImage; +// } - for (int w = 0; w < _width; w++) - { - Rgba32 pixel = new Rgba32(); - rowSpan[w].ToRgba32(ref pixel); +// /// +// public void Execute() +// { +// Parallel.For(0, _height, h => +// { +// var rowSpan = _source.GetPixelRowSpan(h); - _outputImage[_x * _width + w, _y * _height + h] = pixel; - } - }); - } +// for (int w = 0; w < _width; w++) +// { +// Rgba32 pixel = new Rgba32(); +// rowSpan[w].ToRgba32(ref pixel); - /// - public void Dispose() { } - } -} +// _outputImage[_x * _width + w, _y * _height + h] = pixel; +// } +// }); +// } + +// /// +// public void Dispose() { } +// } +//} diff --git a/Yugen.Mosaic.Uwp/Processors/GetTileAverageProcessor.cs b/Yugen.Mosaic.Uwp/Processors/GetTileAverageProcessor.cs index 6abb968..d2aa0aa 100644 --- a/Yugen.Mosaic.Uwp/Processors/GetTileAverageProcessor.cs +++ b/Yugen.Mosaic.Uwp/Processors/GetTileAverageProcessor.cs @@ -1,106 +1,105 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Primitives; -using System; -using System.Threading.Tasks; - -namespace Yugen.Mosaic.Uwp.Processors -{ - public sealed class GetTileAverageProcessor : IImageProcessor - { - public int X { get; } - public int Y { get; } - public int Width { get; } - public int Height { get; } - - public Image ResizedImage { get; } - public Rgba32[] AverageColor { get; } = new Rgba32[1]; - - public GetTileAverageProcessor(int x, int y, int width, int height, Image resizedImage) - { - X = x; - Y = y; - Width = width; - Height = height; - ResizedImage = resizedImage.CloneAs(); - } - - /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new GetTileAverageProcessor(this, source, sourceRectangle); - } - } - - public class GetTileAverageProcessor : IImageProcessor where TPixel : struct, IPixel - { - /// - /// The source instance to modify - /// - private readonly Image _source; - - private readonly int _x; - private readonly int _y; - private readonly int _width; - private readonly int _height; - - private readonly Image _resizedImage; - private readonly Rgba32[] _averageColor; - - /// - /// Initializes a new instance of the class - /// - /// The defining the processor parameters - /// The source for the current processor instance - /// The source area to process for the current processor instance - public GetTileAverageProcessor(GetTileAverageProcessor definition, Image source, Rectangle sourceRectangle) - { - _source = source; - - _x = definition.X; - _y = definition.Y; - _width = definition.Width; - _height = definition.Height; - - _resizedImage = definition.ResizedImage; - _averageColor = definition.AverageColor; - } - - /// - public void Apply() - { - _resizedImage.Mutate(x => x.Resize(_width, _height)); - - long aR = 0; - long aG = 0; - long aB = 0; - - Parallel.For(_y, _y+_height, h => - { - var rowSpan = _resizedImage.GetPixelRowSpan(h); - - for (int w = _x; w < _x + _width; w++) - { - Rgba32 pixel = new Rgba32(); - rowSpan[w].ToRgba32(ref pixel); - - aR += pixel.R; - aG += pixel.G; - aB += pixel.B; - } - }); - - aR /= _width * _height; - aG /= _width * _height; - aB /= _width * _height; - - _averageColor[0] = new Rgba32(Convert.ToByte(aR), Convert.ToByte(aG), Convert.ToByte(aB)); - } - - /// - public void Dispose() { } - } -} +//using SixLabors.ImageSharp; +//using SixLabors.ImageSharp.PixelFormats; +//using SixLabors.ImageSharp.Processing; +//using SixLabors.ImageSharp.Processing.Processors; +//using System; +//using System.Threading.Tasks; +//using Rectangle = SixLabors.ImageSharp.Rectangle; + +//namespace Yugen.Mosaic.Uwp.Processors +//{ +// public sealed class GetTileAverageProcessor : IImageProcessor +// { +// public int X { get; } +// public int Y { get; } +// public int Width { get; } +// public int Height { get; } + +// public Image ResizedImage { get; } +// public Rgba32[] AverageColor { get; } = new Rgba32[1]; + +// public GetTileAverageProcessor(int x, int y, int width, int height, Image resizedImage) +// { +// X = x; +// Y = y; +// Width = width; +// Height = height; +// ResizedImage = resizedImage.CloneAs(); +// } + +// /// +// public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : unmanaged, IPixel +// { +// return new GetTileAverageProcessor(configuration, this, source, sourceRectangle); +// } +// } + +// public class GetTileAverageProcessor : IImageProcessor where TPixel : unmanaged, IPixel +// { +// /// +// /// The source instance to modify +// /// +// private readonly Image _source; + +// private readonly int _x; +// private readonly int _y; +// private readonly int _width; +// private readonly int _height; + +// private readonly Image _resizedImage; +// private readonly Rgba32[] _averageColor; + +// /// +// /// Initializes a new instance of the class +// /// +// /// The defining the processor parameters +// /// The source for the current processor instance +// /// The source area to process for the current processor instance +// public GetTileAverageProcessor(Configuration configuration, GetTileAverageProcessor definition, Image source, Rectangle sourceRectangle) +// { +// _source = source; + +// _x = definition.X; +// _y = definition.Y; +// _width = definition.Width; +// _height = definition.Height; + +// _resizedImage = definition.ResizedImage; +// _averageColor = definition.AverageColor; +// } + +// /// +// public void Execute() +// { +// _resizedImage.Mutate(x => x.Resize(_width, _height)); + +// long aR = 0; +// long aG = 0; +// long aB = 0; + +// Parallel.For(_y, _y+_height, h => +// { +// var rowSpan = _resizedImage.GetPixelRowSpan(h); + +// for (int w = _x; w < _x + _width; w++) +// { +// Rgba32 pixel = new Rgba32(); +// rowSpan[w].ToRgba32(ref pixel); + +// aR += pixel.R; +// aG += pixel.G; +// aB += pixel.B; +// } +// }); + +// aR /= _width * _height; +// aG /= _width * _height; +// aB /= _width * _height; + +// _averageColor[0] = new Rgba32(Convert.ToByte(aR), Convert.ToByte(aG), Convert.ToByte(aB)); +// } + +// /// +// public void Dispose() { } +// } +//} diff --git a/Yugen.Mosaic.Uwp/Processors/GetTilesAverageProcessor.cs b/Yugen.Mosaic.Uwp/Processors/GetTilesAverageProcessor.cs index d980341..ad32b4c 100644 --- a/Yugen.Mosaic.Uwp/Processors/GetTilesAverageProcessor.cs +++ b/Yugen.Mosaic.Uwp/Processors/GetTilesAverageProcessor.cs @@ -1,111 +1,110 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Primitives; -using System; -using System.Threading.Tasks; - -namespace Yugen.Mosaic.Uwp.Processors -{ - public sealed class GetTilesAverageProcessor : IImageProcessor - { - public int TX { get; } - public int TY { get; } - public Size TileSize { get; } - - public Rgba32[,] AverageColors { get; } - - public GetTilesAverageProcessor(int tX, int tY, Size tileSize, Rgba32[,] avgsMaster) - { - TX = tX; - TY = tY; - TileSize = tileSize; - - AverageColors = avgsMaster; - } - - /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new GetTilesAverageProcessor(this, source, sourceRectangle); - } - } - - public class GetTilesAverageProcessor : IImageProcessor where TPixel : struct, IPixel - { - /// - /// The source instance to modify - /// - private readonly Image _source; - - private readonly int _tX; - private readonly int _tY; - private Size _tileSize; - - private readonly Rgba32[,] _averageColors; - - /// - /// Initializes a new instance of the class - /// - /// The defining the processor parameters - /// The source for the current processor instance - /// The source area to process for the current processor instance - public GetTilesAverageProcessor(GetTilesAverageProcessor definition, Image source, Rectangle sourceRectangle) - { - _source = source; - - _tX = definition.TX; - _tY = definition.TY; - _tileSize = definition.TileSize; - - _averageColors = definition.AverageColors; - } - - /// - public void Apply() - { - Parallel.For(0, _tY, y => - { - var rowSpan = _source.GetPixelRowSpan(y); - - for (int x = 0; x < _tX; x++) - { - _averageColors[x, y].FromRgba32(GetTileAverage(_source, x * _tileSize.Width, y * _tileSize.Height, _tileSize.Width, _tileSize.Height)); - } - }); - } - - private Rgba32 GetTileAverage(Image source, int x, int y, int width, int height) - { - long aR = 0; - long aG = 0; - long aB = 0; - - Parallel.For(y, y + height, h => - { - var rowSpan = _source.GetPixelRowSpan(h); - - for (int w = x; w < x + width; w++) - { - Rgba32 pixel = new Rgba32(); - rowSpan[w].ToRgba32(ref pixel); - - aR += pixel.R; - aG += pixel.G; - aB += pixel.B; - } - }); - - aR /= width * height; - aG /= width * height; - aB /= width * height; - - return new Rgba32(Convert.ToByte(aR), Convert.ToByte(aG), Convert.ToByte(aB)); - } - - - /// - public void Dispose() { } - } -} +//using SixLabors.ImageSharp; +//using SixLabors.ImageSharp.PixelFormats; +//using SixLabors.ImageSharp.Processing.Processors; +//using System; +//using System.Threading.Tasks; +//using Rectangle = SixLabors.ImageSharp.Rectangle; + +//namespace Yugen.Mosaic.Uwp.Processors +//{ +// public sealed class GetTilesAverageProcessor : IImageProcessor +// { +// public int TX { get; } +// public int TY { get; } +// public Size TileSize { get; } + +// public Rgba32[,] AverageColors { get; } + +// public GetTilesAverageProcessor(int tX, int tY, Size tileSize, Rgba32[,] avgsMaster) +// { +// TX = tX; +// TY = tY; +// TileSize = tileSize; + +// AverageColors = avgsMaster; +// } + +// /// +// public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : unmanaged, IPixel +// { +// return new GetTilesAverageProcessor(configuration, this, source, sourceRectangle); +// } +// } + +// public class GetTilesAverageProcessor : IImageProcessor where TPixel : unmanaged, IPixel +// { +// /// +// /// The source instance to modify +// /// +// private readonly Image _source; + +// private readonly int _tX; +// private readonly int _tY; +// private Size _tileSize; + +// private readonly Rgba32[,] _averageColors; + +// /// +// /// Initializes a new instance of the class +// /// +// /// The defining the processor parameters +// /// The source for the current processor instance +// /// The source area to process for the current processor instance +// public GetTilesAverageProcessor(Configuration configuration, GetTilesAverageProcessor definition, Image source, Rectangle sourceRectangle) +// { +// _source = source; + +// _tX = definition.TX; +// _tY = definition.TY; +// _tileSize = definition.TileSize; + +// _averageColors = definition.AverageColors; +// } + +// /// +// public void Execute() +// { +// Parallel.For(0, _tY, y => +// { +// var rowSpan = _source.GetPixelRowSpan(y); + +// for (int x = 0; x < _tX; x++) +// { +// _averageColors[x, y].FromRgba32(GetTileAverage(_source, x * _tileSize.Width, y * _tileSize.Height, _tileSize.Width, _tileSize.Height)); +// } +// }); +// } + +// private Rgba32 GetTileAverage(Image source, int x, int y, int width, int height) +// { +// long aR = 0; +// long aG = 0; +// long aB = 0; + +// Parallel.For(y, y + height, h => +// { +// var rowSpan = _source.GetPixelRowSpan(h); + +// for (int w = x; w < x + width; w++) +// { +// Rgba32 pixel = new Rgba32(); +// rowSpan[w].ToRgba32(ref pixel); + +// aR += pixel.R; +// aG += pixel.G; +// aB += pixel.B; +// } +// }); + +// aR /= width * height; +// aG /= width * height; +// aB /= width * height; + +// return new Rgba32(Convert.ToByte(aR), Convert.ToByte(aG), Convert.ToByte(aB)); +// } + + +// /// +// public void Dispose() { } +// } +//} diff --git a/Yugen.Mosaic.Uwp/Processors/PlainColorProcessor.cs b/Yugen.Mosaic.Uwp/Processors/PlainColorProcessor.cs index 07c6af7..740bf6e 100644 --- a/Yugen.Mosaic.Uwp/Processors/PlainColorProcessor.cs +++ b/Yugen.Mosaic.Uwp/Processors/PlainColorProcessor.cs @@ -1,77 +1,75 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Primitives; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; +//using SixLabors.ImageSharp; +//using SixLabors.ImageSharp.PixelFormats; +//using SixLabors.ImageSharp.Processing.Processors; +//using System.Numerics; +//using System.Runtime.CompilerServices; +//using System.Threading.Tasks; -namespace Yugen.Mosaic.Uwp.Processors -{ - public sealed class PlainColorProcessor : IImageProcessor - { - public Rgba32 AverageColor { get; } +//namespace Yugen.Mosaic.Uwp.Processors +//{ +// public sealed class PlainColorProcessor : IImageProcessor +// { +// public PlainColorProcessor(Rgba32 averageColor) +// { +// AverageColor = averageColor; +// } - public PlainColorProcessor(Rgba32 averageColor) - { - AverageColor = averageColor; - } +// public Rgba32 AverageColor { get; } - /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new PlainColorProcessor(this, source, sourceRectangle); - } - } +// /// +// public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : unmanaged, IPixel +// { +// return new PlainColorProcessor(configuration, this, source, sourceRectangle); +// } +// } - public class PlainColorProcessor : IImageProcessor where TPixel : struct, IPixel - { - /// - /// The source instance to modify - /// - private readonly Image _source; +// public class PlainColorProcessor : IImageProcessor where TPixel : unmanaged, IPixel +// { +// /// +// /// The source instance to modify +// /// +// private readonly Image _source; +// private readonly Rgba32 _averageColor; - private readonly Rgba32 _averageColor; +// /// +// /// Initializes a new instance of the class +// /// +// /// The defining the processor parameters +// /// The source for the current processor instance +// /// The source area to process for the current processor instance +// public PlainColorProcessor(Configuration configuration, PlainColorProcessor definition, Image source, Rectangle sourceRectangle) +// { +// _source = source; +// _averageColor = definition.AverageColor; +// } - /// - /// Initializes a new instance of the class - /// - /// The defining the processor parameters - /// The source for the current processor instance - /// The source area to process for the current processor instance - public PlainColorProcessor(PlainColorProcessor definition, Image source, Rectangle sourceRectangle) - { - _source = source; - _averageColor = definition.AverageColor; - } +// public void Execute() +// { +// int width = _source.Width; +// Image source = _source; +// //RgbaVector averageColorVector = AverageColor.ToPixel(); - /// - public void Apply() - { - int width = _source.Width; - Image source = _source; - //RgbaVector averageColorVector = AverageColor.ToPixel(); +// var averageColor4 = _averageColor.ToVector4(); //var b = AverageColor.ToScaledVector4(); - var averageColor4 = _averageColor.ToVector4(); //var b = AverageColor.ToScaledVector4(); +// Parallel.For(0, source.Height, y => +// { +// //Vector4 averageColor4 = Unsafe.As(ref averageColorVector); +// ref TPixel r0 = ref source.GetPixelRowSpan(y).GetPinnableReference(); - Parallel.For(0, source.Height, y => - { - //Vector4 averageColor4 = Unsafe.As(ref averageColorVector); - ref TPixel r0 = ref source.GetPixelRowSpan(y).GetPinnableReference(); +// for (int x = 0; x < width; x++) +// { +// Vector4 color4 = Unsafe.Add(ref r0, x).ToVector4(); +// color4 = (color4 + averageColor4) / 2; +// color4 = Vector4.Clamp(color4, Vector4.Zero, Vector4.One); - for (int x = 0; x < width; x++) - { - Vector4 color4 = Unsafe.Add(ref r0, x).ToVector4(); - color4 = (color4 + averageColor4) / 2; - color4 = Vector4.Clamp(color4, Vector4.Zero, Vector4.One); +// Unsafe.Add(ref r0, x).FromVector4(color4); +// } +// }); +// } + +// /// +// public void Dispose() { } +// } +//} - Unsafe.Add(ref r0, x).FromVector4(color4); - } - }); - } - /// - public void Dispose() { } - } -} diff --git a/Yugen.Mosaic.Uwp/Properties/AssemblyInfo.cs b/Yugen.Mosaic.Uwp/Properties/AssemblyInfo.cs index 9a1479d..d53b0dd 100644 --- a/Yugen.Mosaic.Uwp/Properties/AssemblyInfo.cs +++ b/Yugen.Mosaic.Uwp/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Yugen.Mosaic.Uwp/Services/AdjustHueSearchAndReplaceService.cs b/Yugen.Mosaic.Uwp/Services/AdjustHueSearchAndReplaceService.cs new file mode 100644 index 0000000..37e36b7 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Services/AdjustHueSearchAndReplaceService.cs @@ -0,0 +1,91 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Yugen.Mosaic.Uwp.Models; + +namespace Yugen.Mosaic.Uwp.Services +{ + public class AdjustHueSearchAndReplaceService : SearchAndReplaceService + { + public AdjustHueSearchAndReplaceService(Image outputImage, Size tileSize, int tX, int tY, List tileImageList, Rgba32[,] avgsMaster) : base(outputImage, tileSize, tX, tY, tileImageList, avgsMaster) + { + } + + // Adjust hue - get the first (random) tile found and adjust its colours to suit the average + public override void SearchAndReplace() + { + var r = new Random(); + var tileQueue = new List(); + //int maxQueueLength = Math.Min(1000, Math.Max(0, _tileImageList.Count - 50)); + + Parallel.For(0, _tX * _tY, xy => + { + var y = xy / _tX; + var x = xy % _tX; + + // (R * ColCount) + C + var index = ((y * _tX) + x) % _tileImageList.Count; + + // Check if it's the same as the last (X)? + //if (tileQueue.Count > 1) + //{ + // while (tileQueue.Contains(_tileImageList[index])) + // { + // index = r.Next(_tileImageList.Count); + // } + //} + + // Add to the 'queue' + Tile tileFound = _tileImageList[index]; + //if (tileQueue.Count >= maxQueueLength && tileQueue.Count > 0) + // tileQueue.RemoveAt(0); + //tileQueue.Add(tileFound); + + // Adjust the hue + var adjustedImage = new Image(tileFound.ResizedImage.Width, tileFound.ResizedImage.Height); + + //var adjustHueProcessor = new AdjustHueProcessor(tileFound.ResizedImage, _avgsMaster[x, y]); + //adjustedImage.Mutate(c => c.ApplyProcessor(adjustHueProcessor)); + + AdjustHue(tileFound.ResizedImage, adjustedImage, _avgsMaster[x, y]); + + // Apply found tile to section + //var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); + //adjustedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); + + ApplyTileFoundProcessor(x, y, adjustedImage); + + //_progress++; + }); + } + + private void AdjustHue(Image source, Image output, Rgba32 averageColor) + { + output.Mutate(c => + { + Parallel.For(0, source.Height, h => + { + var rowSpan = source.GetPixelRowSpan(h); + + for (int w = 0; w < source.Width; w++) + { + Rgba32 pixel = new Rgba32(); + rowSpan[w].ToRgba32(ref pixel); + + int R = Math.Min(255, Math.Max(0, (pixel.R + averageColor.R) / 2)); + int G = Math.Min(255, Math.Max(0, (pixel.G + averageColor.G) / 2)); + int B = Math.Min(255, Math.Max(0, (pixel.B + averageColor.B) / 2)); + + Color clAvg = new Rgba32(Convert.ToByte(R), Convert.ToByte(G), Convert.ToByte(B)); + + Rgba32 pixelColor = clAvg.ToPixel(); + output[w, h] = pixelColor; + } + }); + }); + } + } +} diff --git a/Yugen.Mosaic.Uwp/Services/ClassicSearchAndReplaceService.cs b/Yugen.Mosaic.Uwp/Services/ClassicSearchAndReplaceService.cs new file mode 100644 index 0000000..e032885 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Services/ClassicSearchAndReplaceService.cs @@ -0,0 +1,49 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System.Collections.Generic; +using System.Threading.Tasks; +using Yugen.Mosaic.Uwp.Helpers; +using Yugen.Mosaic.Uwp.Models; + +namespace Yugen.Mosaic.Uwp.Services +{ + public class ClassicSearchAndReplaceService : SearchAndReplaceService + { + public ClassicSearchAndReplaceService(Image outputImage, Size tileSize, int tX, int tY, List tileImageList, Rgba32[,] avgsMaster) : base(outputImage, tileSize, tX, tY, tileImageList, avgsMaster) + { + } + + public override void SearchAndReplace() + { + Parallel.For(0, _tX * _tY, xy => + { + int y = xy / _tX; + int x = xy % _tX; + + int index = 0; + int difference = 100; + Tile tileFound = _tileImageList[0]; + + // Search for a tile with a similar color + foreach (var tile in _tileImageList) + { + var newDifference = ColorHelper.GetDifference(_avgsMaster[x, y], _tileImageList[index].AverageColor); + if (newDifference < difference) + { + tileFound = _tileImageList[index]; + difference = newDifference; + } + index++; + } + + // Apply found tile to section + //var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); + //tileFound.ResizedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); + + ApplyTileFoundProcessor(x, y, tileFound.ResizedImage); + + //_progress++; + }); + } + } +} diff --git a/Yugen.Mosaic.Uwp/Services/MosaicService.cs b/Yugen.Mosaic.Uwp/Services/MosaicService.cs index 133ac21..3333fab 100644 --- a/Yugen.Mosaic.Uwp/Services/MosaicService.cs +++ b/Yugen.Mosaic.Uwp/Services/MosaicService.cs @@ -1,7 +1,6 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; using System; using System.Collections.Generic; using System.IO; @@ -9,23 +8,24 @@ using System.Threading.Tasks; using Windows.Storage.Streams; using Windows.UI.Xaml.Media.Imaging; +using Yugen.Mosaic.Uwp.Helpers; +using Yugen.Mosaic.Uwp.Interfaces; using Yugen.Mosaic.Uwp.Models; -using Yugen.Mosaic.Uwp.Processors; namespace Yugen.Mosaic.Uwp.Services { - public class MosaicService + public class MosaicService : IMosaicService { private Image _masterImage; - private List _tileImageList { get; set; } = new List(); + internal List _tileImageList { get; set; } = new List(); private Size _tileSize; - private int _tX; - private int _tY; - private Rgba32[,] _avgsMaster; + internal int _tX; + internal int _tY; + internal Rgba32[,] _avgsMaster; - private int _progress; + internal int _progress; private int _progressMax; @@ -44,9 +44,11 @@ public Image AddTileImage(string name, Stream stream) public void RemoveTileImage(string name) { - var item = _tileImageList.FirstOrDefault(x => x.Name.Equals(name)); + Tile item = _tileImageList.FirstOrDefault(x => x.Name.Equals(name)); if (item != null) + { _tileImageList.Remove(item); + } } public Image GetResizedImage(Image image, int size) @@ -62,7 +64,7 @@ public Image GetResizedImage(Image image, int size) public InMemoryRandomAccessStream GetStream(Image image) { - InMemoryRandomAccessStream outputStream = new InMemoryRandomAccessStream(); + var outputStream = new InMemoryRandomAccessStream(); image.SaveAsJpeg(outputStream.AsStreamForWrite()); outputStream.Seek(0); return outputStream; @@ -72,7 +74,9 @@ public InMemoryRandomAccessStream GetStream(Image image) public Image GenerateMosaic(Size outputSize, Size tileSize, int mosaicType) { if (_masterImage == null || (mosaicType != 2 && _tileImageList.Count < 1)) + { return null; + } Image resizedMasterImage = _masterImage.Clone(x => x.Resize(outputSize.Width, outputSize.Height)); @@ -91,24 +95,35 @@ public Image GenerateMosaic(Size outputSize, Size tileSize, int mosaicTy } - private void GetTilesAverage(Image masterImage) - { - var getTilesAverageProcessor = new GetTilesAverageProcessor(_tX, _tY, _tileSize, _avgsMaster); - masterImage.Mutate(c => c.ApplyProcessor(getTilesAverageProcessor)); - } + private void GetTilesAverage(Image masterImage) => + //var getTilesAverageProcessor = new GetTilesAverageProcessor(_tX, _tY, _tileSize, _avgsMaster); + //masterImage.Mutate(c => c.ApplyProcessor(getTilesAverageProcessor)); + + Parallel.For(0, _tY, y => + { + Span rowSpan = masterImage.GetPixelRowSpan(y); + + for (var x = 0; x < _tX; x++) + { + _avgsMaster[x, y].FromRgba32(ColorHelper.GetAverageColor(masterImage, x, y, _tileSize)); + } + }); private void LoadTilesAndResize() { _progressMax = _tileImageList.Count; _progress = 0; - foreach (var tile in _tileImageList) + foreach (Tile tile in _tileImageList) { - var getTileAverageProcessor = new GetTileAverageProcessor(0, 0, _tileSize.Width, _tileSize.Height, tile.OriginalImage); - tile.OriginalImage.Mutate(c => c.ApplyProcessor(getTileAverageProcessor)); + //var getTileAverageProcessor = new GetTileAverageProcessor(0, 0, _tileSize.Width, _tileSize.Height, tile.OriginalImage); + //tile.OriginalImage.Mutate(c => c.ApplyProcessor(getTileAverageProcessor)); + //tile.ResizedImage = getTileAverageProcessor.ResizedImage; + //tile.AverageColor = getTileAverageProcessor.AverageColor[0]; - tile.ResizedImage = getTileAverageProcessor.ResizedImage; - tile.AverageColor = getTileAverageProcessor.AverageColor[0]; + tile.ResizedImage = tile.OriginalImage.CloneAs(); ; + tile.ResizedImage.Mutate(x => x.Resize(_tileSize.Width, _tileSize.Height)); + tile.AverageColor = ColorHelper.GetAverageColor(tile.ResizedImage); _progress++; } @@ -120,19 +135,25 @@ private void SearchAndReplace(Image outputImage, Size tileSize, int mosa _progressMax = _tileImageList.Count; _progress = 0; + ISearchAndReplaceService SearchAndReplaceService; + switch (mosaicType) { case 0: - SearchAndReplaceClassic(outputImage, tileSize); + SearchAndReplaceService = new ClassicSearchAndReplaceService(outputImage, tileSize, _tX, _tY, _tileImageList, _avgsMaster); + SearchAndReplaceService.SearchAndReplace(); break; case 1: - SearchAndReplaceRandom(outputImage, tileSize); + SearchAndReplaceService = new RandomSearchAndReplaceService(outputImage, tileSize, _tX, _tY, _tileImageList, _avgsMaster); + SearchAndReplaceService.SearchAndReplace(); break; case 2: - SearchAndReplaceAdjustHue(outputImage, tileSize); + SearchAndReplaceService = new AdjustHueSearchAndReplaceService(outputImage, tileSize, _tX, _tY, _tileImageList, _avgsMaster); + SearchAndReplaceService.SearchAndReplace(); break; case 3: - PlainColor(outputImage, tileSize); + SearchAndReplaceService = new PlainColorSearchAndReplaceService(outputImage, tileSize, _tX, _tY, _tileImageList, _avgsMaster); + SearchAndReplaceService.SearchAndReplace(); break; } @@ -140,151 +161,6 @@ private void SearchAndReplace(Image outputImage, Size tileSize, int mosa } - private void SearchAndReplaceClassic(Image outputImage, Size tileSize) - { - Parallel.For(0, _tX * _tY, xy => - { - int y = xy / _tX; - int x = xy % _tX; - - int index = 0; - int difference = 100; - Tile tileFound = _tileImageList[0]; - - // Search for a tile with a similar color - foreach (var tile in _tileImageList) - { - var newDifference = GetDifference(_avgsMaster[x, y], _tileImageList[index].AverageColor); - if (newDifference < difference) - { - tileFound = _tileImageList[index]; - difference = newDifference; - } - index++; - } - - // Apply found tile to section - var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); - tileFound.ResizedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); - - _progress++; - }); - } - - // Don't adjust hue - keep searching for a tile close enough - private void SearchAndReplaceRandom(Image outputImage, Size tileSize) - { - Random r = new Random(); - - Parallel.For(0, _tX * _tY, xy => - { - int y = xy / _tX; - int x = xy % _tX; - - // Reset searching variables - int threshold = 0; - int searchCounter = 0; - Tile tileFound = null; - - // Search for a tile with a similar color - while (tileFound == null) - { - int index = r.Next(_tileImageList.Count); - var difference = GetDifference(_avgsMaster[x, y], _tileImageList[index].AverageColor); - if (difference < threshold) - { - tileFound = _tileImageList[index]; - } - else - { - searchCounter++; - if (searchCounter >= _tileImageList.Count) - threshold += 5; - } - } - - // Apply found tile to section - var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); - tileFound.ResizedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); - - _progress++; - }); - } - - // Adjust hue - get the first (random) tile found and adjust its colours to suit the average - private void SearchAndReplaceAdjustHue(Image outputImage, Size tileSize) - { - Random r = new Random(); - List tileQueue = new List(); - int maxQueueLength = Math.Min(1000, Math.Max(0, _tileImageList.Count - 50)); - - Parallel.For(0, _tX * _tY, xy => - { - int y = xy / _tX; - int x = xy % _tX; - - int index = 0; - - // Check if it's the same as the last (X)? - if (tileQueue.Count > 1) - { - while (tileQueue.Contains(_tileImageList[index])) - { - index = r.Next(_tileImageList.Count); - } - } - - // Add to the 'queue' - Tile tileFound = _tileImageList[index]; - if (tileQueue.Count >= maxQueueLength && tileQueue.Count > 0) - tileQueue.RemoveAt(0); - tileQueue.Add(tileFound); - - // Adjust the hue - Image adjustedImage = new Image(tileFound.ResizedImage.Width, tileFound.ResizedImage.Height); - var adjustHueProcessor = new AdjustHueProcessor(tileFound.ResizedImage, _avgsMaster[x, y]); - adjustedImage.Mutate(c => c.ApplyProcessor(adjustHueProcessor)); - - // Apply found tile to section - var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); - adjustedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); - - _progress++; - }); - } - - // Use just mosic colored tiles - private void PlainColor(Image outputImage, Size tileSize) - { - Parallel.For(0, _tX * _tY, xy => - { - int y = xy / _tX; - int x = xy % _tX; - - // Generate colored tile - Image adjustedImage = new Image(tileSize.Width, tileSize.Height); - var plainColorProcessor = new PlainColorProcessor(_avgsMaster[x, y]); - adjustedImage.Mutate(c => c.ApplyProcessor(plainColorProcessor)); - - // Apply found tile to section - var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); - adjustedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); - - _progress++; - }); - } - - - private int GetDifference(Rgba32 source, Rgba32 target) - { - int dR = Math.Abs(source.R - target.R); - int dG = Math.Abs(source.G - target.G); - int dB = Math.Abs(source.B - target.B); - int diff = Math.Max(dR, dG); - return Math.Max(diff, dB); - } - - public void Reset() { _masterImage = null; diff --git a/Yugen.Mosaic.Uwp/Services/PlainColorSearchAndReplaceService.cs b/Yugen.Mosaic.Uwp/Services/PlainColorSearchAndReplaceService.cs new file mode 100644 index 0000000..359093b --- /dev/null +++ b/Yugen.Mosaic.Uwp/Services/PlainColorSearchAndReplaceService.cs @@ -0,0 +1,50 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System.Collections.Generic; +using System.Numerics; +using System.Threading.Tasks; +using Yugen.Mosaic.Uwp.Models; + +namespace Yugen.Mosaic.Uwp.Services +{ + public class PlainColorSearchAndReplaceService : SearchAndReplaceService + { + public PlainColorSearchAndReplaceService(Image outputImage, Size tileSize, int tX, int tY, List tileImageList, Rgba32[,] avgsMaster) : base(outputImage, tileSize, tX, tY, tileImageList, avgsMaster) + { + } + + // Use just mosic colored tiles + public override void SearchAndReplace() + { + Parallel.For(0, _tX * _tY, xy => + { + int y = xy / _tX; + int x = xy % _tX; + + // Generate colored tile + var adjustedImage = new Image(_tileSize.Width, _tileSize.Height); + //var plainColorProcessor = new PlainColorProcessor(_avgsMaster[x, y]); + //adjustedImage.Mutate(c => c.ApplyProcessor(plainColorProcessor)); + + var averageColor4 = _avgsMaster[x, y].ToVector4(); + + adjustedImage.Mutate(c => c.ProcessPixelRowsAsVector4(row => + { + foreach (ref Vector4 pixel in row) + { + pixel = (pixel + averageColor4) / 2; + } + })); + + // Apply found tile to section + //var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); + //adjustedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); + + ApplyTileFoundProcessor(x, y, adjustedImage); + + //_progress++; + }); + } + } +} diff --git a/Yugen.Mosaic.Uwp/Services/RandomSearchAndReplaceService.cs b/Yugen.Mosaic.Uwp/Services/RandomSearchAndReplaceService.cs new file mode 100644 index 0000000..69aaf99 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Services/RandomSearchAndReplaceService.cs @@ -0,0 +1,61 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Yugen.Mosaic.Uwp.Helpers; +using Yugen.Mosaic.Uwp.Models; + +namespace Yugen.Mosaic.Uwp.Services +{ + public class RandomSearchAndReplaceService : SearchAndReplaceService + { + public RandomSearchAndReplaceService(Image outputImage, Size tileSize, int tX, int tY, List tileImageList, Rgba32[,] avgsMaster) : base(outputImage, tileSize, tX, tY, tileImageList, avgsMaster) + { + } + + // Don't adjust hue - keep searching for a tile close enough + public override void SearchAndReplace() + { + var r = new Random(); + + Parallel.For(0, _tX * _tY, xy => + { + var y = xy / _tX; + var x = xy % _tX; + + // Reset searching variables + var threshold = 0; + var searchCounter = 0; + Tile tileFound = null; + + // Search for a tile with a similar color + while (tileFound == null) + { + var index = r.Next(_tileImageList.Count); + var difference = ColorHelper.GetDifference(_avgsMaster[x, y], _tileImageList[index].AverageColor); + if (difference < threshold) + { + tileFound = _tileImageList[index]; + } + else + { + searchCounter++; + if (searchCounter >= _tileImageList.Count) + { + threshold += 5; + } + } + } + + // Apply found tile to section + //var applyTileFoundProcessor = new ApplyTileFoundProcessor(x, y, tileSize.Width, tileSize.Height, outputImage); + //tileFound.ResizedImage.Mutate(c => c.ApplyProcessor(applyTileFoundProcessor)); + + ApplyTileFoundProcessor(x, y, tileFound.ResizedImage); + + //_progress++; + }); + } + } +} diff --git a/Yugen.Mosaic.Uwp/Services/SearchAndReplaceService.cs b/Yugen.Mosaic.Uwp/Services/SearchAndReplaceService.cs new file mode 100644 index 0000000..38e4819 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Services/SearchAndReplaceService.cs @@ -0,0 +1,63 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Yugen.Mosaic.Uwp.Interfaces; +using Yugen.Mosaic.Uwp.Models; + +namespace Yugen.Mosaic.Uwp.Services +{ + public abstract class SearchAndReplaceService : ISearchAndReplaceService + { + internal readonly Image _outputImage; + internal readonly Size _tileSize; + internal readonly int _tX; + internal readonly int _tY; + internal readonly List _tileImageList; + internal readonly Rgba32[,] _avgsMaster; + + public SearchAndReplaceService(Image outputImage, Size tileSize, int tX, int tY, List tileImageList, Rgba32[,] avgsMaster) + { + _outputImage = outputImage; + _tileSize = tileSize; + _tX = tX; + _tY = tY; + _tileImageList = tileImageList; + _avgsMaster = avgsMaster; + } + + public virtual void SearchAndReplace() { } + + // TODO: c.DrawImage crash (System.NullReferenceException) + // with the current SixLabors.ImageSharp.Drawing preview version + //internal void ApplyTileFoundProcessor(int x, int y, Image source) + //{ + // _outputImage.Mutate(c => + // { + // var point = new Point(x * source.Width, y * source.Height); + // try + // { + // c.DrawImage(source, point, 1); + // } + // catch { } + // }); + //} + + internal void ApplyTileFoundProcessor(int x, int y, Image source) + { + Parallel.For(0, source.Height, h => + { + Span rowSpan = source.GetPixelRowSpan(h); + + for (var w = 0; w < source.Width; w++) + { + var pixel = new Rgba32(); + rowSpan[w].ToRgba32(ref pixel); + + _outputImage[x * source.Width + w, y * source.Height + h] = pixel; + } + }); + } + } +} diff --git a/Yugen.Mosaic.Uwp/Services/ThemeSelectorService.cs b/Yugen.Mosaic.Uwp/Services/ThemeSelectorService.cs index e7caee3..f9363b4 100644 --- a/Yugen.Mosaic.Uwp/Services/ThemeSelectorService.cs +++ b/Yugen.Mosaic.Uwp/Services/ThemeSelectorService.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Windows.ApplicationModel.Core; -using Windows.Storage; using Windows.UI; using Windows.UI.Core; using Windows.UI.ViewManagement; @@ -20,7 +19,7 @@ public static class ThemeSelectorService public static async Task InitializeAsync() { - var theme = await LoadThemeFromSettingsAsync(); + ElementTheme theme = await LoadThemeFromSettingsAsync(); await SetThemeAsync(theme); } @@ -31,7 +30,7 @@ public static async Task SetThemeAsync(ElementTheme theme) await SetRequestedThemeAsync(); await SaveThemeInSettingsAsync(Theme); - var titleBar = ApplicationView.GetForCurrentView().TitleBar; + ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar; //Active titleBar.BackgroundColor = Colors.Transparent; @@ -48,7 +47,7 @@ public static async Task SetThemeAsync(ElementTheme theme) public static async Task SetRequestedThemeAsync() { - foreach (var view in CoreApplication.Views) + foreach (CoreApplicationView view in CoreApplication.Views) { await view.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { @@ -63,7 +62,7 @@ await view.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => private static async Task LoadThemeFromSettingsAsync() { ElementTheme cacheTheme = ElementTheme.Default; - string themeName = await SettingsHelper.ReadAsync(SettingsKey); + var themeName = await SettingsHelper.ReadAsync(SettingsKey); if (!string.IsNullOrEmpty(themeName)) { @@ -73,17 +72,14 @@ private static async Task LoadThemeFromSettingsAsync() return cacheTheme; } - private static async Task SaveThemeInSettingsAsync(ElementTheme theme) - { - await SettingsHelper.WriteAsync(SettingsKey, theme.ToString()); - } + private static async Task SaveThemeInSettingsAsync(ElementTheme theme) => await SettingsHelper.WriteAsync(SettingsKey, theme.ToString()); private static T GetThemeResource(ElementTheme theme, string resKey) { - bool isLightTheme = (theme == ElementTheme.Default) + var isLightTheme = (theme == ElementTheme.Default) ? (IsSystemThemeLight()) : (theme == ElementTheme.Light); - string themeKey = isLightTheme ? "Light" : "Dark"; + var themeKey = isLightTheme ? "Light" : "Dark"; var themeDictionary = (ResourceDictionary)Application.Current.Resources.ThemeDictionaries[themeKey]; return (T)themeDictionary[resKey]; } diff --git a/Yugen.Mosaic.Uwp/SettingsDialog.xaml.cs b/Yugen.Mosaic.Uwp/SettingsDialog.xaml.cs index 53771c2..21515c4 100644 --- a/Yugen.Mosaic.Uwp/SettingsDialog.xaml.cs +++ b/Yugen.Mosaic.Uwp/SettingsDialog.xaml.cs @@ -9,12 +9,9 @@ public sealed partial class SettingsDialog : ContentDialog { public SettingsDialog() { - this.InitializeComponent(); + InitializeComponent(); } - private void Button_Tapped(object sender, TappedRoutedEventArgs e) - { - Hide(); - } + private void Button_Tapped(object sender, TappedRoutedEventArgs e) => Hide(); } } diff --git a/Yugen.Mosaic.Uwp/Strings/en-US/Resources.resw b/Yugen.Mosaic.Uwp/Strings/en-US/Resources.resw new file mode 100644 index 0000000..b7510e5 --- /dev/null +++ b/Yugen.Mosaic.Uwp/Strings/en-US/Resources.resw @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Add a list of Tile Images, Yugen Mosaic will use as tiles to build your mosaic + + + Create a Tile Images List + + + Create the mosaic. + + + Create the Mosaic + + + Choose what image you want to use as the Matrix of the mosaic. Yugen Mosaic will create a mosaic as close as possible to the main image. + + + Select the Main Image + + + Choose the tpe of mosaic. + + + MosaicType + + + Choose the size of the mosaic. + + + Set the parameters of the Mosaic + + + The last step is to save the mosaic. + + + Save the Mosaic + + + After you created the Tile Images List, it is necessary to set all the parameters of the mosaic. Here you can set the size of every single tile + + + TileProperties + + \ No newline at end of file diff --git a/Yugen.Mosaic.Uwp/ViewModels/MainViewModel.cs b/Yugen.Mosaic.Uwp/ViewModels/MainViewModel.cs index 8517bc5..2ffe53b 100644 --- a/Yugen.Mosaic.Uwp/ViewModels/MainViewModel.cs +++ b/Yugen.Mosaic.Uwp/ViewModels/MainViewModel.cs @@ -2,7 +2,6 @@ using Microsoft.UI.Xaml.Controls; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -31,16 +30,16 @@ public class MainViewModel : BaseViewModel public BitmapImage MasterBpmSource { - get { return _masterBmpSource; } - set { Set(ref _masterBmpSource, value); } + get => _masterBmpSource; + set => Set(ref _masterBmpSource, value); } private bool _isAddMasterUIVisible = true; public bool IsAddMasterUIVisible { - get { return _isAddMasterUIVisible; } - set { Set(ref _isAddMasterUIVisible, value); } + get => _isAddMasterUIVisible; + set => Set(ref _isAddMasterUIVisible, value); } @@ -48,16 +47,16 @@ public bool IsAddMasterUIVisible public int TileWidth { - get { return _tileWidth; } - set { Set(ref _tileWidth, value); } + get => _tileWidth; + set => Set(ref _tileWidth, value); } private int _tileHeight = 25; public int TileHeight { - get { return _tileHeight; } - set { Set(ref _tileHeight, value); } + get => _tileHeight; + set => Set(ref _tileHeight, value); } private Size TileSize => new Size(_tileWidth, _tileHeight); @@ -66,8 +65,8 @@ public int TileHeight public ObservableCollection TileBmpCollection { - get { return _tileBmpCollection; } - set { Set(ref _tileBmpCollection, value); } + get => _tileBmpCollection; + set => Set(ref _tileBmpCollection, value); } @@ -75,24 +74,24 @@ public ObservableCollection TileBmpCollection public BitmapImage OutputBmpSource { - get { return _outputBmpSource; } - set { Set(ref _outputBmpSource, value); } + get => _outputBmpSource; + set => Set(ref _outputBmpSource, value); } private int _outputWidth = 1000; public int OutputWidth { - get { return _outputWidth; } - set { Set(ref _outputWidth, value); } + get => _outputWidth; + set => Set(ref _outputWidth, value); } private int _outputHeight = 1000; public int OutputHeight { - get { return _outputHeight; } - set { Set(ref _outputHeight, value); } + get => _outputHeight; + set => Set(ref _outputHeight, value); } private Size OutputSize => new Size(_outputWidth, _outputHeight); @@ -102,8 +101,8 @@ public int OutputHeight public bool IsAlignmentGridVisibile { - get { return _isAlignmentGridVisibile; } - set { Set(ref _isAlignmentGridVisibile, value); } + get => _isAlignmentGridVisibile; + set => Set(ref _isAlignmentGridVisibile, value); } @@ -119,8 +118,8 @@ public bool IsAlignmentGridVisibile public MosaicType SelectedMosaicType { - get { return _selectedMosaicType; } - set { Set(ref _selectedMosaicType, value); } + get => _selectedMosaicType; + set => Set(ref _selectedMosaicType, value); } @@ -128,8 +127,8 @@ public MosaicType SelectedMosaicType public bool IsLoading { - get { return _isLoading; } - set { Set(ref _isLoading, value); } + get => _isLoading; + set => Set(ref _isLoading, value); } private readonly MosaicService _mosaicService = new MosaicService(); @@ -141,32 +140,32 @@ public bool IsLoading public bool IsTeachingTipOpen { - get { return _isTeachingTipOpen; } - set { Set(ref _isTeachingTipOpen, value); } + get => _isTeachingTipOpen; + set => Set(ref _isTeachingTipOpen, value); } private string _teachingTipTitle; public string TeachingTipTitle { - get { return _teachingTipTitle; } - set { Set(ref _teachingTipTitle, value); } + get => _teachingTipTitle; + set => Set(ref _teachingTipTitle, value); } private string _teachingTipSubTitle; public string TeachingTipSubTitle { - get { return _teachingTipSubTitle; } - set { Set(ref _teachingTipSubTitle, value); } + get => _teachingTipSubTitle; + set => Set(ref _teachingTipSubTitle, value); } private FrameworkElement _teachingTipTarget; public FrameworkElement TeachingTipTarget { - get { return _teachingTipTarget; } - set { Set(ref _teachingTipTarget, value); } + get => _teachingTipTarget; + set => Set(ref _teachingTipTarget, value); } @@ -176,47 +175,28 @@ public MainViewModel() } - public void Grid_PointerEntered(object sender, PointerRoutedEventArgs e) - { - IsAddMasterUIVisible = true; - } + public void Grid_PointerEntered(object sender, PointerRoutedEventArgs e) => IsAddMasterUIVisible = true; - public void Grid_PointerExited(object sender, PointerRoutedEventArgs e) - { - UpdateIsAddMasterUIVisible(); - } + public void Grid_PointerExited(object sender, PointerRoutedEventArgs e) => UpdateIsAddMasterUIVisible(); - private void UpdateIsAddMasterUIVisible() - { - IsAddMasterUIVisible = (MasterBpmSource.PixelWidth > 0 && MasterBpmSource.PixelHeight > 0) ? false : true; - } + private void UpdateIsAddMasterUIVisible() => IsAddMasterUIVisible = (MasterBpmSource.PixelWidth > 0 && MasterBpmSource.PixelHeight > 0) ? false : true; - public void AddMasterGrid_Tapped(object sender, TappedRoutedEventArgs e) - { - AddMaster().FireAndForgetSafeAsync(); - } + public void AddMasterGrid_Tapped(object sender, TappedRoutedEventArgs e) => AddMaster().FireAndForgetSafeAsync(); - public void AddTilesButton_Click(object sender, RoutedEventArgs e) - { - AddTiles((Button) sender).FireAndForgetSafeAsync(); - } + public void AddTilesButton_Click(object sender, RoutedEventArgs e) => AddTiles((Button)sender).FireAndForgetSafeAsync(); public void AdaptiveGridView_ItemClick(object sender, ItemClickEventArgs e) { if (e.ClickedItem is TileBmp item) + { RemoveTile(item).FireAndForgetSafeAsync(); + } } - public void GenerateButton_Click(object sender, RoutedEventArgs e) - { - Generate((Button) sender).FireAndForgetSafeAsync(); - } + public void GenerateButton_Click(object sender, RoutedEventArgs e) => Generate((Button)sender).FireAndForgetSafeAsync(); - public void SaveButton_Click(object sender, RoutedEventArgs e) - { - Save((Button) sender).FireAndForgetSafeAsync(); - } + public void SaveButton_Click(object sender, RoutedEventArgs e) => Save((Button)sender).FireAndForgetSafeAsync(); public void ResetButton_Click(object sender, RoutedEventArgs e) { @@ -236,26 +216,23 @@ public void HelpButton_Click(object sender, RoutedEventArgs e) ShowTeachingTip(); } - public void SettingsButton_Click(object sender, RoutedEventArgs e) - { - Settings().FireAndForgetSafeAsync(); - } + public void SettingsButton_Click(object sender, RoutedEventArgs e) => Settings().FireAndForgetSafeAsync(); private async Task AddMaster() { IsLoading = true; - var masterFile = await FilePickerHelper.OpenFile( - new List {".jpg", ".png"}, + StorageFile masterFile = await FilePickerHelper.OpenFile( + new List { ".jpg", ".png" }, Windows.Storage.Pickers.PickerLocationId.PicturesLibrary); if (masterFile != null) { - using (var inputStream = await masterFile.OpenReadAsync()) - using (var stream = inputStream.AsStreamForRead()) + using (IRandomAccessStreamWithContentType inputStream = await masterFile.OpenReadAsync()) + using (Stream stream = inputStream.AsStreamForRead()) { - var image = _mosaicService.AddMasterImage(stream); + Image image = _mosaicService.AddMasterImage(stream); using (Image copy = _mosaicService.GetResizedImage(image, 400)) { @@ -263,7 +240,7 @@ private async Task AddMaster() await MasterBpmSource.SetSourceAsync(outputStream); } - var newSize = RatioHelper.Convert(image.Width, image.Height, OutputSize.Width, OutputSize.Height); + Tuple newSize = RatioHelper.Convert(image.Width, image.Height, OutputSize.Width, OutputSize.Height); OutputWidth = newSize.Item1; OutputHeight = newSize.Item2; } @@ -276,11 +253,13 @@ private async Task AddMaster() private async Task AddTiles(Button button) { - var files = await FilePickerHelper.OpenFiles( - new List {".jpg", ".png"}, + IReadOnlyList files = await FilePickerHelper.OpenFiles( + new List { ".jpg", ".png" }, Windows.Storage.Pickers.PickerLocationId.PicturesLibrary); if (files == null) + { return; + } button.IsEnabled = false; IsLoading = true; @@ -288,10 +267,10 @@ private async Task AddTiles(Button button) await Task.Run(() => Parallel.ForEach(files, async file => { - using (var inputStream = await file.OpenReadAsync()) - using (var stream = inputStream.AsStreamForRead()) + using (IRandomAccessStreamWithContentType inputStream = await file.OpenReadAsync()) + using (Stream stream = inputStream.AsStreamForRead()) { - var image = _mosaicService.AddTileImage(file.DisplayName, stream); + Image image = _mosaicService.AddTileImage(file.DisplayName, stream); using (Image copy = _mosaicService.GetResizedImage(image, 200)) { @@ -355,13 +334,15 @@ private async Task Save(Button button) {FileFormat.Jpg.ToString(), new List() {FileFormat.Jpg.FileFormatToString()}} }; - var file = await FilePickerHelper.SaveFile("Mosaic", fileTypes, + StorageFile file = await FilePickerHelper.SaveFile("Mosaic", fileTypes, Windows.Storage.Pickers.PickerLocationId.PicturesLibrary); if (file == null || _outputImage == null) + { return; + } - using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite)) + using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite)) { switch (file.FileType) { @@ -387,8 +368,12 @@ private async Task Settings() public void ShowTeachingTip() { - var onboardingElement = OnboardingHelper.ShowTeachingTip(); - if (onboardingElement == null) return; + OnboardingElement onboardingElement = OnboardingHelper.ShowTeachingTip(); + if (onboardingElement == null) + { + return; + } + TeachingTipTitle = onboardingElement.Title; TeachingTipSubTitle = onboardingElement.Subtitle; TeachingTipTarget = onboardingElement.Target; @@ -403,10 +388,7 @@ public void TeachingTip_Closing(TeachingTip sender, TeachingTipClosingEventArgs IsTeachingTipOpen = false; } - public void TeachingTip_Closed(TeachingTip sender, TeachingTipClosedEventArgs args) - { - ShowTeachingTip(); - } + public void TeachingTip_Closed(TeachingTip sender, TeachingTipClosedEventArgs args) => ShowTeachingTip(); public void TeachingTip_ActionButtonClick(TeachingTip sender, object args) { diff --git a/Yugen.Mosaic.Uwp/ViewModels/SettingsViewModel.cs b/Yugen.Mosaic.Uwp/ViewModels/SettingsViewModel.cs index 7599402..9a96ee4 100644 --- a/Yugen.Mosaic.Uwp/ViewModels/SettingsViewModel.cs +++ b/Yugen.Mosaic.Uwp/ViewModels/SettingsViewModel.cs @@ -9,7 +9,7 @@ namespace Yugen.Mosaic.Uwp.ViewModels { - public class SettingsViewModel: BaseViewModel + public class SettingsViewModel : BaseViewModel { private const string STORE_REVIEWFORMAT = "ms-windows-store:REVIEW?PFN={0}"; private ElementTheme _elementTheme = ThemeSelectorService.Theme; @@ -18,8 +18,8 @@ public class SettingsViewModel: BaseViewModel public ElementTheme ElementTheme { - get { return _elementTheme; } - set { Set(ref _elementTheme, value); } + get => _elementTheme; + set => Set(ref _elementTheme, value); } public ICommand SwitchThemeCommand { diff --git a/Yugen.Mosaic.Uwp/Yugen.Mosaic.Uwp.csproj b/Yugen.Mosaic.Uwp/Yugen.Mosaic.Uwp.csproj index aafb144..49fdd2a 100644 --- a/Yugen.Mosaic.Uwp/Yugen.Mosaic.Uwp.csproj +++ b/Yugen.Mosaic.Uwp/Yugen.Mosaic.Uwp.csproj @@ -17,8 +17,9 @@ 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} true - True - 8972A44B0B859E4F8EC723E9536C0770C8309EEB + False + + False SHA256 True @@ -137,7 +138,10 @@ + + + MainPage.xaml @@ -148,7 +152,15 @@ + + + + + + + + SettingsDialog.xaml @@ -235,10 +247,10 @@ - 3.1.0 + 3.2.1 - 3.1.0 + 3.2.1 6.2.10 @@ -256,7 +268,7 @@ 2.3.200213001 - 1.0.0-beta0007 + 1.0.0-rc0001 1.0.0-beta0007 @@ -265,16 +277,18 @@ 1.6.5 - 1.0.20 + 1.0.22 - 1.0.20 + 1.0.22 - 1.0.20 + 1.0.22 - + + + 14.0