diff --git a/Controls/Metadata.xaml b/Controls/Metadata.xaml
index df5d61b..45f1c7b 100644
--- a/Controls/Metadata.xaml
+++ b/Controls/Metadata.xaml
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DolphinDynamicInputTextureCreator.Controls"
+ xmlns:converters="clr-namespace:DolphinDynamicInputTextureCreator.ValueConverters"
mc:Ignorable="d"
Height="220" Width="320">
@@ -31,6 +32,8 @@
+
+
diff --git a/DolphinDynamicInputTexture/Data/DynamicInputPack.cs b/DolphinDynamicInputTexture/Data/DynamicInputPack.cs
index b02a6e2..5e9c754 100644
--- a/DolphinDynamicInputTexture/Data/DynamicInputPack.cs
+++ b/DolphinDynamicInputTexture/Data/DynamicInputPack.cs
@@ -121,8 +121,8 @@ public string GameID
/// export directory
public void ExportToLocation(string location)
{
- WriteJson(Path.Combine(location, GeneratedJsonName + ".json"));
WriteImages(location);
+ WriteJson(Path.Combine(location, GeneratedJsonName + ".json"));
WriteGameID(location);
}
@@ -153,6 +153,7 @@ private void WriteImages(string location)
{
//exports the images for the output_textures
WriteImage(location, texture);
+
foreach (HostDevice device in texture.HostDevices)
{
foreach (HostKey key in device.HostKeys)
@@ -164,7 +165,7 @@ private void WriteImages(string location)
}
}
- private void WriteImage(string location, Interfaces.IImage image)
+ private void WriteImage(string location, IImage image)
{
// Unlikely that we get here but skip textures that don't exist
if (!File.Exists(image.TexturePath))
@@ -174,13 +175,25 @@ private void WriteImage(string location, Interfaces.IImage image)
image.RelativeTexturePath = CheckRelativeTexturePath(image);
string output_location = Path.Combine(location, image.RelativeTexturePath);
+ //create the directory when it does not exist.
+ Directory.CreateDirectory(Path.GetDirectoryName(output_location));
+
+ //Scaling of the texture if necessary
+ if (image is DynamicInputTexture texture)
+ {
+ if (texture.ExportImageScaling != 0 && texture.ExportImageScaling != texture.ImageWidthScaling)
+ {
+ texture.SetImageScaling(output_location, texture.ExportImageScaling);
+ return;
+ }
+ }
+
// Prevents the file from trying to overwrite itself.
if (Path.GetFullPath(output_location) == Path.GetFullPath(image.TexturePath))
return;
//write the image
const bool overwrite = true;
- Directory.CreateDirectory(Path.GetDirectoryName(output_location));
File.Copy(image.TexturePath, output_location, overwrite);
}
diff --git a/DolphinDynamicInputTexture/Data/DynamicInputTexture.cs b/DolphinDynamicInputTexture/Data/DynamicInputTexture.cs
index 4e6aed0..7264481 100644
--- a/DolphinDynamicInputTexture/Data/DynamicInputTexture.cs
+++ b/DolphinDynamicInputTexture/Data/DynamicInputTexture.cs
@@ -1,5 +1,6 @@
using DolphinDynamicInputTexture.Interfaces;
using Newtonsoft.Json;
+using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Drawing;
@@ -187,18 +188,98 @@ public double ImageHeightScaling
}
}
+ ///
+ /// The image size is set to a multiple of the original size when exporting.
+ /// 0 = Keep current size.
+ ///
+ public int ExportImageScaling
+ {
+ get => _export_image_scaling;
+ set
+ {
+ if (value < 0) throw new ArgumentException("cannot be less than zero", nameof(ExportImageScaling));
+
+ _export_image_scaling = (byte)value;
+ OnPropertyChanged(nameof(ExportImageScaling));
+ }
+ }
+ private byte _export_image_scaling = 0;
#endregion
#region Update
+ ///
+ /// Scales the image in relation to the original size.
+ ///
+ /// Save location of the new file
+ /// Size in relation to the original size
+ public void SetImageScaling(string savepath, int Scaling)
+ {
+ if (Scaling <= 0)
+ {
+ throw new ArgumentException("Must be at least 1 or greater", nameof(Scaling));
+ }
+
+ SetImageScaling(savepath, (int)(HashProperties.ImageWidth * Scaling), (int)(HashProperties.ImageHeight * Scaling));
+ }
+
+ ///
+ /// Scales the image to an absulute size.
+ ///
+ /// Save location of the new file
+ /// width in pixel
+ /// height in pixel
+ public void SetImageScaling(string savepath, int width, int height)
+ {
+ using(Bitmap newImage = new Bitmap(width, height))
+ {
+ using (Bitmap Image = new Bitmap(TexturePath))
+ using (Graphics graphics = Graphics.FromImage(newImage))
+ {
+ graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
+ graphics.DrawImage(Image, 0, 0, newImage.Width, newImage.Height);
+ }
+ newImage.Save(savepath, System.Drawing.Imaging.ImageFormat.Png);
+
+ // sets the new path and updates the regions to the new size.
+ TexturePath = savepath;
+ }
+ }
+
+ ///
+ /// reads the image size and adjusts the regions if necessary.
+ ///
private void UpdateImageWidthHeight()
{
if (File.Exists(_texture_path))
{
using (var bmp = new Bitmap(_texture_path))
{
- ImageHeight = bmp.Height;
- ImageWidth = bmp.Width;
+ if (ImageHeight > 0 && ImageWidth > 0)
+ {
+ double width_scale = (double)bmp.Width / ImageWidth;
+ double height_scale = (double)bmp.Height / ImageHeight;
+
+ //When scaling up, the scale must be set directly.
+ if (width_scale >= 1) ImageWidth = bmp.Width;
+ if (height_scale >= 1) ImageHeight = bmp.Height;
+
+ foreach (InputRegion region in Regions)
+ {
+ region.RegionRect.X *= width_scale;
+ region.RegionRect.Width *= width_scale;
+ region.RegionRect.Y *= height_scale;
+ region.RegionRect.Height *= height_scale;
+ }
+
+ ImageWidth = bmp.Width;
+ ImageHeight = bmp.Height;
+ }
+ else
+ {
+ ImageHeight = bmp.Height;
+ ImageWidth = bmp.Width;
+ }
}
}
}
diff --git a/ViewModels/Dialogs.cs b/ViewModels/Dialogs.cs
index b47fca6..abca180 100644
--- a/ViewModels/Dialogs.cs
+++ b/ViewModels/Dialogs.cs
@@ -124,7 +124,10 @@ public static bool DialogExportToLocation(in DynamicInputPackViewModel pack)
var dialog = new System.Windows.Forms.FolderBrowserDialog();
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
+ pack.SetExportTextureScaling();
pack.ExportToLocation(dialog.SelectedPath);
+ // Updating the user interface in case the image file has changed.
+ pack.Textures.Select(pack.Textures.Selected);
return true;
}
return false;
diff --git a/ViewModels/DynamicInputPackViewModel.cs b/ViewModels/DynamicInputPackViewModel.cs
index f5bd181..75f6b63 100644
--- a/ViewModels/DynamicInputPackViewModel.cs
+++ b/ViewModels/DynamicInputPackViewModel.cs
@@ -132,7 +132,45 @@ public bool ShouldGetHashFromTextureFilename
}
}
+ ///
+ /// List of possible texture scaling during export.
+ ///
+ public string[] ExportTextureScalingModes
+ {
+ get => _export_texture_scaling_modes ??= new string[] { "Deactivated", "Dynamic", "1x (Original Size)", "2x", "3x", "4x", "5x" , "6x", "7x", "8x" };
+ }
+ private string[] _export_texture_scaling_modes;
+
+ ///
+ /// The currently selected export texture scaling.
+ ///
+ public string SelectedExportTextureScaling
+ {
+ get => (string)ExportTextureScalingModes.GetValue(_selected_export_texture_scaling);
+ set
+ {
+ for (int i = 0; i < ExportTextureScalingModes.Length; i++)
+ {
+ if (value == ExportTextureScalingModes[i])
+ {
+ _selected_export_texture_scaling = i;
+ OnPropertyChanged(nameof(SelectedExportTextureScaling));
+ return;
+ }
+ }
+ _selected_export_texture_scaling = 0;
+ OnPropertyChanged(nameof(SelectedExportTextureScaling));
+ }
+ }
+ internal int _selected_export_texture_scaling = 0;
+
+ ///
+ /// Number of pixels that the smallest region should have at least after exporting, when the Dynamic mode is used.
+ ///
+ private int _targeted_regione_size = 96;
+
#endregion
+
#region Commands
#region SelectedTexture
@@ -331,5 +369,69 @@ public void SetInitialZoom(DynamicInputTexture Texture, double absolutescale = 6
#endregion
+ #region ExportScale
+
+ ///
+ /// set the export scale for each texture.
+ ///
+ public void SetExportTextureScaling()
+ {
+ foreach (DynamicInputTexture texture in Textures)
+ {
+ switch (_selected_export_texture_scaling)
+ {
+ case 0:
+ //(Disabled) Leaves the textures unchanged.
+ texture.ExportImageScaling = 0;
+ break;
+ case 1:
+ //(Dynamic) Calculates a good display size.
+ SetExportTextureScaling_Dynamic(texture);
+ break;
+ default:
+ //(x1-8) Use the specified scaling.
+ texture.ExportImageScaling = _selected_export_texture_scaling - 1;
+ break;
+ }
+ }
+
+ }
+
+ ///
+ /// Calculates a good texture scaling based on region size.
+ ///
+ ///
+ private void SetExportTextureScaling_Dynamic(DynamicInputTexture texture)
+ {
+ // 0 if there are no regions.
+ if (texture.Regions.Count <= 0)
+ {
+ texture.ExportImageScaling = 0;
+ return;
+ }
+
+ //calculate a scaling based on the regions.
+ int smallest_region = texture.ImageWidth;
+ foreach (InputRegion region in texture.Regions)
+ {
+ int regionsize = (int)(region.RegionRect.Height + region.RegionRect.Width) / 2;
+ if (smallest_region > regionsize)
+ {
+ smallest_region = regionsize;
+ }
+ }
+ smallest_region = (int)(smallest_region / ((texture.ImageHeightScaling + texture.ImageWidthScaling) / 2));
+ int scaling = (int)Math.Round((double)_targeted_regione_size / smallest_region, 0, MidpointRounding.AwayFromZero);
+
+ // unlikely however try to avoid too large textures.
+ int pixelsize = texture.HashProperties.ImageWidth > texture.HashProperties.ImageHeight ? texture.HashProperties.ImageWidth : texture.HashProperties.ImageHeight;
+ if (pixelsize * scaling > 4096)
+ {
+ scaling = (int)Math.Round((double)4096 / pixelsize, MidpointRounding.ToZero);
+ }
+
+ texture.ExportImageScaling = (byte)scaling;
+ }
+ #endregion
}
}