ImageInfoView.axaml.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. using System.Runtime.InteropServices;
  2. using Avalonia;
  3. using Avalonia.Controls;
  4. using Avalonia.Input;
  5. using Avalonia.Threading;
  6. using PicView.Avalonia.Navigation;
  7. using PicView.Avalonia.Resizing;
  8. using PicView.Avalonia.UI;
  9. using PicView.Avalonia.ViewModels;
  10. using PicView.Core.Conversion;
  11. using PicView.Core.Exif;
  12. using PicView.Core.Extensions;
  13. using PicView.Core.FileHandling;
  14. using PicView.Core.Sizing;
  15. using PicView.Core.Titles;
  16. using R3;
  17. namespace PicView.Avalonia.Views.Main;
  18. public partial class ImageInfoView : UserControl
  19. {
  20. private readonly CompositeDisposable _disposables = new();
  21. public ImageInfoView()
  22. {
  23. InitializeComponent();
  24. // Disable print menu on macOS
  25. // TODO: Remove this once print is implemented for macOS
  26. if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  27. {
  28. PrintMenuItem.IsVisible = false;
  29. }
  30. Loaded += (_, _) =>
  31. {
  32. if (DataContext is not MainViewModel vm)
  33. {
  34. return;
  35. }
  36. ResponsiveResizeUpdate(vm);
  37. KeyDown += (_, e) =>
  38. {
  39. switch (e.Key)
  40. {
  41. case Key.Down:
  42. case Key.PageDown:
  43. ScrollViewer.LineDown();
  44. break;
  45. case Key.Up:
  46. case Key.PageUp:
  47. ScrollViewer.LineUp();
  48. break;
  49. case Key.Home:
  50. ScrollViewer.ScrollToHome();
  51. break;
  52. case Key.End:
  53. ScrollViewer.ScrollToEnd();
  54. break;
  55. }
  56. };
  57. PointerPressed += (_, e) =>
  58. {
  59. if (!e.GetCurrentPoint(this).Properties.IsRightButtonPressed)
  60. {
  61. return;
  62. }
  63. // Context menu doesn't want to be opened normally
  64. MainContextMenu.Open();
  65. };
  66. CloseItem.Click += (_, _) => (VisualRoot as Window)?.Close();
  67. PixelWidthTextBox.KeyDown += async (s, e) => await ResizeImageOnEnter(s, e);
  68. PixelHeightTextBox.KeyDown += async (s, e) => await ResizeImageOnEnter(s, e);
  69. PixelWidthTextBox.KeyUp += delegate { AdjustAspectRatio(PixelWidthTextBox); };
  70. PixelHeightTextBox.KeyUp += delegate { AdjustAspectRatio(PixelHeightTextBox); };
  71. Observable.EveryValueChanged(vm.PicViewer.FileInfo, x => x.Value, UIHelper.GetFrameProvider)
  72. .SubscribeAwait(UpdateValuesAsync).AddTo(_disposables);
  73. SizeChanged += (_, _) => ResponsiveResizeUpdate(vm);
  74. RemoveImageDataMenuItem.Click += async (_, _) => { await RemoveImageDataAsync(); };
  75. FileNameTextBox.KeyDown += async (_, e) =>
  76. await HandleRenameOnEnterAsync(e, () =>
  77. Path.Combine(vm.PicViewer.FileInfo.CurrentValue.DirectoryName!, FileNameTextBox.Text));
  78. FullPathTextBox.KeyDown += async (_, e) =>
  79. await HandleRenameOnEnterAsync(e, () => FullPathTextBox.Text ?? string.Empty);
  80. DirectoryNameTextBox.KeyDown += async (_, e) =>
  81. await HandleRenameOnEnterAsync(e, () =>
  82. Path.Combine(DirectoryNameTextBox.Text, vm.PicViewer.FileInfo.CurrentValue.Name));
  83. // Register EXIF property updates on 'Enter' key press
  84. RegisterExifUpdateHandlers();
  85. // Orientation is for display only atm
  86. OrientationBox.DropDownClosed += (_, _) =>
  87. {
  88. OrientationBox.SelectedIndex = vm.Exif.Orientation.Value!;
  89. };
  90. // Resolution Units are for display only atm
  91. ResolutionUnitBox.DropDownClosed += (_, _) =>
  92. {
  93. ResolutionUnitBox.SelectedIndex = (int)vm.Exif.ResolutionUnit.Value!;
  94. };
  95. ColorRepresentationBox.DropDownClosed += async (_, _) =>
  96. {
  97. await AddExifPropertyAsync(ExifWriter.AddColorSpace, vm.Exif.ColorRepresentation.CurrentValue);
  98. };
  99. CompressionBox.DropDownClosed += async (_, _) =>
  100. {
  101. await AddExifPropertyAsync(ExifWriter.AddCompression, vm.Exif.Compression.CurrentValue);
  102. };
  103. vm.InfoWindow.IsLoading.Value = false;
  104. };
  105. }
  106. private async Task HandleRenameOnEnterAsync(KeyEventArgs e, Func<string> getNewPath)
  107. {
  108. if (e.Key is not Key.Enter || DataContext is not MainViewModel vm)
  109. {
  110. return;
  111. }
  112. try
  113. {
  114. var newPath = getNewPath();
  115. if (string.IsNullOrWhiteSpace(newPath))
  116. {
  117. return;
  118. }
  119. await Dispatcher.UIThread.InvokeAsync(() => SetLoadingState(true));
  120. vm.MainWindow.IsLoadingIndicatorShown.Value = true;
  121. NavigationManager.DisableWatcher();
  122. var fileInfo = vm.PicViewer.FileInfo.CurrentValue;
  123. var oldPath = fileInfo.FullName;
  124. // Avoid renaming if the path hasn't changed
  125. if (oldPath.Equals(newPath, StringComparison.OrdinalIgnoreCase))
  126. {
  127. return;
  128. }
  129. var renamed = await FileRenamer.AttemptRenameAsync(
  130. oldPath,
  131. newPath,
  132. ErrorHandling.ReloadAsync(vm),
  133. vm.PlatformService.DeleteFile(oldPath, true))
  134. .ConfigureAwait(false);
  135. if (renamed)
  136. {
  137. await NavigationManager.LoadPicFromFile(newPath, vm).ConfigureAwait(false);
  138. }
  139. }
  140. finally
  141. {
  142. await Dispatcher.UIThread.InvokeAsync(() => SetLoadingState(false));
  143. vm.MainWindow.IsLoadingIndicatorShown.Value = false;
  144. if (Settings.Navigation.IsFileWatcherEnabled)
  145. {
  146. NavigationManager.EnableWatcher();
  147. }
  148. }
  149. }
  150. private void ResponsiveResizeUpdate(MainViewModel vm)
  151. {
  152. if (!Application.Current.TryGetResource("ScrollBarThickness", Application.Current.ActualThemeVariant,
  153. out var value))
  154. {
  155. return;
  156. }
  157. if (value is not double scrollBarThickness)
  158. {
  159. return;
  160. }
  161. var panelWidth = double.IsNaN(ParentPanel.Width) ? ParentPanel.Bounds.Width : ParentPanel.Width;
  162. panelWidth = panelWidth is 0 ? MinWidth : panelWidth;
  163. vm.InfoWindow.ResponsiveResizeUpdate(panelWidth, scrollBarThickness);
  164. }
  165. private async ValueTask UpdateValuesAsync(FileInfo? fileInfo, CancellationToken cancellationToken)
  166. {
  167. if (DataContext is not MainViewModel vm || fileInfo is null)
  168. {
  169. return;
  170. }
  171. var preLoadValue = await NavigationManager.GetPreLoadValueAsync(fileInfo);
  172. await Task.Run(() =>
  173. {
  174. vm.Exif.UpdateExifValues(preLoadValue.ImageModel);
  175. }, cancellationToken);
  176. if (DirectoryNameTextBox.Text != fileInfo.DirectoryName)
  177. {
  178. DirectoryNameTextBox.Text = fileInfo.DirectoryName;
  179. }
  180. FileSizeBox.Text = vm.PicViewer.FileInfo?.CurrentValue?.Length.GetReadableFileSize();
  181. vm.PicViewer.ShouldOptimizeImageBeEnabled.Value =
  182. ConversionHelper.DetermineIfOptimizeImageShouldBeEnabled(vm.PicViewer.FileInfo?.CurrentValue);
  183. GoogleLinkButton.IsEnabled = !string.IsNullOrWhiteSpace(vm.Exif.GoogleLink.CurrentValue);
  184. BingLinkButton.IsEnabled = !string.IsNullOrWhiteSpace(vm.Exif.BingLink.CurrentValue);
  185. vm.Exif.IsExifAvailable.Value = vm.PicViewer.Format.CurrentValue.IsExifImage();
  186. }
  187. private void SetLoadingState(bool isLoading)
  188. {
  189. ParentPanel.Opacity = isLoading ? 0.1 : 1;
  190. ParentPanel.IsHitTestVisible = !isLoading;
  191. SpinWaiter.IsVisible = isLoading;
  192. }
  193. private void AdjustAspectRatio(TextBox sender)
  194. {
  195. if (DataContext is not MainViewModel vm)
  196. {
  197. return;
  198. }
  199. var aspectRatio = (double)vm.PicViewer.PixelWidth.CurrentValue / vm.PicViewer.PixelHeight.CurrentValue;
  200. AspectRatioHelper.SetAspectRatioForTextBox(PixelWidthTextBox, PixelHeightTextBox, sender == PixelWidthTextBox,
  201. aspectRatio, DataContext as MainViewModel);
  202. if (!int.TryParse(PixelWidthTextBox.Text, out var width) ||
  203. !int.TryParse(PixelHeightTextBox.Text, out var height))
  204. {
  205. return;
  206. }
  207. if (width <= 0 || height <= 0)
  208. {
  209. return;
  210. }
  211. var printSizes =
  212. PrintSizing.GetPrintSizes(width, height, vm.Exif.DpiX.CurrentValue, vm.Exif.DpiY.CurrentValue);
  213. PrintSizeInchTextBox.Text = printSizes.PrintSizeInch;
  214. PrintSizeCmTextBox.Text = printSizes.PrintSizeCm;
  215. SizeMpTextBox.Text = printSizes.SizeMp;
  216. var gcd = AspectRatioFormatter.GCD(width, height);
  217. AspectRatioTextBox.Text =
  218. AspectRatioFormatter.GetFormattedAspectRatio(gcd, vm.PicViewer.PixelWidth.CurrentValue,
  219. vm.PicViewer.PixelHeight.CurrentValue);
  220. }
  221. private static async Task DoResize(MainViewModel vm, bool isWidth, object width, object height)
  222. {
  223. if (isWidth)
  224. {
  225. if (!double.TryParse((string?)width, out var widthValue))
  226. {
  227. return;
  228. }
  229. if (widthValue > 0)
  230. {
  231. var success = await ConversionHelper.ResizeByWidth(vm.PicViewer.FileInfo.CurrentValue, widthValue)
  232. .ConfigureAwait(false);
  233. if (success)
  234. {
  235. await NavigationManager.QuickReload().ConfigureAwait(false);
  236. }
  237. }
  238. }
  239. else
  240. {
  241. if (!double.TryParse((string?)height, out var heightValue))
  242. {
  243. return;
  244. }
  245. if (heightValue > 0)
  246. {
  247. var success = await ConversionHelper.ResizeByHeight(vm.PicViewer.FileInfo.CurrentValue, heightValue)
  248. .ConfigureAwait(false);
  249. if (success)
  250. {
  251. await NavigationManager.QuickReload().ConfigureAwait(false);
  252. }
  253. }
  254. }
  255. }
  256. private async Task ResizeImageOnEnter(object? sender, KeyEventArgs e)
  257. {
  258. if (e.Key == Key.Enter)
  259. {
  260. if (DataContext is not MainViewModel vm)
  261. {
  262. return;
  263. }
  264. await Dispatcher.UIThread.InvokeAsync(() => SetLoadingState(true));
  265. try
  266. {
  267. await DoResize(vm, Equals(sender, PixelWidthTextBox), PixelWidthTextBox.Text, PixelHeightTextBox.Text)
  268. .ConfigureAwait(false);
  269. }
  270. finally
  271. {
  272. await Dispatcher.UIThread.InvokeAsync(() => SetLoadingState(false));
  273. }
  274. }
  275. }
  276. protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
  277. {
  278. base.OnDetachedFromVisualTree(e);
  279. Disposable.Dispose(_disposables);
  280. }
  281. #region EXIF Update Registration
  282. /// <summary>
  283. /// Helper method to register a KeyDown event for a TextBox to update an EXIF property.
  284. /// </summary>
  285. private void RegisterExifUpdateOnEnter(TextBox textBox, Func<Task> updateAction)
  286. {
  287. textBox.KeyDown += async (_, e) =>
  288. {
  289. if (e.Key is Key.Enter or Key.Tab)
  290. {
  291. await updateAction();
  292. }
  293. };
  294. }
  295. /// <summary>
  296. /// Registers all EXIF property update handlers.
  297. /// </summary>
  298. private void RegisterExifUpdateHandlers()
  299. {
  300. RegisterExifUpdateOnEnter(AuthorsBox, AddAuthorsAsync);
  301. RegisterExifUpdateOnEnter(CopyRightBox, AddCopyrightAsync);
  302. RegisterExifUpdateOnEnter(SoftwareBox, AddSoftwareAsync);
  303. RegisterExifUpdateOnEnter(SubjectBox, AddSubjectAsync);
  304. RegisterExifUpdateOnEnter(TitleBox, AddTitleAsync);
  305. RegisterExifUpdateOnEnter(CommentBox, AddCommentAsync);
  306. RegisterExifUpdateOnEnter(LatitudeBox, AddLatitudeAsync);
  307. RegisterExifUpdateOnEnter(LongitudeBox, AddLongitudeAsync);
  308. RegisterExifUpdateOnEnter(AltitudeBox, AddAltitudeAsync);
  309. RegisterExifUpdateOnEnter(CompressedBitsPerPixelBox, AddCompressedBitsPerPixelAsync);
  310. RegisterExifUpdateOnEnter(CameraMakerBox, AddCameraMakerAsync);
  311. RegisterExifUpdateOnEnter(CameraModelBox, AddCameraModelAsync);
  312. RegisterExifUpdateOnEnter(FNumberBox, AddFNumberAsync);
  313. RegisterExifUpdateOnEnter(MaxApertureBox, AddMaxApertureAsync);
  314. RegisterExifUpdateOnEnter(ExposureBiasBox, AddExposureBiasAsync);
  315. RegisterExifUpdateOnEnter(ExposureTimeBox, AddExposureTimeAsync);
  316. RegisterExifUpdateOnEnter(ExposureProgramBox, AddExposureProgramAsync);
  317. RegisterExifUpdateOnEnter(DigitalZoomBox, AddDigitalZoomAsync);
  318. RegisterExifUpdateOnEnter(FocalLengthBox, AddFocalLengthAsync);
  319. RegisterExifUpdateOnEnter(FocalLength35mmBox, AddFocalLength35mmAsync);
  320. RegisterExifUpdateOnEnter(IsoSpeedBox, AddIsoSpeedAsync);
  321. RegisterExifUpdateOnEnter(MeteringModeBox, AddMeteringModeAsync);
  322. RegisterExifUpdateOnEnter(ContrastBox, AddContrastAsync);
  323. RegisterExifUpdateOnEnter(SaturationBox, AddSaturationAsync);
  324. RegisterExifUpdateOnEnter(SharpnessBox, AddSharpnessAsync);
  325. RegisterExifUpdateOnEnter(WhiteBalanceBox, AddWhiteBalanceAsync);
  326. RegisterExifUpdateOnEnter(FlashEnergyBox, AddFlashEnergyAsync);
  327. RegisterExifUpdateOnEnter(FlashModeBox, AddFlashModeAsync);
  328. RegisterExifUpdateOnEnter(LightSourceBox, AddLightSourceAsync);
  329. RegisterExifUpdateOnEnter(BrightnessBox, AddBrightnessAsync);
  330. RegisterExifUpdateOnEnter(PhotometricInterpretationBox, AddPhotometricInterpretationAsync);
  331. RegisterExifUpdateOnEnter(LensMakerBox, AddLensMakerAsync);
  332. RegisterExifUpdateOnEnter(LensModelBox, AddLensModelAsync);
  333. RegisterExifUpdateOnEnter(ExifVersionBox, AddExifVersionAsync);
  334. }
  335. #endregion
  336. #region EXIF Update Methods
  337. /// <summary>
  338. /// Generic helper to add an EXIF property value to the image file.
  339. /// </summary>
  340. private async Task AddExifPropertyAsync<T>(Func<FileInfo?, T, Task<bool>> addAction, T value)
  341. {
  342. if (DataContext is not MainViewModel vm)
  343. {
  344. return;
  345. }
  346. var isAdded = await addAction(vm.PicViewer.FileInfo?.CurrentValue, value);
  347. if (isAdded)
  348. {
  349. await UpdateValuesAsync(vm.PicViewer.FileInfo?.CurrentValue, CancellationToken.None);
  350. }
  351. }
  352. public async Task RemoveImageDataAsync()
  353. {
  354. if (DataContext is not MainViewModel vm)
  355. {
  356. return;
  357. }
  358. var isRemoved = await ExifWriter.RemoveExifProfile(vm.PicViewer.FileInfo?.CurrentValue);
  359. if (isRemoved)
  360. {
  361. await UpdateValuesAsync(vm.PicViewer.FileInfo?.CurrentValue, CancellationToken.None);
  362. }
  363. }
  364. private async Task AddAuthorsAsync()
  365. {
  366. if (DataContext is MainViewModel vm)
  367. {
  368. await AddExifPropertyAsync(ExifWriter.AddAuthors, vm.Exif.Authors.CurrentValue);
  369. }
  370. }
  371. private async Task AddCopyrightAsync()
  372. {
  373. if (DataContext is MainViewModel vm)
  374. {
  375. await AddExifPropertyAsync(ExifWriter.AddCopyright, vm.Exif.Copyright.CurrentValue);
  376. }
  377. }
  378. private async Task AddSoftwareAsync()
  379. {
  380. if (DataContext is MainViewModel vm)
  381. {
  382. await AddExifPropertyAsync(ExifWriter.AddSoftware, vm.Exif.Software.CurrentValue);
  383. }
  384. }
  385. private async Task AddSubjectAsync()
  386. {
  387. if (DataContext is MainViewModel vm)
  388. {
  389. await AddExifPropertyAsync(ExifWriter.AddSubject, vm.Exif.Subject.CurrentValue);
  390. }
  391. }
  392. private async Task AddTitleAsync()
  393. {
  394. if (DataContext is MainViewModel vm)
  395. {
  396. await AddExifPropertyAsync(ExifWriter.AddTitle, vm.Exif.Title.CurrentValue);
  397. }
  398. }
  399. private async Task AddCommentAsync()
  400. {
  401. if (DataContext is MainViewModel vm)
  402. {
  403. await AddExifPropertyAsync(ExifWriter.AddComment, vm.Exif.Comment.CurrentValue);
  404. }
  405. }
  406. private async Task AddLatitudeAsync()
  407. {
  408. if (DataContext is MainViewModel vm)
  409. {
  410. await AddExifPropertyAsync(GpsHelper.AddLatitude, vm.Exif.Latitude.CurrentValue);
  411. }
  412. }
  413. private async Task AddLongitudeAsync()
  414. {
  415. if (DataContext is MainViewModel vm)
  416. {
  417. await AddExifPropertyAsync(GpsHelper.AddLongitude, vm.Exif.Longitude.CurrentValue);
  418. }
  419. }
  420. private async Task AddAltitudeAsync()
  421. {
  422. if (DataContext is MainViewModel vm)
  423. {
  424. await AddExifPropertyAsync(GpsHelper.AddAltitude, vm.Exif.Altitude.CurrentValue);
  425. }
  426. }
  427. private async Task AddCompressionAsync()
  428. {
  429. if (DataContext is MainViewModel vm)
  430. {
  431. await AddExifPropertyAsync(ExifWriter.AddCompression, vm.Exif.Compression.CurrentValue);
  432. }
  433. }
  434. private async Task AddCompressedBitsPerPixelAsync()
  435. {
  436. if (DataContext is MainViewModel vm)
  437. {
  438. await AddExifPropertyAsync(ExifWriter.AddCompressedBitsPerPixel, vm.Exif.CompressedBitsPixel.CurrentValue);
  439. }
  440. }
  441. private async Task AddCameraMakerAsync()
  442. {
  443. if (DataContext is MainViewModel vm)
  444. {
  445. await AddExifPropertyAsync(ExifWriter.AddCameraMaker, vm.Exif.CameraMaker.CurrentValue);
  446. }
  447. }
  448. private async Task AddCameraModelAsync()
  449. {
  450. if (DataContext is MainViewModel vm)
  451. {
  452. await AddExifPropertyAsync(ExifWriter.AddCameraModel, vm.Exif.CameraModel.CurrentValue);
  453. }
  454. }
  455. private async Task AddFNumberAsync()
  456. {
  457. if (DataContext is MainViewModel vm)
  458. {
  459. await AddExifPropertyAsync(ExifWriter.AddFNumber, vm.Exif.FNumber.CurrentValue);
  460. }
  461. }
  462. private async Task AddMaxApertureAsync()
  463. {
  464. if (DataContext is MainViewModel vm)
  465. {
  466. await AddExifPropertyAsync(ExifWriter.AddMaxAperture, vm.Exif.MaxAperture.CurrentValue);
  467. }
  468. }
  469. private async Task AddExposureBiasAsync()
  470. {
  471. if (DataContext is MainViewModel vm)
  472. {
  473. await AddExifPropertyAsync(ExifWriter.AddExposureBias, vm.Exif.ExposureBias.CurrentValue);
  474. }
  475. }
  476. private async Task AddExposureTimeAsync()
  477. {
  478. if (DataContext is MainViewModel vm)
  479. {
  480. await AddExifPropertyAsync(ExifWriter.AddExposureTime, vm.Exif.ExposureTime.CurrentValue);
  481. }
  482. }
  483. private async Task AddExposureProgramAsync()
  484. {
  485. if (DataContext is MainViewModel vm)
  486. {
  487. await AddExifPropertyAsync(ExifWriter.AddExposureProgram, vm.Exif.ExposureProgram.CurrentValue);
  488. }
  489. }
  490. private async Task AddDigitalZoomAsync()
  491. {
  492. if (DataContext is MainViewModel vm)
  493. {
  494. await AddExifPropertyAsync(ExifWriter.AddDigitalZoom, vm.Exif.DigitalZoom.CurrentValue);
  495. }
  496. }
  497. private async Task AddFocalLengthAsync()
  498. {
  499. if (DataContext is MainViewModel vm)
  500. {
  501. await AddExifPropertyAsync(ExifWriter.AddFocalLength, vm.Exif.FocalLength.CurrentValue);
  502. }
  503. }
  504. private async Task AddFocalLength35mmAsync()
  505. {
  506. if (DataContext is MainViewModel vm)
  507. {
  508. await AddExifPropertyAsync(ExifWriter.AddFocalLength35mm, vm.Exif.FocalLength35Mm.CurrentValue);
  509. }
  510. }
  511. private async Task AddIsoSpeedAsync()
  512. {
  513. if (DataContext is MainViewModel vm)
  514. {
  515. await AddExifPropertyAsync(ExifWriter.AddIsoSpeed, vm.Exif.ISOSpeed.CurrentValue);
  516. }
  517. }
  518. private async Task AddMeteringModeAsync()
  519. {
  520. if (DataContext is MainViewModel vm)
  521. {
  522. await AddExifPropertyAsync(ExifWriter.AddMeteringMode, vm.Exif.MeteringMode.CurrentValue);
  523. }
  524. }
  525. private async Task AddContrastAsync()
  526. {
  527. if (DataContext is MainViewModel vm)
  528. {
  529. await AddExifPropertyAsync(ExifWriter.AddContrast, vm.Exif.Contrast.CurrentValue);
  530. }
  531. }
  532. private async Task AddSaturationAsync()
  533. {
  534. if (DataContext is MainViewModel vm)
  535. {
  536. await AddExifPropertyAsync(ExifWriter.AddSaturation, vm.Exif.Saturation.CurrentValue);
  537. }
  538. }
  539. private async Task AddSharpnessAsync()
  540. {
  541. if (DataContext is MainViewModel vm)
  542. {
  543. await AddExifPropertyAsync(ExifWriter.AddSharpness, vm.Exif.Sharpness.CurrentValue);
  544. }
  545. }
  546. private async Task AddWhiteBalanceAsync()
  547. {
  548. if (DataContext is MainViewModel vm)
  549. {
  550. await AddExifPropertyAsync(ExifWriter.AddWhiteBalance, vm.Exif.WhiteBalance.CurrentValue);
  551. }
  552. }
  553. private async Task AddFlashEnergyAsync()
  554. {
  555. if (DataContext is MainViewModel vm)
  556. {
  557. await AddExifPropertyAsync(ExifWriter.AddFlashEnergy, vm.Exif.FlashEnergy.CurrentValue);
  558. }
  559. }
  560. private async Task AddFlashModeAsync()
  561. {
  562. if (DataContext is MainViewModel vm)
  563. {
  564. await AddExifPropertyAsync(ExifWriter.AddFlashMode, vm.Exif.FlashMode.CurrentValue);
  565. }
  566. }
  567. private async Task AddLightSourceAsync()
  568. {
  569. if (DataContext is MainViewModel vm)
  570. {
  571. await AddExifPropertyAsync(ExifWriter.AddLightSource, vm.Exif.LightSource.CurrentValue);
  572. }
  573. }
  574. private async Task AddBrightnessAsync()
  575. {
  576. if (DataContext is MainViewModel vm)
  577. {
  578. await AddExifPropertyAsync(ExifWriter.AddBrightness, vm.Exif.Brightness.CurrentValue);
  579. }
  580. }
  581. private async Task AddPhotometricInterpretationAsync()
  582. {
  583. if (DataContext is MainViewModel vm)
  584. {
  585. await AddExifPropertyAsync(ExifWriter.AddPhotometricInterpretation,
  586. vm.Exif.PhotometricInterpretation.CurrentValue);
  587. }
  588. }
  589. private async Task AddLensMakerAsync()
  590. {
  591. if (DataContext is MainViewModel vm)
  592. {
  593. await AddExifPropertyAsync(ExifWriter.AddLensMaker, vm.Exif.LensMaker.CurrentValue);
  594. }
  595. }
  596. private async Task AddLensModelAsync()
  597. {
  598. if (DataContext is MainViewModel vm)
  599. {
  600. await AddExifPropertyAsync(ExifWriter.AddLensModel, vm.Exif.LensModel.CurrentValue);
  601. }
  602. }
  603. private async Task AddExifVersionAsync()
  604. {
  605. if (DataContext is MainViewModel vm)
  606. {
  607. await AddExifPropertyAsync(ExifWriter.AddExifVersion, vm.Exif.ExifVersion.CurrentValue);
  608. }
  609. }
  610. #endregion
  611. }