@@ -8,26 +8,68 @@ public partial class WindowsLockScreenImagesForm : Form
88 private FileInfo [ ] assets = Array . Empty < FileInfo > ( ) ;
99
1010 private string assetsUserDirectory = string . Empty ;
11+ private string assetsLockScreenDirectory = string . Empty ;
1112
1213 private FileInfo [ ] getAssets ( )
1314 {
1415 var userDirectory = Environment . GetFolderPath ( Environment . SpecialFolder . UserProfile ) ;
15- //const string directory = @"C:\Users\USERNAME\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets";
16- var directory = Path . Combine ( userDirectory , @"AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets" ) ;
17- this . assetsUserDirectory = directory ;
18- if ( ! Directory . Exists ( directory ) )
16+ var wallpaper_directory = Path . Combine ( userDirectory , @"AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets" ) ;
17+ var lockscreen_directory = Path . Combine ( userDirectory , @"AppData\Roaming\Microsoft\Windows\Themes" ) ;
18+ this . assetsUserDirectory = wallpaper_directory ;
19+ this . assetsLockScreenDirectory = lockscreen_directory ;
20+ List < FileInfo > files = new List < FileInfo > ( ) ;
21+ if ( Directory . Exists ( wallpaper_directory ) )
1922 {
20- MessageBox . Show ( $ "Directory '{ directory } ' does not exist!", "Something went wrong" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
21- return this . assets ;
23+ foreach ( var file in new DirectoryInfo ( wallpaper_directory ) . GetFiles ( ) )
24+ {
25+ if ( file . Length >= 50 * 1024 )
26+ files . Add ( file ) ;
27+ }
28+ }
29+ else
30+ {
31+ MessageBox . Show ( $ "Directory '{ wallpaper_directory } ' does not exist!", "Warning" , MessageBoxButtons . OK , MessageBoxIcon . Warning ) ;
32+ }
33+
34+ if ( Directory . Exists ( lockscreen_directory ) )
35+ {
36+ foreach ( var file in new DirectoryInfo ( lockscreen_directory ) . GetFiles ( ) )
37+ {
38+ if ( file . Extension != ".ini" )
39+ files . Add ( file ) ;
40+ }
41+ }
42+ else
43+ {
44+ MessageBox . Show ( $ "Directory '{ lockscreen_directory } ' does not exist!", "Warning" , MessageBoxButtons . OK , MessageBoxIcon . Warning ) ;
45+ }
46+ return files . ToArray ( ) ;
47+ }
48+ private Bitmap createThumbnail ( Image original , Size maxSize )
49+ {
50+ double ratioX = ( double ) maxSize . Width / original . Width ;
51+ double ratioY = ( double ) maxSize . Height / original . Height ;
52+ double ratio = Math . Min ( ratioX , ratioY ) ;
53+
54+ int newWidth = ( int ) ( original . Width * ratio ) ;
55+ int newHeight = ( int ) ( original . Height * ratio ) ;
56+
57+ var thumb = new Bitmap ( newWidth , newHeight ) ;
58+ using ( var graphics = Graphics . FromImage ( thumb ) )
59+ {
60+ graphics . CompositingQuality = System . Drawing . Drawing2D . CompositingQuality . HighQuality ;
61+ graphics . InterpolationMode = System . Drawing . Drawing2D . InterpolationMode . HighQualityBicubic ;
62+ graphics . SmoothingMode = System . Drawing . Drawing2D . SmoothingMode . HighQuality ;
63+ graphics . DrawImage ( original , 0 , 0 , newWidth , newHeight ) ;
2264 }
23- return new DirectoryInfo ( directory ) . GetFiles ( ) ;
65+ return thumb ;
2466 }
2567
2668 public WindowsLockScreenImagesForm ( )
2769 {
2870 InitializeComponent ( ) ;
2971
30- this . Icon = new Icon ( AppDomain . CurrentDomain . BaseDirectory + @"\WindowsLockScreenImagesIcon.ico" ) ;
72+ this . Icon = new Icon ( AppDomain . CurrentDomain . BaseDirectory + @"\WindowsLockScreenImagesIcon.ico" ) ;
3173
3274 this . assets = getAssets ( ) ;
3375
@@ -39,59 +81,38 @@ public WindowsLockScreenImagesForm()
3981 }
4082 // status bar
4183 var statusStrip = new StatusStrip ( ) ;
84+ statusStrip . ShowItemToolTips = true ;
4285 // label to show file information (name, size)
4386 var statusStripLabel = new ToolStripStatusLabel ( "Click an image from the list to view" ) ;
4487 statusStrip . Items . Add ( statusStripLabel ) ;
4588 // buttons to save the selected file and to open the directory with explorer
4689 statusStrip . Items . Add ( new ToolStripStatusLabel ( "" ) { Spring = true , TextAlign = ContentAlignment . MiddleRight } ) ;
47- var statusStripSaveButton = new ToolStripSplitButton ( "Click to save selected image" )
90+ var statusStripSaveButton = new ToolStripSplitButton ( "Click to save selected image" )
4891 {
4992 DropDownButtonWidth = 0
5093 } ;
51- statusStripSaveButton . Click += ( s , e ) =>
52- {
53- var selectedIndex = listBox . SelectedIndex ;
54- if ( selectedIndex >= 0 )
55- {
56- var metaItem = listBox . Items [ selectedIndex ] as ListBoxMetaItem ;
57- if ( metaItem is not null )
58- {
59- var fullFileName = metaItem . Info ? . FullName ;
60-
61- var saveFileDialog = new SaveFileDialog
62- {
63- FileName = $ "{ metaItem . Info ? . Name } .jpg",
64- Filter = "JPEG (*.jpg)|*.jpeg,*.jpg" ,
65- InitialDirectory = Environment . GetFolderPath ( Environment . SpecialFolder . Desktop )
66- } ;
67- if ( saveFileDialog . ShowDialog ( ) == DialogResult . OK )
68- {
69- if ( File . Exists ( fullFileName ) )
70- {
71- Image . FromFile ( fullFileName ) . Save ( saveFileDialog . FileName , ImageFormat . Jpeg ) ;
72- }
73- }
74- }
75- }
76- else
77- {
78- MessageBox . Show ( "Click on an image on the list to select it and save it." , "Information" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
79- }
80- } ;
8194 statusStrip . Items . Add ( statusStripSaveButton ) ;
8295 statusStrip . Items . Add ( new ToolStripSeparator ( ) ) ;
8396 var statusStripOpenButton = new ToolStripSplitButton ( "Click to open images folder" )
8497 {
8598 DropDownButtonWidth = 0
8699 } ;
100+ // open explorer on the two directories
87101 statusStripOpenButton . Click += ( s , e ) =>
88102 {
89- ProcessStartInfo startInfo = new ProcessStartInfo
103+ ProcessStartInfo startInfo1 = new ProcessStartInfo
90104 {
91105 Arguments = this . assetsUserDirectory ,
92106 FileName = "explorer.exe"
93107 } ;
94- Process . Start ( startInfo ) ;
108+
109+ ProcessStartInfo startInfo2 = new ProcessStartInfo
110+ {
111+ Arguments = this . assetsLockScreenDirectory ,
112+ FileName = "explorer.exe"
113+ } ;
114+ Process . Start ( startInfo1 ) ;
115+ Process . Start ( startInfo2 ) ;
95116 } ;
96117 statusStrip . Items . Add ( statusStripOpenButton ) ;
97118 // split panel
@@ -104,17 +125,110 @@ public WindowsLockScreenImagesForm()
104125 var pictureBox = new PictureBox
105126 {
106127 Dock = DockStyle . Fill ,
107- SizeMode = PictureBoxSizeMode . Zoom
128+ SizeMode = PictureBoxSizeMode . Zoom ,
108129 } ;
109- // left = list of files
110- listBox = new ListBox
130+ var pictureContainer = new Panel
111131 {
112- Dock = DockStyle . Fill
132+ Dock = DockStyle . Fill ,
133+ Padding = new Padding ( 5 ) ,
113134 } ;
135+ pictureContainer . Controls . Add ( pictureBox ) ;
136+ // create thumbnail viewer
137+ var thumbnailPanel = new FlowLayoutPanel
138+ {
139+ Dock = DockStyle . Fill ,
140+ AutoScroll = true ,
141+ WrapContents = true ,
142+ FlowDirection = FlowDirection . LeftToRight
143+ } ;
144+
145+ // map thumbnail PictureBox to FileInfo
146+ Dictionary < PictureBox , FileInfo > pictureMap = new ( ) ;
147+
148+ PictureBox ? selectedThumbnail = null ;
149+
114150 foreach ( var fileInfo in this . assets )
115151 {
116- listBox . Items . Add ( new ListBoxMetaItem ( fileInfo ) ) ;
152+ try
153+ {
154+ using var tempImage = Image . FromFile ( fileInfo . FullName ) ;
155+ var thumbnail = createThumbnail ( tempImage , new Size ( 100 , 60 ) ) ;
156+
157+ var picBox = new PictureBox
158+ {
159+ Image = thumbnail ,
160+ Width = 100 ,
161+ Height = 60 ,
162+ SizeMode = PictureBoxSizeMode . Zoom ,
163+ Cursor = Cursors . Hand ,
164+ Margin = new Padding ( 5 )
165+ } ;
166+
167+ picBox . Click += ( s , e ) =>
168+ {
169+ if ( File . Exists ( fileInfo . FullName ) )
170+ {
171+ pictureBox . Image = Image . FromFile ( fileInfo . FullName ) ;
172+
173+ var filenameLength = fileInfo . Name . Length ;
174+ statusStripLabel . Text = $ "{ fileInfo . Name . Substring ( 0 , 4 ) } ...{ fileInfo . Name . Substring ( filenameLength - 4 , 4 ) } ({ new ListBoxMetaItem ( fileInfo ) . HumanReadableSize ( ) } )";
175+ statusStripLabel . ToolTipText = fileInfo . FullName ;
176+
177+ selectedThumbnail = ( PictureBox ) s ! ;
178+ }
179+ } ;
180+
181+ pictureMap [ picBox ] = fileInfo ;
182+ thumbnailPanel . Controls . Add ( picBox ) ;
183+ }
184+ catch
185+ {
186+ // discard invalid image files
187+ }
117188 }
189+
190+ statusStripSaveButton . Click += ( s , e ) =>
191+ {
192+ FileInfo ? selectedFile = null ;
193+
194+ if ( listBox . Visible && listBox . SelectedIndex >= 0 )
195+ {
196+ var metaItem = listBox . Items [ listBox . SelectedIndex ] as ListBoxMetaItem ;
197+ selectedFile = metaItem ? . Info ;
198+ }
199+ else if ( thumbnailPanel . Visible && selectedThumbnail != null && pictureMap . TryGetValue ( selectedThumbnail , out var fileFromThumbnail ) )
200+ {
201+ selectedFile = fileFromThumbnail ;
202+ }
203+
204+ if ( selectedFile != null && File . Exists ( selectedFile . FullName ) )
205+ {
206+ var saveFileDialog = new SaveFileDialog
207+ {
208+ FileName = $ "{ selectedFile . Name } .jpg",
209+ Filter = "JPEG (*.jpg)|*.jpeg;*.jpg" ,
210+ InitialDirectory = Environment . GetFolderPath ( Environment . SpecialFolder . Desktop )
211+ } ;
212+
213+ if ( saveFileDialog . ShowDialog ( ) == DialogResult . OK )
214+ {
215+ using var img = Image . FromFile ( selectedFile . FullName ) ;
216+ img . Save ( saveFileDialog . FileName , ImageFormat . Jpeg ) ;
217+ }
218+ }
219+ else
220+ {
221+ MessageBox . Show ( "Click on an image to select it and save it." , "Information" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
222+ }
223+ } ;
224+
225+ listBox . Dock = DockStyle . Fill ;
226+
227+ foreach ( var file in this . assets )
228+ {
229+ listBox . Items . Add ( new ListBoxMetaItem ( file ) ) ;
230+ }
231+
118232 listBox . Click += ( s , e ) =>
119233 {
120234 var selectedIndex = listBox . SelectedIndex ;
@@ -134,9 +248,30 @@ public WindowsLockScreenImagesForm()
134248 }
135249 }
136250 } ;
251+
252+ thumbnailPanel . Visible = false ;
253+ listBox . Visible = true ;
254+
255+ var toggleViewButton = new ToolStripSplitButton ( "Click to show thumbnails" )
256+ {
257+ DropDownButtonWidth = 0
258+ } ;
259+ // button to toggle between file list and thumbnails
260+ toggleViewButton . Click += ( s , e ) =>
261+ {
262+ bool showingThumbnails = thumbnailPanel . Visible ;
263+
264+ thumbnailPanel . Visible = ! showingThumbnails ;
265+ listBox . Visible = showingThumbnails ;
266+
267+ toggleViewButton . Text = showingThumbnails ? "Click to show file list" : "Click to show thumbnails" ;
268+ } ;
269+ statusStrip . Items . Add ( new ToolStripSeparator ( ) ) ;
270+ statusStrip . Items . Add ( toggleViewButton ) ;
137271 //
272+ splitContainer . Panel1 . Controls . Add ( thumbnailPanel ) ;
138273 splitContainer . Panel1 . Controls . Add ( listBox ) ;
139- splitContainer . Panel2 . Controls . Add ( pictureBox ) ;
274+ splitContainer . Panel2 . Controls . Add ( pictureContainer ) ;
140275 //
141276 this . Controls . Add ( splitContainer ) ;
142277 this . Controls . Add ( statusStrip ) ;
0 commit comments