Skip to content

Commit 586ad84

Browse files
committed
v1.2.2.16
1 parent cdf804c commit 586ad84

12 files changed

+207
-71
lines changed

src/AboutWindow.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
</StackPanel.Resources>
4141
<StackPanel Orientation="Horizontal" Margin="0 0 0 12">
4242
<Image Source="favicon.ico" Width="24" Height="24" Margin="0 0 4 0"/>
43-
<TextBlock Text="{Binding Path=AppName2, Source={x:Static Properties:Settings.Default}}" FontSize="24" Margin="0" VerticalAlignment="Center"/>
43+
<TextBlock x:Name="TextBlock_AppName" Text="ZDY" FontSize="24" Margin="0" VerticalAlignment="Center"/>
4444
</StackPanel>
4545

4646
<TextBlock Margin="0 0 0 7" FontSize="11" VerticalAlignment="Bottom">

src/AboutWindow.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public AboutWindow()
1818
Assembly assembly = Assembly.GetExecutingAssembly();
1919

2020
this.TextBlock_ApplicationIntPtrSize.Text = Application.Current.GetIntPtrSize().ToString();
21+
this.TextBlock_AppName.Text = Properties.Settings.Default.AppName.Substring(1);
2122
this.TextBlock_Name.Text = assembly.GetProduct();
2223
this.TextBlock_Copyright.Text = $"2022 - {DateTime.Now.Year}";
2324
this.TextBlock_Version.Text = assembly.GetFileVersion();

src/App.config

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
<setting name="AppName" serializeAs="String">
2020
<value>ZDY ' PICTURE</value>
2121
</setting>
22-
<setting name="AppName2" serializeAs="String">
23-
<value>DY ' PICTURE</value>
24-
</setting>
2522
</Zhai.PictureView.Properties.Settings>
2623
</userSettings>
2724
</configuration>

src/ImageDecoder.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Diagnostics;
66
using System.Drawing;
77
using System.IO;
8+
using System.Reflection;
89
using System.Runtime.InteropServices;
910
using System.Threading.Tasks;
1011
using System.Windows;
@@ -144,7 +145,7 @@ internal static async Task<BitmapSource> GetBitmapSourceAsync(string filename)
144145
catch (Exception e)
145146
{
146147
#if DEBUG
147-
Debug.WriteLine("RenderToBitmapSource returned " + filename + " null, \n" + e.Message);
148+
Trace.WriteLine($"{nameof(GetBitmapSourceAsync)} {filename} exception, \n {e.Message}");
148149
#endif
149150
return null;
150151
}
@@ -429,5 +430,48 @@ internal static bool TryGetExifValue(IExifValue value, out string name, out stri
429430
}
430431

431432
#endregion
433+
434+
public static async Task<bool> SaveImageAsync(Stream stream, string targetPath, int? quality = null, int? width = null, int? height = null)
435+
{
436+
try
437+
{
438+
using MagickImage magickImage = new();
439+
440+
if (stream is not null)
441+
{
442+
await magickImage.ReadAsync(stream);
443+
}
444+
else
445+
{
446+
return false;
447+
}
448+
449+
if (quality is not null)
450+
{
451+
magickImage.Quality = quality.Value;
452+
}
453+
454+
if (width is not null)
455+
{
456+
magickImage.Resize(width.Value, 0);
457+
}
458+
else if (height is not null)
459+
{
460+
magickImage.Resize(0, height.Value);
461+
}
462+
463+
await magickImage.WriteAsync(targetPath);
464+
}
465+
catch (Exception e)
466+
{
467+
#if DEBUG
468+
Trace.WriteLine($"{nameof(SaveImageAsync)} {targetPath} exception, \n {e.Message}");
469+
#endif
470+
471+
return false;
472+
}
473+
474+
return true;
475+
}
432476
}
433477
}

