diff --git a/MapUiTools/WPF/MapUiTools.WPF.csproj b/MapUiTools/WPF/MapUiTools.WPF.csproj
index d0e590f..b77ab69 100644
--- a/MapUiTools/WPF/MapUiTools.WPF.csproj
+++ b/MapUiTools/WPF/MapUiTools.WPF.csproj
@@ -10,6 +10,7 @@
Copyright © 2023 Clemens Fischer
true
x64
+ false
diff --git a/PhotoLocator/Helpers/ColorToneControl.xaml b/PhotoLocator/Controls/ColorToneControl.xaml
similarity index 84%
rename from PhotoLocator/Helpers/ColorToneControl.xaml
rename to PhotoLocator/Controls/ColorToneControl.xaml
index 0be2700..eb4974e 100644
--- a/PhotoLocator/Helpers/ColorToneControl.xaml
+++ b/PhotoLocator/Controls/ColorToneControl.xaml
@@ -1,10 +1,10 @@
-
diff --git a/PhotoLocator/Helpers/ColorToneControl.xaml.cs b/PhotoLocator/Controls/ColorToneControl.xaml.cs
similarity index 99%
rename from PhotoLocator/Helpers/ColorToneControl.xaml.cs
rename to PhotoLocator/Controls/ColorToneControl.xaml.cs
index a3c7897..d69e50b 100644
--- a/PhotoLocator/Helpers/ColorToneControl.xaml.cs
+++ b/PhotoLocator/Controls/ColorToneControl.xaml.cs
@@ -1,4 +1,5 @@
using PhotoLocator.BitmapOperations;
+using PhotoLocator.Helpers;
using System;
using System.ComponentModel;
using System.Threading.Tasks;
@@ -8,7 +9,7 @@
using System.Windows.Media;
using System.Windows.Media.Imaging;
-namespace PhotoLocator.Helpers
+namespace PhotoLocator.Controls
{
///
/// Interaction logic for ColorToneControl.xaml
diff --git a/PhotoLocator/Helpers/CropControl.xaml b/PhotoLocator/Controls/CropControl.xaml
similarity index 97%
rename from PhotoLocator/Helpers/CropControl.xaml
rename to PhotoLocator/Controls/CropControl.xaml
index fd85a30..4d34aaa 100644
--- a/PhotoLocator/Helpers/CropControl.xaml
+++ b/PhotoLocator/Controls/CropControl.xaml
@@ -1,9 +1,9 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PhotoLocator/Controls/DropDownSlider.xaml.cs b/PhotoLocator/Controls/DropDownSlider.xaml.cs
new file mode 100644
index 0000000..f749329
--- /dev/null
+++ b/PhotoLocator/Controls/DropDownSlider.xaml.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace PhotoLocator.Controls;
+
+public partial class DropDownSlider : UserControl
+{
+ bool _onTextChangedRunning, _onNumericValueChangedRunning;
+
+ public DropDownSlider()
+ {
+ InitializeComponent();
+ }
+
+ public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
+ nameof(Text), typeof(string), typeof(DropDownSlider), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnTextChanged));
+
+ public string Text
+ {
+ get => (string)GetValue(TextProperty);
+ set => SetValue(TextProperty, value);
+ }
+
+ static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is not DropDownSlider control || control._onNumericValueChangedRunning)
+ return;
+ if (double.TryParse(control.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out var v))
+ {
+ control._onTextChangedRunning = true;
+ control.NumericValue = Math.Clamp(v, control.Minimum, control.Maximum);
+ control._onTextChangedRunning = false;
+ }
+ }
+
+ public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
+ nameof(Minimum), typeof(double), typeof(DropDownSlider), new PropertyMetadata(0.0));
+ public double Minimum { get => (double)GetValue(MinimumProperty); set => SetValue(MinimumProperty, value); }
+
+ public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
+ nameof(Maximum), typeof(double), typeof(DropDownSlider), new PropertyMetadata(100.0));
+ public double Maximum { get => (double)GetValue(MaximumProperty); set => SetValue(MaximumProperty, value); }
+
+ public static readonly DependencyProperty TickFrequencyProperty = DependencyProperty.Register(
+ nameof(TickFrequency), typeof(double), typeof(DropDownSlider), new PropertyMetadata(1.0));
+ public double TickFrequency { get => (double)GetValue(TickFrequencyProperty); set => SetValue(TickFrequencyProperty, value); }
+
+ public static readonly DependencyProperty NumericValueProperty = DependencyProperty.Register(
+ nameof(NumericValue), typeof(double), typeof(DropDownSlider), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnNumericValueChanged));
+ public double NumericValue { get => (double)GetValue(NumericValueProperty); set => SetValue(NumericValueProperty, value); }
+
+ public static readonly DependencyProperty DecimalsProperty = DependencyProperty.Register(
+ nameof(Decimals), typeof(int), typeof(DropDownSlider), new PropertyMetadata(1, OnFormatChanged));
+ public int Decimals { get => (int)GetValue(DecimalsProperty); set => SetValue(DecimalsProperty, value); }
+
+ public static readonly DependencyProperty SliderValueUnitsProperty = DependencyProperty.Register(
+ nameof(SliderValueUnits), typeof(string), typeof(DropDownSlider), new PropertyMetadata(string.Empty, OnFormatChanged));
+ public string SliderValueUnits { get => (string)GetValue(SliderValueUnitsProperty); set => SetValue(SliderValueUnitsProperty, value); }
+
+ static void OnFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is DropDownSlider control)
+ control.UpdateFormattedValue();
+ }
+
+ public static readonly DependencyProperty FormattedNumericValueProperty = DependencyProperty.Register(
+ nameof(FormattedNumericValue), typeof(string), typeof(DropDownSlider), new PropertyMetadata(string.Empty));
+ public string FormattedNumericValue { get => (string)GetValue(FormattedNumericValueProperty); private set => SetValue(FormattedNumericValueProperty, value); }
+
+ static void OnNumericValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is not DropDownSlider control)
+ return;
+ control._onNumericValueChangedRunning = true;
+ if (!control._onTextChangedRunning)
+ control.Text = control.NumericValue.ToString("F" + control.Decimals.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
+ control.UpdateFormattedValue();
+ control._onNumericValueChangedRunning = false;
+ }
+
+ void UpdateFormattedValue()
+ {
+ FormattedNumericValue = NumericValue.ToString("F" + Decimals.ToString(CultureInfo.InvariantCulture), CultureInfo.CurrentCulture) + SliderValueUnits;
+ }
+}
diff --git a/PhotoLocator/Helpers/IntMath.cs b/PhotoLocator/Helpers/IntMath.cs
index 89e0186..c53b1d3 100644
--- a/PhotoLocator/Helpers/IntMath.cs
+++ b/PhotoLocator/Helpers/IntMath.cs
@@ -17,6 +17,9 @@ public static int Round(double a)
return (int)Math.Round(a);
}
+ ///
+ /// Clamp without min/max check, for better performance when the caller can guarantee the value is within range.
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Clamp(int value, int min, int max)
{
diff --git a/PhotoLocator/Helpers/RealMath.cs b/PhotoLocator/Helpers/RealMath.cs
index b5bec1e..83bd83d 100644
--- a/PhotoLocator/Helpers/RealMath.cs
+++ b/PhotoLocator/Helpers/RealMath.cs
@@ -5,6 +5,9 @@ namespace PhotoLocator.Helpers
{
public static class RealMath
{
+ ///
+ /// Clamp without min/max sanity check, for better performance when the caller can guarantee that max>min
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Clamp(float value, float min, float max)
{
@@ -15,6 +18,9 @@ public static float Clamp(float value, float min, float max)
return value;
}
+ ///
+ /// Clamp without min/max sanity check, for better performance when the caller can guarantee that max>min
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Clamp(double value, double min, double max)
{
@@ -53,7 +59,6 @@ public static float SmoothStep(float x)
return (3.0f - 2.0f * x) * x * x;
}
-
///
/// Smooth step edge between min and max
///
diff --git a/PhotoLocator/Helpers/StringExtensions.cs b/PhotoLocator/Helpers/StringExtensions.cs
index fcf4607..80e393d 100644
--- a/PhotoLocator/Helpers/StringExtensions.cs
+++ b/PhotoLocator/Helpers/StringExtensions.cs
@@ -6,5 +6,10 @@ public static string TrimPath(this string path)
{
return path.Trim(' ', '"');
}
+
+ public static string TrimInvariantValue(this string str)
+ {
+ return str.Trim().Replace(',', '.');
+ }
}
}
diff --git a/PhotoLocator/LocalContrastView.xaml b/PhotoLocator/LocalContrastView.xaml
index 136b21f..4c958ef 100644
--- a/PhotoLocator/LocalContrastView.xaml
+++ b/PhotoLocator/LocalContrastView.xaml
@@ -4,7 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
- xmlns:local="clr-namespace:PhotoLocator" xmlns:helpers="clr-namespace:PhotoLocator.Helpers"
+ xmlns:local="clr-namespace:PhotoLocator" xmlns:controls="clr-namespace:PhotoLocator.Controls"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:LocalContrastViewModel, IsDesignTimeCreatable=True}"
Background="Black"
@@ -181,7 +181,7 @@
-
+
-
diff --git a/PhotoLocator/Metadata/ExifHandler.cs b/PhotoLocator/Metadata/ExifHandler.cs
index 8f79121..4f55790 100644
--- a/PhotoLocator/Metadata/ExifHandler.cs
+++ b/PhotoLocator/Metadata/ExifHandler.cs
@@ -427,6 +427,7 @@ public static void SetGeotag(BitmapMetadata metadata, Location location)
?? metadata.GetQuery(FileTimeStampQuery1) ?? metadata.GetQuery(FileTimeStampQuery2)) as string;
if (!DateTime.TryParseExact(timestampStr, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var timeStamp) &&
+ !DateTime.TryParseExact(timestampStr, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out timeStamp) &&
!DateTime.TryParse(metadata.DateTaken, out timeStamp))
return null;
diff --git a/PhotoLocator/Metadata/MaskBasedNaming.cs b/PhotoLocator/Metadata/MaskBasedNaming.cs
index 3f8a1b3..d2badd6 100644
--- a/PhotoLocator/Metadata/MaskBasedNaming.cs
+++ b/PhotoLocator/Metadata/MaskBasedNaming.cs
@@ -125,8 +125,8 @@ private void AppendMetadata(StringBuilder result, string query1, string query2)
var value = (metadata?.GetQuery(query1) ?? metadata?.GetQuery(query2))?.ToString();
if (value is null)
return;
- foreach (var ch in Path.GetInvalidFileNameChars())
- value = value.Replace(ch, '_');
+ foreach (var ch in _invalidFileNameChars)
+ value = value.Replace(ch, '-');
result.Append(value);
}
diff --git a/PhotoLocator/PhotoLocator.csproj b/PhotoLocator/PhotoLocator.csproj
index aa224f3..d04075e 100644
--- a/PhotoLocator/PhotoLocator.csproj
+++ b/PhotoLocator/PhotoLocator.csproj
@@ -15,6 +15,7 @@
CA1014,CA1309,CA1515,CA1814,CA1819,IDE0017
true
x64
+ false
false
diff --git a/PhotoLocator/VideoTransformCommands.cs b/PhotoLocator/VideoTransformCommands.cs
index ecd3cc9..bfdd1db 100644
--- a/PhotoLocator/VideoTransformCommands.cs
+++ b/PhotoLocator/VideoTransformCommands.cs
@@ -19,6 +19,7 @@
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
+using System.Windows.Threading;
namespace PhotoLocator;
@@ -32,6 +33,8 @@ public class VideoTransformCommands : INotifyPropertyChanged
readonly IMainViewModel _mainViewModel;
readonly VideoProcessing _videoTransforms;
Action? _progressCallback;
+ DispatcherTimer? _previewUpdateDelay;
+ string? _previewSkipTo;
double _progressOffset, _progressScale;
TimeSpan _inputDuration;
double _fps;
@@ -81,12 +84,14 @@ public string SkipTo
get;
set
{
- if (!SetProperty(ref field, value.Trim()))
+ if (!SetProperty(ref field, value.TrimInvariantValue()))
return;
UpdateInputArgs();
UpdateOutputArgs();
_localContrastSetup?.SourceBitmap = null;
- _mainViewModel.UpdatePreviewPictureAsync(SkipTo).WithExceptionLogging();
+ BeginPreviewUpdate(SkipTo);
+ if (double.TryParse(SkipTo, CultureInfo.InvariantCulture, out var skipToSeconds) && skipToSeconds <= SkipToSliderMax)
+ DurationSliderMax = SkipToSliderMax - skipToSeconds;
}
} = string.Empty;
@@ -95,17 +100,60 @@ public string Duration
get;
set
{
- if (!SetProperty(ref field, value.Trim()))
+ if (!SetProperty(ref field, value.TrimInvariantValue()))
return;
UpdateInputArgs();
UpdateOutputArgs();
if (string.IsNullOrEmpty(SkipTo))
- _mainViewModel.UpdatePreviewPictureAsync(Duration).WithExceptionLogging();
+ BeginPreviewUpdate(Duration);
else if (double.TryParse(SkipTo, CultureInfo.InvariantCulture, out var skipToSeconds) && double.TryParse(Duration, CultureInfo.InvariantCulture, out var durationSeconds))
- _mainViewModel.UpdatePreviewPictureAsync((skipToSeconds + durationSeconds).ToString(CultureInfo.InvariantCulture)).WithExceptionLogging();
+ BeginPreviewUpdate((skipToSeconds + durationSeconds).ToString(CultureInfo.InvariantCulture));
}
} = string.Empty;
+ public double SkipToSliderMax
+ {
+ get;
+ set => SetProperty(ref field, value);
+ } = 600;
+
+ public double DurationSliderMax
+ {
+ get;
+ set => SetProperty(ref field, value);
+ } = 600;
+
+ private void UpdateTrimSliderRanges()
+ {
+ var firstSelected = _mainViewModel.GetSelectedItems(true).First();
+ if (!firstSelected.IsVideo)
+ return;
+ try
+ {
+ SkipToSliderMax = DurationSliderMax = GetClipDurationSeconds(firstSelected.FullPath);
+ }
+ catch (Exception ex)
+ {
+ ExceptionHandler.LogException(ex);
+ }
+ }
+
+ private void BeginPreviewUpdate(string skipTo)
+ {
+ if (_previewUpdateDelay is null)
+ {
+ _previewUpdateDelay = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.5) };
+ _previewUpdateDelay.Tick += (s, e) =>
+ {
+ _previewUpdateDelay.Stop();
+ _mainViewModel.UpdatePreviewPictureAsync(_previewSkipTo).WithExceptionLogging();
+ };
+ }
+ _previewSkipTo = skipTo;
+ _previewUpdateDelay.Stop();
+ _previewUpdateDelay.Start();
+ }
+
public bool IsRotateChecked
{
get;
@@ -121,7 +169,7 @@ public string RotationAngle
get;
set
{
- if (SetProperty(ref field, value.Trim()))
+ if (SetProperty(ref field, value.TrimInvariantValue()))
UpdateProcessArgs();
}
} = string.Empty;
@@ -141,7 +189,7 @@ public string SpeedupBy
get;
set
{
- if (SetProperty(ref field, value.Trim()))
+ if (SetProperty(ref field, value.TrimInvariantValue()))
UpdateProcessArgs();
}
} = string.Empty;
@@ -188,7 +236,7 @@ public string ScaleTo
get;
set
{
- if (SetProperty(ref field, value.Trim()))
+ if (SetProperty(ref field, value.TrimInvariantValue()))
UpdateProcessArgs();
}
} = "w:h";
@@ -254,7 +302,7 @@ public string? EffectParameter
get => _effectParameter;
set
{
- if (SetProperty(ref _effectParameter, value?.Trim().Replace(',', '.')))
+ if (SetProperty(ref _effectParameter, value?.TrimInvariantValue()))
UpdateProcessArgs();
}
}
@@ -519,7 +567,7 @@ public string VideoBitRate
get;
set
{
- if (SetProperty(ref field, value.Trim()))
+ if (SetProperty(ref field, value.TrimInvariantValue()))
UpdateOutputArgs();
}
} = string.Empty;
@@ -558,7 +606,7 @@ public string RegistrationRegion
{
if (RegistrationMode == RegistrationMode.Off)
return null;
-
+
ROI? roi = null;
if (!string.IsNullOrEmpty(RegistrationRegion) && RegistrationRegion[0] != 'w')
{
@@ -669,7 +717,7 @@ private void UpdateProcessArgs()
filters.Add(effect);
else if (SelectedEffect.Tag is ParameterizedFilter effectFilter)
filters.Add(string.Format(CultureInfo.InvariantCulture, effectFilter.Filter,
- EffectParameter,
+ EffectParameter,
IsScaleChecked ? ScaleTo.Replace(':', 'x') : "1920x1080",
string.IsNullOrEmpty(FrameRate) ? "30" : FrameRate));
if (IsSpeedupChecked && (CombineFramesMode != CombineFramesMode.RollingAverage || !SpeedupByEqualsCombineFramesCount))
@@ -727,6 +775,12 @@ private void UpdateOutputArgs()
ProcessSelected.Execute(null);
});
+ private bool IsAnyProcessingSelected()
+ {
+ return IsCropChecked || IsScaleChecked || IsRotateChecked || IsStabilizeChecked || IsSpeedupChecked || IsLocalContrastChecked ||
+ IsCombineFramesOperation || SelectedEffect?.Tag is not null;
+ }
+
public ICommand Combine => new RelayCommand(o =>
{
if (_mainViewModel.GetSelectedItems(true).All(item => item.IsVideo))
@@ -745,12 +799,6 @@ private void UpdateOutputArgs()
ProcessSelected.Execute(null);
});
- private bool IsAnyProcessingSelected()
- {
- return IsCropChecked || IsScaleChecked || IsRotateChecked || IsStabilizeChecked || IsSpeedupChecked || IsLocalContrastChecked ||
- IsCombineFramesOperation || SelectedEffect?.Tag is not null;
- }
-
public ICommand CombineFade => new RelayCommand(async parameter =>
{
// Based on https://stackoverflow.com/questions/63553906/merging-multiple-video-files-with-ffmpeg-and-xfade-filter
@@ -758,8 +806,6 @@ private bool IsAnyProcessingSelected()
const double FadeDuration = 1;
const string Transition = "fade"; // See https://ffmpeg.org/ffmpeg-filters.html#xfade
- if (string.IsNullOrEmpty(_mainViewModel.Settings.ExifToolPath))
- throw new UserMessageException("ExifTool path is not set in settings, please set it before using this command");
var allSelected = _mainViewModel.GetSelectedItems(true).Where(item => item.IsVideo).ToArray();
if (allSelected.Length < 2)
throw new UserMessageException("Select at least 2 videos");
@@ -783,12 +829,7 @@ await _mainViewModel.RunProcessWithProgressBarAsync(async (progressCallback, ct)
progressCallback(-1);
var clipDurations = new double[allSelected.Length];
for (int i = 0; i < allSelected.Length; i++)
- {
- var metadata = ExifTool.LoadMetadata(allSelected[i].FullPath, _mainViewModel.Settings.ExifToolPath);
- var spanStr = metadata["Duration"];
- if (!double.TryParse(spanStr.Trim('s'), CultureInfo.InvariantCulture, out clipDurations[i]))
- clipDurations[i] = TimeSpan.Parse(spanStr, CultureInfo.InvariantCulture).TotalSeconds;
- }
+ clipDurations[i] = GetClipDurationSeconds(allSelected[i].FullPath);
var sb = new StringBuilder();
for (int i = 0; i < allSelected.Length; i++)
@@ -821,6 +862,15 @@ await _mainViewModel.RunProcessWithProgressBarAsync(async (progressCallback, ct)
await _mainViewModel.AddOrUpdateItemAsync(outFileName, false, true);
});
+ private double GetClipDurationSeconds(string fileName)
+ {
+ var metadata = ExifTool.LoadMetadata(fileName, _mainViewModel.Settings.ExifToolPath ?? throw new UserMessageException("ExifTool path not set in settings"));
+ var spanStr = metadata["Duration"];
+ if (!double.TryParse(spanStr.Trim('s'), CultureInfo.InvariantCulture, out var result))
+ result = TimeSpan.Parse(spanStr, CultureInfo.InvariantCulture).TotalSeconds;
+ return result;
+ }
+
public ICommand Compare => new RelayCommand(async o =>
{
var allSelected = _mainViewModel.GetSelectedItems(true).ToArray();
@@ -889,6 +939,7 @@ internal void CropSelected(Rect cropRectangle)
if (_localContrastSetup is not null && _localContrastSetup.SourceBitmap is not null)
_localContrastSetup.SourceBitmap = null;
var window = new VideoTransformWindow() { Owner = App.Current.MainWindow, DataContext = this };
+ window.Dispatcher.BeginInvoke(UpdateTrimSliderRanges, DispatcherPriority.Background);
try
{
if (window.ShowDialog() is not true)
@@ -896,6 +947,7 @@ internal void CropSelected(Rect cropRectangle)
}
finally
{
+ _previewUpdateDelay?.Stop();
if (_localContrastSetup is not null && _localContrastSetup.SourceBitmap is not null)
_localContrastSetup.SourceBitmap = null;
window.DataContext = null;
@@ -974,7 +1026,7 @@ await _mainViewModel.RunProcessWithProgressBarAsync(async (progressCallback, ct)
await _mainViewModel.AddOrUpdateItemAsync(outFileName, OutputMode == OutputMode.ImageSequence, true);
if (!string.IsNullOrEmpty(message) && parameter is null)
MessageBox.Show(App.Current.MainWindow, message);
- });
+ });
async Task RunStabilizePreProcessingAsync(CancellationToken ct)
{
@@ -1179,7 +1231,7 @@ private void PrepareProgressDisplay(Action? progressCallback)
{
_inputDuration = TimeSpan.FromSeconds(durationS);
_hasDuration = true;
- }
+ }
else
_hasDuration = false;
_hasFps = false;
@@ -1223,4 +1275,4 @@ private void ProcessStdError(string line)
}
}
}
-}
+}
\ No newline at end of file
diff --git a/PhotoLocator/VideoTransformWindow.xaml b/PhotoLocator/VideoTransformWindow.xaml
index 91b9a8b..44fd582 100644
--- a/PhotoLocator/VideoTransformWindow.xaml
+++ b/PhotoLocator/VideoTransformWindow.xaml
@@ -5,6 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:helpers="clr-namespace:PhotoLocator.Helpers"
xmlns:local="clr-namespace:PhotoLocator"
+ xmlns:controls="clr-namespace:PhotoLocator.Controls"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:VideoTransformCommands, IsDesignTimeCreatable=false}"
Background="Black"
@@ -23,22 +24,22 @@
-
+
-
+
-
+
-
+
@@ -202,7 +203,7 @@
-
+
diff --git a/PhotoLocatorTest/Metadata/ExifHandlerTest.cs b/PhotoLocatorTest/Metadata/ExifHandlerTest.cs
index e980436..2c30b87 100644
--- a/PhotoLocatorTest/Metadata/ExifHandlerTest.cs
+++ b/PhotoLocatorTest/Metadata/ExifHandlerTest.cs
@@ -245,7 +245,7 @@ public void GetMetadataString_ShouldFormatMetadata()
Assert.AreEqual("FC7303, 100.7m, 1/80s, f/2.8, 4.49mm, ISO100, " + JpegTestDataTimestamp, str);
}
- [TestMethod, Ignore]
+ [TestMethod, Ignore("Performance test")]
public void GetMetadataString_ShouldFormatMetadata_Performance()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
diff --git a/PhotoLocatorTest/Metadata/MaskBasedNamingTest.cs b/PhotoLocatorTest/Metadata/MaskBasedNamingTest.cs
index 22a52d4..e8f67b5 100644
--- a/PhotoLocatorTest/Metadata/MaskBasedNamingTest.cs
+++ b/PhotoLocatorTest/Metadata/MaskBasedNamingTest.cs
@@ -89,7 +89,7 @@ public void GetFileNameWithMaskDimensions()
[TestMethod]
public void GetFileNameWithMaskDescription()
{
- Assert.AreEqual("DCIM_100MEDIA_DJI_0007.JPG",
+ Assert.AreEqual("DCIM-100MEDIA-DJI_0007.JPG",
_renamer.GetFileName("|desc|"));
}
}
diff --git a/PhotoLocatorTest/PhotoLocatorTest.csproj b/PhotoLocatorTest/PhotoLocatorTest.csproj
index 7513c46..20a9232 100644
--- a/PhotoLocatorTest/PhotoLocatorTest.csproj
+++ b/PhotoLocatorTest/PhotoLocatorTest.csproj
@@ -7,6 +7,7 @@
PhotoLocator
false
x64
+ false
diff --git a/PhotoLocatorTest/PictureFileFormats/JpegliEncoderTest.cs b/PhotoLocatorTest/PictureFileFormats/JpegliEncoderTest.cs
index 353482b..cb4ebe2 100644
--- a/PhotoLocatorTest/PictureFileFormats/JpegliEncoderTest.cs
+++ b/PhotoLocatorTest/PictureFileFormats/JpegliEncoderTest.cs
@@ -1,4 +1,5 @@
using PhotoLocator.Metadata;
+using System.Diagnostics;
using System.Windows.Media.Imaging;
namespace PhotoLocator.PictureFileFormats
@@ -20,7 +21,7 @@ public void SaveToFile_ShouldIncludeMetadata()
const string TargetPathJpeg = @"jpeg.jpg";
const string TargetPathJpegli = @"jpegli.jpg";
- Console.WriteLine($"Source size: {new FileInfo(SourcePath).Length / 1024} kb");
+ Debug.WriteLine($"Source size: {new FileInfo(SourcePath).Length / 1024} kb");
using var sourceFile = File.OpenRead(SourcePath);
var source = GeneralFileFormatHandler.LoadFromStream(sourceFile, Rotation.Rotate0, int.MaxValue, true, TestContext.CancellationToken);
@@ -29,12 +30,12 @@ public void SaveToFile_ShouldIncludeMetadata()
GeneralFileFormatHandler.SaveToFile(source, TargetPathJpeg, metadata, 95);
var sizeJpeg = new FileInfo(TargetPathJpeg).Length;
- Console.WriteLine($"Dest size jpeg: {sizeJpeg / 1024} kb");
+ Debug.WriteLine($"Dest size jpeg: {sizeJpeg / 1024} kb");
JpegliEncoder.SaveToFile(source, TargetPathJpegli, metadata, 94, EncoderPath);
var sizeJpegli = new FileInfo(TargetPathJpegli).Length;
- Console.WriteLine($"Dest size jpegli: {sizeJpegli / 1024} kb");
- Console.WriteLine($"{100.0 * sizeJpegli / sizeJpeg:0.0}%");
+ Debug.WriteLine($"Dest size jpegli: {sizeJpegli / 1024} kb");
+ Debug.WriteLine($"{100.0 * sizeJpegli / sizeJpeg:0.0}%");
Assert.AreEqual(metadata!.DateTaken, ExifHandler.LoadMetadata(File.OpenRead(TargetPathJpegli))?.DateTaken);
}
diff --git a/PhotoshopImageLoader/PhotoLocator.PhotoshopImageLoader.csproj b/PhotoshopImageLoader/PhotoLocator.PhotoshopImageLoader.csproj
index 2eb90ea..2525dc7 100644
--- a/PhotoshopImageLoader/PhotoLocator.PhotoshopImageLoader.csproj
+++ b/PhotoshopImageLoader/PhotoLocator.PhotoshopImageLoader.csproj
@@ -4,6 +4,7 @@
net10.0-windows
True
x64
+ false
CA2022