Wallpaper Collection is a combination of several smaller / beginner-level C# topics combined into a useful Windows utility application. After researching the legality of saving Windows Spotlight images (for your own use), seeing the response on several different pages on Microsoft's own website, and enjoying the beauty of the images myself, like the photographers, I decided to share my work with anyone interested in an attempt make your desktop and hence the world, a slightly more enjoyable place.
Introduction
Windows 10 introduced many of us to Windows Spotlight artwork. Windows Spotlight contains an evolving collection of beautiful images captured from around the world, shared by Microsoft, pushed to your lock / login screen along with some background information on where and sometimes how the image was captured. Windows Spotlight allows you to like or dislike the images presented to you so that it may give you more of the image type you prefer. There is a good chance that your choices are used for pruning its image recognition and categorization AI back-end.
Many people, including myself, have expressed interest in collecting some of these amazing images for use as Windows wallpaper. The following article will discuss how I pulled together various C# classes used to create this utility and how to easily collect the Windows Spotlight images for your own use using the utility.
Microsoft acknowledged how anyone could explore the data provided through Windows Spotlight.
This page led me down the proverbial rabbit hole of development which started life as a simple .BAT (batch) file and culminated in this application.
Background
Several topics such as custom controls, password encryption, and accessing a password protected UNC path, will be covered to address challenges that I encountered while developing this application.
While I believe that the topics covered here are not ground-breaking in anyway, they may be useful to someone just learning C#. My hope is that perhaps this article might encourage other beginning authors to forge new tools by combining pieces of this utility and other Code Project articles.
Using the Program
When you run the program, the first thing it does is collect your Windows user name from your profile. This is used to build a path to where Windows Spotlight stores the "slightly hidden" images that you see on your lock screen assuming you have Windows Spotlight set as the background for your lock screen... and why wouldn't you!
This is visible in the textbox under the "Source Folder:" label. You should not have to modify the value here.
Folder selection and browse buttons are available for all folders so that you may select and visually explore them.
These are more widely used for the destination folders, both local and UNC folder below.
Next, you should consider which image orientations you are most interested in. For example, at first I only wanted to save landscape images for use as desktop wallpaper; that is to say, images that are larger horizontally than vertically (like most computer monitors). There are checkboxes which allow you to choose your preferences.
When you click the "Browse" button (in the very near future), the mode selection checkboxes will determine which images are automatically selected for saving / copying.
There are currently two rules for browsing and displaying the images that you wish to select and collect; one rule for file size and one for file age or date modified. These items will only browse images that are greater than the specified size (in Kilobytes) and those which have been modified more recently than the specified date. The date defaults to one month prior to when the application is run.
Next, click the button labelled Browse right next to the Browse rules. The application will collect images based on your browse rules and display them in the main window panel and will "select" any images which meet your selection criteria checkboxes that were checked above.
You may select images that will be "processed" (later) by clicking on the image representation itself or on the checkbox control next to each image.
NOTE: You may choose to use the Rename
functionality if you are only saving images from one machine. This way, instead of keeping the original image filename of some huge hexadecimal string a la 36a2432655c43fced237e... etc. your images could be named Wallpaper00001.jpg, etc. This poses a problem when you are collecting images from multiple machines and storing them in the same "master" folder, a UNC folder for example.
There are a set of manual image select buttons on the lower right edge of the application to assist with image selection if you choose to use them. The button labels should be self-explanatory.
Once you have selected images you wish to save, you need to specify where to save them. The following controls allow you to choose where the images will be saved when the "Copy To Local" and "Sync To UNC Path" buttons are clicked later.
The Destination Folder is just a regular folder that you choose to store the images. Windows Spotlight images are really just JPEG files that need little modification to use.
My Netgear router has the ability to share files and folders with any machine attached to my home network. I found it useful to place my "master" wallpaper image collection on a password protected network share so that all machines in my house can use the images. The UNC User Name, Password, Domain and User Path are used to connect to my password-protected network share. You can use any password-protected UNC path on any device attached to the same network where you have write permissions.
Using the UNC path is optional. If you do not wish to use the functionality, simply leave every field empty.
If you use Dropbox or other cloud storage, you could take this one step further and specify either folder to be your cloud share thus propagating your images to the cloud. My router can already do this and is much less expensive than Dropbox on a month by month basis.
Once your images have been selected and your destination folders have been specified, all you have to do is click the button labelled "Copy To Local". This will copy and rename all selected image files to your selected destination directory.
If you are using the UNC path options, you may click the button labelled "Sync To UNC Path". This means synchronize, or copy back, all of the files from the UNC path back to the local destination folder which do not already exist in the destination folder.
I have many (too many) machines on my local network. I run this program on all of them. They all feed my UNC path folder. What you may not realize is that each machine is given different images from Microsoft's Windows Spotlight gallery. In other words, I can collect images A, B, and C from my laptop and images D, E, and F from my workstation. I copy all of them to my UNC path on my router share. Then, when I click the Sync To UNC Path button, I will have images A, B, C, D, E, and F back in my local folder on the node where I clicked this button.
You may use either the destination folder or UNC path browse buttons (the yellow folder icon button) to examine your current collection.
Clicking the yellow folder browse button on my destination folder reveals all of the images collected and locally available on my machine.
This is handy for verification of functionality but also so that you can easily choose an image by right-clicking on it and selecting "Set as desktop background".
Duplicate Image Detection
After my image collection began to grow with v1.0 of this utility, I started to notice images which were the same but, for whatever reason, provided by Microsoft with different filenames. As a result, I soon realized the need to have a duplicate image detection algorithm with this utility. The follow screen clips were taken directly from the main image browsing interface on one particular day. Notice the identical file size, identical image, yet different filename.
In v1.0, I had the logic to calculate hash-based checksums for each image, because I anticipated a possible issue with duplicates at some point, but did nothing with this checksum data. In v1.1.0.2, I was able to finally put this to use as one piece of comparison data to detect and remove duplicate images thus saving precious hard drive space.
When you click the "Scan For Duplicates" button, the program will first scan the specified local storage folder for duplicate images by comparing checksum values and filesize. The program will ask you whether you want to delete or keep the duplicate image for every duplicate detected.
When processing of the local directory has finished, the program will ask you if you would like perform the same scan on your UNC storage path. The program will warn you that this may take a long time simply because a network-based storage device is likely slower to respond compared to a locally attached hard drive.
Scanning the remote UNC path is recommended every few months or so because, if you are like me, and use this program to collect images from multiple machines to feed a single UNC storage path, you will certainly encounter duplicate images at some point. It is simply a matter of time.
End-User Summary
Prior to writing this utility, I used simple Powershell scripts to handle the file copying, renaming, deleting, and general management of the image collection. I figured that an application would help reduce the manual steps, especially when run on multiple machines nearly every day. In addition, I believe a fairly simple Windows / .NET WinForms application may help other people who do not know what a batch file or Powershell script is.
I hope you find the application useful! Now, on to the coding and what is required behind the curtain so to speak!
The Code and the C# Classes
There are thousands of lines of code in this application. Rather than list everything or even useful snippets here, I will simply refer you to the attached Visual Studio solution and projects. The solution was created with Visual Studio 2019 but should be usable in 2017 as well. For a learning exercise, it is recommended to read this section of the article while having the solution open in Visual Studio.
The Sub-Project
The very first thing I needed was a custom control to display a larger thumbnail of the source image than existing .NET controls allow. While an ImageList
or ImageView
are handy, they didn't quite give me what I wanted. As well as displaying a large thumbnail image, I also needed to keep the original image intact, and store / display a file checksum calculated in order to help determine image uniqueness (to avoid image duplicates) essentially when renaming images has occurred. I also wanted the ability to support and provide feedback for transparent or semi-transparent images for future use (overlaying other images programmatically, etc.)
Thus, the ImageListViewer
sub-project of the main project was born. (See the source code.) This project contains three simple classes.
The ImageListViewerControl
is essentially a "compound" (as opposed to completely custom / from scratch) control consisting of a WinForms PictureBox
, Textbox
, and Checkbox
.
This control has a few simple properties and local functions to regulate its appearance. In order to clearly represent the source image, a "transparent background grid" similar to what is used in GIMP or other imaging programs is drawn as a background to this control. This, along with a simple scaling algorithm which centers and scales the source image into a large thumbnail such that you can clearly see the image orientation is the main purpose for creating this control. Note that the logic to combine bitmap images inside this control supports alpha channels. You can test this by reducing the Browse Rules file size to 0 and re-browsing the source images. The source directory typically (but not always) contains many transparent icon-type images which are very small in size compared to the pretty Windows Spotlight pictures. This is the reason the Browse Rules controls exist! :-P
Source image filename, checksum, and file size are currently displayed as metadata. More metadata will follow in future versions.
Click events in this control are used to set the control's Selected property and also to raise the event in the control parent, the ImageListViewerControlCollection
.
The ImageListViewerControlCollection
is a WinForms Panel with certain scroll bar properties and appearance attributes pre-configured.
This control uses a simple set of properties and a grid / object positioning algorithm to draw one or more ImageListViewerControl
child controls.
This control also raises (sometimes called bubbling since bubbles rise) the click events from its child controls up to the collection control's parent, the main application in this case.
The ImageListViewerControlEventArgs
class is used by both of the above controls to notify the parent application, WallpaperCollection.exe, of mouse events occurring inside the custom controls.
This hierarchy is necessary to allow the controls to respond to events themselves internally but to also notify the parent application of what is happening along with pertinent data relevant to the event.
The Main Project
The main project application, the WallpaperCollection
project, makes heavy use of the sub-project controls but also contains some interesting classes used to provide various functionality that this application requires.
The first class worth mentioning that you might find useful in your own code is the FileChecksum
class.
This class uses the .NET Cryptography
classes and makes it painless to both generate a checksum / hash value from a given file and to also verify that an existing file has not been modified based on a previously generated checksum value. Using this class is as simple as this:
FileChecksum fc = new FileChecksum(tempFile.FullName);
fc.CalculateChecksum(this);
string myChecksum = fc.Checksum;
Wallpaper Collection uses this class to record image checksums and stores this inside a local datafile of images already processed so that duplicates may be avoided in the future. Currently, the calculated checksum is displayed in the associated image's ImageListViewerControl
. Not much more is done with it at the moment but the groundwork for future functionality is there.
The VerifyChecksum
method of this class uses the properties PrecalculatedHash
and ChecksumFilename
to verify that an existing file was not modified from the time the pre-calculated (hash) checksum was created. This can alert you to files that were modified against your will after public release, alert you to upload corruptions, etc.
You can also use this class with feedback callback functions, for example, a graphic progress bar % update. However, this requires subtle changes to the existing code as the use case for this application was different from when I originally wrote the class. Callbacks are useful for processing L A R G E files so that the user gets visual feedback (usually on another thread) while the file is evaluated and the checksum is being created or verified. I can provide examples if anyone is interested.
The next class you might find useful in your own code is the SecureStorageEngine
class.
This class is somewhat unique in that I converted this class from old Borland C++ Builder source code (from many years ago) which, at the time, I converted from hand-coded assembly language. You can clearly see the assembler roots in the C# version.
The code is old but useful. It uses a custom 256 bit ciphering system to provide two-way encryption. This is used to securely store the password for the UNC folder access inside the application settings file per Windows user. There should be no more excuses for storing passwords in ANY plain text file!
It is worthy to mention that this class has several constructors, each of which create a different "master" key; the basis for all of the encryption and decryption logic. You can use the default constructor's default master key (see member variable _key
in the source code for this class). You can also specify your own key (via parameter), up to 32 characters. You can rely on the class for automatic creation of a machine-unique key (which takes a second or two to generate) based on the computer's node name, MAC address of the primary NIC, etc.
It is also worthy to point out that if you create your own key via string parameter, you must remember this key and use it with all future decryption attempts. If you lose the key, the encrypted data will remain unreadable. Likewise, it is worth pointing out that using the constructor which creates a machine-unique key is more secure but also is not transportable between machines. The class is purposefully designed to not expose (via properties) the machine-unique key that was created.
This is certainly not "unbreakable" encryption with modern GPU-driven brute force attack software. If you are using a full 256-bit key along with passwords of sufficient length (as you should), then this should deter most brute force decoding attempts simply due to the time required for such an attack. As with all security related issues, longer passwords are a good thing.
Using this class can be as simple as the following:
SecureStorageEngine sseEncrypt = new SecureStorageEngine("f0f70002sometextabcd9876bxaxffsi");
sseEncrypt.EncryptionInput = "YourPlaintextPasswordGoesHere"
sseEncrypt.Encrypt();
string myEncryptedPassword = sseEncrypt.EncryptionOutput;
If you do not use the same master key, "f0f70002sometext...." shown above to decode the encrypted value, you will not be able to retrieve the original password, that is without resorting to hacking or brute force decryption methods.
Only alphanumerics should be used for master key string parameter at the moment.
Another class you might find useful in your own code is the UNCSecureAccess
class. This class is based on an article I found on Code Project entitled Connect to a UNC Path with Credentials by a Code Project user named hayes.adrian (presumably Adrian Hayes ?!?)
I have this wonderful person to thank for providing a well researched and perfectly working example. This helped me connect this image application to the secured share on my router.
This class uses the functions from the NetAPI32 for programmatically accessing network UNC resources. I have only slightly modified the original code available in that article for easier use with this application (interactive user app versus Windows service from the original article). To you hayes.adrian, I say thank you! This has triggered many new project ideas in my head.
There are two very simple classes, WallpaperItem
and WallpaperItems
, which allow easy manipulation of a source image and collection of source images. The first class also stores some of the image metadata (such as source image original file name, renamed file name if renamed, file checksum, etc.) that I wish to track and save to disk.
The rest of the code in the main project simply wires the other classes together into a simple but useful WinForms application.
I am often forced to stare at four mundane walls during office hours and beyond. Any respite from the daily routine, however small, in this case Windows Desktop Wallpaper from places around the world, is a welcome addition to my surroundings. I am all for furthering the embrace of any artistic endeavour. Art is one of the first areas to suffer in times of economic difficulty within our educational system, and life in general. To me, that is both a sad and unnecessary departure from previous generations, to use a rather extreme example of comparison, the Renaissance.
Points of Interest
There are many items of interest for a beginning C# coder included in the solution source code. For example:
How to Display the Version Information Embedded in an Assembly in the WinForms Title
using System.Reflection;
.
.
.
Assembly asm = Assembly.GetExecutingAssembly();
this.Text = "Wallpaper Collection v" + asm.GetName().Version.ToString();
How to Get the Windows Logged In User's Profile Folder where .NET App Settings are Stored
string myUserProfileFolder =
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\AppData\Local\";
There are other helpful items sprinkled throughout the source code. Yes, these items can be easily Google'd but the fun is in the exploration!
I encourage you to step through the code with the Visual Studio debugger with your choice of break points enabled to see what happens when the program starts and with each button click. I hope you find some of the information contained in the article useful in your own C# projects. At the very least, I hope you enjoy the application and build a beautiful wallpaper collection for your personal use.
This application only took me about 4 part-time days to write with the acknowledgment that my secure storage / encryption class and the file checksum class already existed in slightly different variations from previous projects. For the amount of time that I've invested in this project, I believe the outcome is well worth it and could benefit many people.
To Do List
Now that the image duplication logic has been added, I can focus on the remaining goals.
In a future revision, I would like to add the ability to load / execute small command scripts so that the entire process could be automated. In other words, once a "command" file was built, you could just run this program (in the background) and it would automatically collect and copy images based on your configuration.
When time permits, I intend to figure out how and where the metadata for each Windows Spotlight image is stored locally, for example, the location information of the photograph, so that I can record and perhaps encode that information directly into the destination folder bitmap (.JPG) files as custom chunks and / or display it.
History
- v1.0.0.0 - Initial release - not perfect but certainly usable!
- v1.1.0.2 - Added duplicate image cleanup UI and logic