src/MainWindow.xaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,15 @@
227227
<ZDY:ContextMenu>
228228
<MenuItem Icon="{ZDY:Icon Kind=VuesaxOutlineDocumentCopy}" Header="复制图片" Command="{Binding ExecuteCopyCurrentPictureSourceCommand}"/>
229229
<MenuItem Icon="{ZDY:Icon Kind=Copy2}" Header="复制图片地址" Command="{Binding ExecuteCopyCurrentPicturePathCommand}"/>
230-
<MenuItem Icon="{ZDY:Icon Kind=Save}" Header="保存"/>
231-
<MenuItem Icon="{ZDY:Icon Kind=SaveAs}" Header="另存为..."/>
232-
<MenuItem Icon="{ZDY:Icon Kind=MessageEdit}" Header="重命名"/>
230+
<MenuItem Icon="{ZDY:Icon Kind=Save}" Header="保存" Command="{Binding ExecuteSaveImageCommand}"/>
231+
<MenuItem Icon="{ZDY:Icon Kind=SaveAs}" Header="另存为..." Command="{Binding ExecuteSaveAsImageCommand}"/>
233232
<MenuItem Icon="{ZDY:Icon Kind=Delete}" Header="删除" Click="DeleteButton_Click"/>
234233
<Separator/>
235234
<MenuItem Icon="{ZDY:Icon Kind=GalleryEdit}" Header="打开效果面板" Command="{Binding ExecuteTogglePictureEffectsViewCommand}" Visibility="{Binding IsShowPictureEffectsView, Converter={ZDY:BoolToInverseVisibilityConverter}}"/>
236235
<MenuItem Icon="{ZDY:Icon Kind=GalleryEdit}" Header="关闭效果面板" Command="{Binding ExecuteTogglePictureEffectsViewCommand}" Visibility="{Binding IsShowPictureEffectsView, Converter={ZDY:BoolToVisibilityConverter}}"/>
237236
<Separator/>
238237
<MenuItem Icon="{ZDY:Icon Kind=Info}" Header="图片信息" Click="InfoButton_Click"/>
238+
<MenuItem Icon="{ZDY:Icon Kind=Folder2}" Header="打开所在的文件夹" Command="{Binding ExecuteOpenTheFolderCommand}"/>
239239
</ZDY:ContextMenu>
240240
</Image.ContextMenu>
241241
</Image>
@@ -440,5 +440,6 @@
440440
</Style>
441441
</Grid.Style>
442442
</Grid>
443+
<ZDY:Hint Text="{Binding NotificationMessage}" FontWeight="Normal" CornerRadius="4" Margin="0 -160 0 0" Background="{x:Static SystemColors.HighlightBrush}" Duration="0:0:5"/>
443444
</Grid>
444445
</ZDY:GlassesWindow>

src/Picture.cs

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using SkiaSharp;
2+
using System;
23
using System.IO;
34
using System.Threading.Tasks;
45
using System.Windows.Media;
@@ -64,6 +65,27 @@ public PictureExif PictureExif
6465
set => Set(() => PictureExif, ref pictureExif, value);
6566
}
6667

68+
public Stream PictureStream
69+
{
70+
get
71+
{
72+
if (PictureSource == null) return null;
73+
74+
var ms = new MemoryStream();
75+
76+
BitmapEncoder encoder = new BmpBitmapEncoder();
77+
encoder.Frames.Add(BitmapFrame.Create(PictureSource));
78+
encoder.Save(ms);
79+
80+
if (ms.CanSeek)
81+
{
82+
ms.Seek(0, SeekOrigin.Begin);
83+
}
84+
85+
return ms;
86+
}
87+
}
88+
6789
public bool IsAnimation
6890
{
6991
get
@@ -84,6 +106,14 @@ public bool IsLoaded
84106
}
85107
}
86108

109+
public string Extension
110+
{
111+
get
112+
{
113+
return Path.GetExtension(PicturePath);
114+
}
115+
}
116+
87117
public Picture(string filename)
88118
{
89119
var file = new FileInfo(filename);
@@ -183,6 +213,18 @@ public async Task<PictureExif> LoadExif()
183213
return PictureExif;
184214
}
185215

216+
public async Task<bool> SaveAsync(string? targetPath)
217+
{
218+
if (IsLoaded)
219+
{
220+
targetPath ??= PicturePath;
221+
222+
return await ImageDecoder.SaveImageAsync(PictureStream, targetPath);
223+
}
224+
225+
return false;
226+
}
227+
186228
public bool Delete()
187229
{
188230
try
@@ -197,19 +239,6 @@ public bool Delete()
197239
}
198240
}
199241

200-
public Stream ToStream()
201-
{
202-
if (PictureSource == null) return null;
203-
204-
var ms = new MemoryStream();
205-
206-
BitmapEncoder encoder = new BmpBitmapEncoder();
207-
encoder.Frames.Add(BitmapFrame.Create(PictureSource));
208-
encoder.Save(ms);
209-
210-
return ms;
211-
}
212-
213242
public override void Cleanup()
214243
{
215244
base.Cleanup();

src/PictureSupport.cs

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,59 @@ namespace Zhai.PictureView
99
{
1010
internal static class PictureSupport
1111
{
12-
internal static string[] All { get; } = new string[] {
13-
14-
// Standards
15-
".jpg", ".jpeg", ".jpe", ".png", ".bmp", ".tif", ".tiff", ".gif", ".ico", ".jfif", ".webp", ".wbmp",
12+
internal static string[] JPEG { get; } = new string[] {
13+
".jpg", ".jpeg"
14+
};
1615

17-
// Non-standards
16+
internal static string[] PortableNetworkGraphic { get; } = new string[] {
17+
".png"
18+
};
1819

19-
// Photoshop
20-
".psd", ".psb",
20+
internal static string[] GraphicsInterchangeFormat { get; } = new string[] {
21+
".gif"
22+
};
2123

22-
// Pfim
23-
".tga", ".dds",
24+
internal static string[] Icon { get; } = new string[] {
25+
".ico"
26+
};
2427

25-
// Vector
26-
".svg", // Maybe add svgz at some point
27-
".xcf",
28+
internal static string[] Photoshop { get; } = new string[] {
29+
".psd", ".psb"
30+
};
2831

29-
// Camera
30-
".3fr", ".arw", ".cr2", ".crw", ".dcr", ".dng", ".erf", ".kdc", ".mdc", ".mef", ".mos", ".mrw", ".nef", ".nrw", ".orf",
31-
".pef", ".raf", ".raw", ".rw2", ".srf", ".x3f",
32+
internal static string[] Vector { get; } = new string[] {
33+
".svg", ".svgz"
34+
};
3235

33-
// Others
34-
".pgm", ".hdr", ".cut", ".exr", ".dib", ".heic", ".emf", ".wmf", ".wpg", ".pcx", ".xbm", ".xpm"
36+
internal static string[] Camera { get; } = new string[] {
37+
".3fr", ".arw", ".cr2", ".cr3", ".crw", ".dcr", ".dng", ".erf", ".kdc", ".mdc", ".mef", ".mos", ".mrw",
38+
".nef", ".nrw", ".orf", ".pef", ".raf", ".raw", ".rw2", ".srf", ".x3f",
39+
};
3540

41+
internal static string[] Others { get; } = new string[] {
42+
".jpe", ".bmp", ".jfif", ".webp", ".wbmp",
43+
".tif", ".tiff", ".dds", ".tga", ".heic", ".heif", ".hdr", ".xcf", ".jxl", ".jp2",
44+
".b64",
45+
".pgm", ".ppm", ".cut", ".exr", ".dib", ".emf", ".wmf", ".wpg", ".pcx", ".xbm", ".xpm",
3646
};
3747

38-
internal static string AllSupported = String.Join(";", All.Select(t => $"*{t}"));
48+
internal static string[] All { get; } = (new List<IEnumerable<string>> { JPEG, PortableNetworkGraphic, GraphicsInterchangeFormat, Icon, Photoshop, Vector, Camera, Others }).Aggregate((x, y) => x.Concat(y)).ToArray();
49+
50+
internal static string ToFilter(this IEnumerable<string> strings)
51+
{
52+
return String.Join(";", strings.Select(t => $"*{t}"));
53+
}
3954

4055
internal static string Filter { get; } =
41-
$@"All Supported ({AllSupported})|{AllSupported}|
42-
JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|
43-
Portable Network Graphic (*.png)|*.png|
44-
Graphics Interchange Format (*.gif)|*.gif|
45-
Icon (*.ico)|*.ico|
46-
Photoshop (*.psd;*.psb)|*.psd;*.psb|
47-
Pfim (*.tga;*.dds)|*.tga;*.dds|
48-
Vector (*.svg;*.xcf)|*.svg;*.xcf|
49-
Camera (*.3fr;*.arw;*.cr2;*.crw;*.dcr;*.dng;*.erf;*.kdc;*.mdc;*.mef;*.mos;*.mrw;*.nef;*.nrw;*.orf;*.pef;*.raf;*.raw;*.rw2;*.srf;*.x3f)|*.3fr;*.arw;*.cr2;*.crw;*.dcr;*.dng;*.erf;*.kdc;*.mdc;*.mef;*.mos;*.mrw;*.nef;*.nrw;*.orf;*.pef;*.raf;*.raw;*.rw2;*.srf;*.x3f|
50-
Other (*.jpe;*.tif;*.jfif;*.webp;*.wbmp;*.tiff;*.wmf;*.pgm;*.hdr;*.cut;*.exr;*.dib;*.heic;*.emf;*.wpg;*.pcx;*.xbm;*.xpm)|*.jpe;*.tif;*.jfif;*.webp;*.wbmp;*.tiff;*.wmf;*.pgm;*.hdr;*.cut;*.exr;*.dib;*.heic;*.emf;*.wpg;*.pcx;*.xbm;*.xpm|
56+
$@"All Supported ({All.ToFilter()})|{All.ToFilter()}|
57+
JPEG ({GraphicsInterchangeFormat.ToFilter()})|{Icon.ToFilter()}|
58+
Portable Network Graphic ({PortableNetworkGraphic.ToFilter()})|{PortableNetworkGraphic.ToFilter()}|
59+
Graphics Interchange Format ({GraphicsInterchangeFormat.ToFilter()})|{GraphicsInterchangeFormat.ToFilter()}|
60+
Icon ({Icon.ToFilter()})|{Icon.ToFilter()}|
61+
Photoshop ({Photoshop.ToFilter()})|{Photoshop.ToFilter()}|
62+
Vector ({Vector.ToFilter()})|{Vector.ToFilter()}|
63+
Camera ({Camera.ToFilter()})|{Camera.ToFilter()}|
64+
Others ({Others.ToFilter()})|{Others.ToFilter()}|
5165
All Files (*.*)|*.*";
5266

5367
internal static bool IsSupported(string filename) => All.Contains(Path.GetExtension(filename).ToLower());

src/PictureWindowNotification.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Zhai.Famil.Common.Mvvm;
7+
8+
namespace Zhai.PictureView
9+
{
10+
internal partial class PictureWindowViewModel : ViewModelBase
11+
{
12+
public void SendNotificationMessage(string message)
13+
{
14+
if (!String.IsNullOrWhiteSpace(message))
15+
{
16+
NotificationMessage = "";
17+
NotificationMessage = message;
18+
}
19+
}
20+
21+
private string notificationMessage;
22+
public string NotificationMessage
23+
{
24+
get { return notificationMessage; }
25+
set { Set(() => NotificationMessage, ref notificationMessage, value); }
26+
}
27+
}
28+
}

src/PictureWindowViewModel.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Collections.ObjectModel;
44
using System.ComponentModel;
5+
using System.IO;
56
using System.Linq;
67
using System.Runtime.CompilerServices;
78
using System.Text;
@@ -11,10 +12,11 @@
1112
using System.Windows.Threading;
1213
using Zhai.Famil.Common.Mvvm;
1314
using Zhai.Famil.Common.Mvvm.Command;
15+
using Zhai.Famil.Controls;
1416

1517
namespace Zhai.PictureView
1618
{
17-
internal class PictureWindowViewModel : ViewModelBase
19+
internal partial class PictureWindowViewModel : ViewModelBase
1820
{
1921
private Folder folder;
2022
public Folder Folder
@@ -171,12 +173,46 @@ public PictureWindowViewModel()
171173

172174
}, () => CurrentPicture != null && CurrentPicture.IsLoaded)).Value;
173175

176+
public RelayCommand ExecuteSaveImageCommand => new Lazy<RelayCommand>(() => new RelayCommand(() =>
177+
{
178+
179+
180+
}, () => CurrentPicture != null && CurrentPicture.IsLoaded)).Value;
181+
182+
public RelayCommand ExecuteSaveAsImageCommand => new Lazy<RelayCommand>(() => new RelayCommand(async () =>
183+
{
184+
if (Famil.Win32.CommonDialog.SaveFileDialog(Folder.Current.FullName, "", "另存为...", "", CurrentPicture.Extension, default, out string filename))
185+
{
186+
var isSuccess = await CurrentPicture.SaveAsync(filename);
187+
188+
if (isSuccess)
189+
{
190+
SendNotificationMessage("保存成功!");
191+
}
192+
else
193+
{
194+
SendNotificationMessage("保存失败!");
195+
}
196+
}
197+
198+
}, () => CurrentPicture != null && CurrentPicture.IsLoaded)).Value;
199+
174200
public RelayCommand ExecuteCopyCurrentPicturePathCommand => new Lazy<RelayCommand>(() => new RelayCommand(() =>
175201
{
176202
System.Windows.Clipboard.SetText(CurrentPicture.PicturePath);
177203

178204
})).Value;
179205

206+
public RelayCommand ExecuteOpenTheFolderCommand => new Lazy<RelayCommand>(() => new RelayCommand(() =>
207+
{
208+
var info = new System.Diagnostics.ProcessStartInfo("Explorer.exe")
209+
{
210+
Arguments = $"/select,{CurrentPicture.PicturePath}"
211+
};
212+
System.Diagnostics.Process.Start(info);
213+
214+
}, () => CurrentPicture != null)).Value;
215+
180216
#endregion
181217

182218

0 commit comments

Comments
 (0)