/// <summary> /// Load a SpotlightImage object from a Metatada file /// </summary> /// <param name="metadataFile">File to load information from</param> /// <returns>SpotlightImage object</returns> public static SpotlightImage LoadMeta(string metadataFile) { string[] lines = File.ReadAllLines(metadataFile); if (lines.Length > 0 && lines[0] == MetaHeader) { SpotlightImage image = new SpotlightImage(); foreach (string line in lines) { int equalIndex = line.IndexOf('='); if (equalIndex > 0) { string value = ""; string key = line.Substring(0, equalIndex); if (line.Length > (equalIndex + 1)) { value = line.Substring(equalIndex + 1); } switch (key) { case "uri": image.Uri = value; break; case "sha256": image.Sha256 = value; break; case "filesize": int fileSize; if (int.TryParse(value, out fileSize)) { image.FileSize = fileSize; } break; case "title": image.Title = value; break; case "copyright": image.Copyright = value; break; } } } return(image); } else { throw new InvalidDataException("Not a SpotlightImage metadata file: " + metadataFile); } }
static void Main(string[] args) { if (args.Length > 0) { string action = null; bool singleImage = false; bool maximumRes = false; bool? portrait = false; string locale = null; bool allLocales = false; string outputDir = "."; string outputName = "spotlight"; bool integrityCheck = true; bool downloadMany = false; int downloadAmount = int.MaxValue; int cacheSize = int.MaxValue; bool metadata = false; bool metadataAllowInconsistent = false; bool embedMetadata = false; string fromFile = null; int apiTryCount = 3; bool verbose = false; switch (args[0].ToLower()) { case "urls": case "download": case "wallpaper": case "lockscreen": action = args[0].ToLower(); break; default: Console.Error.WriteLine("Unknown action: " + args[0]); Environment.Exit(1); break; } if (args.Length > 1) { for (int i = 1; i < args.Length; i++) { switch (args[i].ToLower()) { case "--single": singleImage = true; break; case "--many": downloadMany = true; break; case "--amount": i++; downloadMany = true; if (i >= args.Length) { Console.Error.WriteLine("--amount expects an additional argument."); Environment.Exit(1); } if (!int.TryParse(args[i], out downloadAmount) || downloadAmount < 0) { Console.Error.WriteLine("Download amount must be a valid and positive number."); Environment.Exit(1); } if (downloadAmount == 0) { downloadAmount = int.MaxValue; } break; case "--cache-size": i++; if (i >= args.Length) { Console.Error.WriteLine("--cache-size expects an additional argument."); Environment.Exit(1); } if (!int.TryParse(args[i], out cacheSize) || cacheSize <= 0) { Console.Error.WriteLine("Cache size must be a valid and strictly positive number."); Environment.Exit(1); } break; case "--maxres": maximumRes = true; break; case "--portrait": portrait = true; break; case "--landscape": portrait = false; break; case "--locale": i++; if (i < args.Length) { locale = args[i]; } else { Console.Error.WriteLine("--locale expects an additional argument."); Environment.Exit(1); } if (!System.Text.RegularExpressions.Regex.Match(locale, "^[a-z]{2}-[A-Z]{2}$").Success) { Console.Error.WriteLine("--locale expected format is xx-XX, e.g. en-US."); Environment.Exit(1); } break; case "--all-locales": allLocales = true; downloadMany = true; break; case "--outdir": i++; if (i < args.Length) { outputDir = args[i]; } else { Console.Error.WriteLine("--outdir expects an additional argument."); Environment.Exit(1); } if (!Directory.Exists(outputDir)) { Console.Error.WriteLine("Output directory '" + outputDir + "' does not exist."); Environment.Exit(1); } break; case "--outname": i++; if (i < args.Length) { outputName = args[i]; } else { Console.Error.WriteLine("--outname expects an additional argument."); Environment.Exit(1); } foreach (char invalidChar in Path.GetInvalidFileNameChars()) { if (outputName.Contains(invalidChar)) { Console.Error.WriteLine("Invalid character '" + invalidChar + "' in specified output file name."); Environment.Exit(1); } } break; case "--skip-integrity": integrityCheck = false; break; case "--api-tries": i++; if (i >= args.Length) { Console.Error.WriteLine("--api-tries expects an additional argument."); Environment.Exit(1); } if (!int.TryParse(args[i], out apiTryCount) || apiTryCount <= 0) { Console.Error.WriteLine("API tries must be a valid and strictly positive number."); Environment.Exit(1); } break; case "--metadata": metadata = true; break; case "--inconsistent-metadata": metadata = true; metadataAllowInconsistent = true; break; case "--embed-meta": embedMetadata = true; break; case "--from-file": i++; if (i < args.Length) { fromFile = args[i]; } else { Console.Error.WriteLine("--from-file expects an additional argument."); Environment.Exit(1); } if (!File.Exists(fromFile)) { Console.Error.WriteLine("Input file '" + fromFile + "' does not exist."); Environment.Exit(1); } break; case "--from-dir": i++; if (i < args.Length) { fromFile = args[i]; } else { Console.Error.WriteLine("--from-dir expects an additional argument."); Environment.Exit(1); } if (Directory.Exists(fromFile)) { string[] jpegFiles = Directory.EnumerateFiles(fromFile, "*.jpg", SearchOption.AllDirectories).ToArray(); if (jpegFiles.Any()) { fromFile = jpegFiles[new Random().Next(0, jpegFiles.Length)]; } else { Console.Error.WriteLine("Input directory '" + fromFile + "' does not contain JPG files."); Environment.Exit(1); } } else { Console.Error.WriteLine("Input directory '" + fromFile + "' does not exist."); Environment.Exit(1); } break; case "--restore": if (action == "lockscreen") { if (FileSystemAdmin.IsAdmin()) { try { Lockscreen.RestoreDefaultGlobalLockscreen(); Environment.Exit(0); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(4); } } else { Console.Error.WriteLine("This program must run as administrator to restore the global lockscreen."); Environment.Exit(4); } } break; case "--verbose": verbose = true; break; default: Console.Error.WriteLine("Unknown argument: " + args[i]); Environment.Exit(1); break; } } if (downloadMany && cacheSize < downloadAmount) { Console.Error.WriteLine( "Download amount ({0}) is greater than cache size ({1}). Reducing download amount to {1}.", downloadAmount == int.MaxValue ? "MAX" : downloadAmount.ToString(), cacheSize ); downloadAmount = cacheSize; } if (downloadMany && metadata && allLocales && !metadataAllowInconsistent) { Console.Error.WriteLine("--metadata combined with --all-locales will produce random metadata languages."); Console.Error.WriteLine("Please relaunch with --inconsistent-metadata if you really intend to do this."); Environment.Exit(1); } } try { Queue <string> remainingLocales = new Queue <string>(); if (allLocales) { remainingLocales = new Queue <string>(Locales.AllKnownSpotlightLocales); Console.Error.WriteLine(String.Format("Starting download using {0} locales", remainingLocales.Count)); locale = remainingLocales.Dequeue(); Console.Error.WriteLine(String.Format("Switching to {0} - {1} locales remaining", locale, remainingLocales.Count + 1)); } int downloadCount = 0; int noNewImgCount = 0; do { SpotlightImage[] images = (fromFile != null && (action == "wallpaper" || action == "lockscreen")) ? new[] { new SpotlightImage() } // Skip API request, we'll use a local file : Spotlight.GetImageUrls(maximumRes, portrait, locale, apiTryCount); if (images.Length < 1) { Console.Error.WriteLine(Program.Name + " received an empty image set from Spotlight API."); Environment.Exit(2); } SpotlightImage randomImage = images.OrderBy(p => new Guid()).First(); if (action == "urls") { if (singleImage) { Console.WriteLine(randomImage.Uri); } else { foreach (SpotlightImage image in images) { Console.WriteLine(image.Uri); } } Environment.Exit(0); } try { if (singleImage || action == "wallpaper" || action == "lockscreen") { string imageFile = fromFile ?? randomImage.DownloadToFile(outputDir, integrityCheck, metadata, outputName, apiTryCount); if (embedMetadata) { imageFile = SpotlightImage.EmbedMetadata(imageFile, outputDir, outputName); } Console.WriteLine(imageFile); if (action == "wallpaper") { try { Desktop.SetWallpaper(imageFile); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(4); } } else if (action == "lockscreen") { if (FileSystemAdmin.IsAdmin()) { try { Lockscreen.SetGlobalLockscreen(imageFile); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(4); } } else { Console.Error.WriteLine("This program must run as administrator to change the global lockscreen."); Environment.Exit(4); } } Environment.Exit(0); } downloadCount = 0; foreach (SpotlightImage image in images) { string imagePath = image.GetFilePath(outputDir); if (!File.Exists(imagePath)) { try { Console.WriteLine(image.DownloadToFile(outputDir, integrityCheck, metadata, null, apiTryCount)); downloadCount++; downloadAmount--; if (downloadAmount <= 0) { break; } } catch (InvalidDataException) { Console.Error.WriteLine("Skipping invalid image: " + image.Uri); } } } if (verbose) { Console.Error.WriteLine("Successfully downloaded: " + downloadCount + " images."); Console.Error.WriteLine("Already downloaded: " + (images.Length - downloadCount) + " images."); } if (downloadCount == 0) { noNewImgCount++; } else { noNewImgCount = 0; } } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(3); } if (allLocales && noNewImgCount >= 50 && remainingLocales.Count > 0) { noNewImgCount = 0; locale = remainingLocales.Dequeue(); Console.Error.WriteLine(String.Format("Switching to {0} - {1} locales remaining", locale, remainingLocales.Count + 1)); } } while (downloadMany && (downloadCount > 0 || noNewImgCount < 50) && downloadAmount > 0); if (cacheSize < int.MaxValue && cacheSize > 0) { foreach (FileInfo imgToDelete in Directory.GetFiles(outputDir, "*.jpg", SearchOption.TopDirectoryOnly) .Select(filePath => new FileInfo(filePath)) .OrderByDescending(fileInfo => fileInfo.CreationTime) .Skip(cacheSize)) { string metadataFile = SpotlightImage.GetMetaLocation(imgToDelete.FullName); if (File.Exists(metadataFile)) { File.Delete(metadataFile); } imgToDelete.Delete(); } } Environment.Exit(0); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(2); } } foreach (string str in new[] { " ==== " + Program.Name + " v" + Program.Version + " - By ORelio - Microzoom.fr ====", "", "Retrieve Windows Spotlight images by requesting the Microsoft Spotlight API.", Program.Name + " can also define images as wallpaper and system-wide lockscreen image.", "", "Usage:", " " + Program.Name + ".exe <action> [arguments]", " Only one action must be provided, as first argument", " Then, provide any number of arguments from the list below.", "", "Actions:", " urls Query Spotlight API and print image URLs to standard output", " download Download all images and print file path to standard output", " wallpaper Download one random image and define it as wallpaper", " lockscreen Download one random image and define it as global lockscreen", "", "Arguments:", " --single Print only one random url or download only one image as spotlight.jpg", " --many Try downloading as much images as possible by calling API many times", " --amount <n> Stop downloading after <n> images successfully downloaded, implies --many", " --cache-size <n> Only keep <n> most recent images in the output directory, delete others", " --maxres Force maximum image resolution instead of tailoring to current screen res", " --portrait Force portrait image instead of autodetecting from current screen res", " --landscape Force landscape image instead of autodetecting from current screen res", " --locale <xx-XX> Force specified locale, e.g. en-US, instead of autodetecting from system", " --all-locales Attempt to download images for all known Spotlight locales, implies --many", " --outdir <dir> Set output directory instead of defaulting to working directory", " --outname <name> Set output file name as <name>.ext for --single or --embed-meta", " --skip-integrity Skip integrity check of downloaded files: file size and sha256 hash", " --api-tries <n> Amount of unsuccessful API calls before giving up. Default is 3.", " --metadata Also save image metadata such as title & copyright as <image-name>.txt", " --embed-meta When available, embed metadata into wallpaper or lockscreen image", " --from-file Set the specified file as wallpaper/lockscreen instead of downloading", " --from-dir Set a random image from the specified directory as wallpaper/lockscreen", " --restore Restore the default lockscreen image, has no effect with other actions", " --verbose Display additional status messages while downloading images from API", "", "Exit codes:", " 0 Success", " 1 Invalid arguments", " 2 Spotlight API request failure", " 3 Image download failure or Failed to write image to disk", " 4 Failed to define image as wallpaper or lock screen image" }) { Console.Error.WriteLine(str); } Environment.Exit(1); }
/// <summary> /// Request new images from the Spotlight API and return image urls (Single Attempt) /// </summary> /// <param name="maxres">Force maximum image resolution. Otherwise, current main monitor screen resolution is used</param> /// <param name="portrait">Null = Auto detect from current main monitor resolution, True = portrait, False = landscape.</param> /// <param name="locale">Null = Auto detect from current system, or specify xx-XX value format such as en-US</param> /// <returns>List of images</returns> /// <exception cref="System.Net.WebException">An exception is thrown if the request fails</exception> /// <exception cref="System.IO.InvalidDataException">An exception is thrown if the JSON data is invalid</exception> private static SpotlightImage[] GetImageUrlsSingleAttempt(bool maxres = false, bool?portrait = null, string locale = null) { List <SpotlightImage> images = new List <SpotlightImage>(); Json.JSONData imageData = Json.ParseJson(PerformApiRequest(maxres, locale)); if (portrait == null) { portrait = Screen.PrimaryScreen.Bounds.Height > Screen.PrimaryScreen.Bounds.Width; } if (imageData.Type == Json.JSONData.DataType.Object && imageData.Properties.ContainsKey("batchrsp")) { imageData = imageData.Properties["batchrsp"]; if (imageData.Type == Json.JSONData.DataType.Object && imageData.Properties.ContainsKey("items")) { if (!imageData.Properties.ContainsKey("ver") || imageData.Properties["ver"].StringValue != "1.0") { Console.Error.WriteLine("SpotlightAPI: Unknown or missing API response version. Errors may occur."); } imageData = imageData.Properties["items"]; if (imageData.Type == Json.JSONData.DataType.Array) { foreach (Json.JSONData element in imageData.DataArray) { if (element.Type == Json.JSONData.DataType.Object && element.Properties.ContainsKey("item")) { Json.JSONData item = element.Properties["item"]; if (item.Type == Json.JSONData.DataType.String) { item = Json.ParseJson(item.StringValue); } if (item.Type == Json.JSONData.DataType.Object && item.Properties.ContainsKey("ad") && item.Properties["ad"].Type == Json.JSONData.DataType.Object) { item = item.Properties["ad"]; string title; Json.JSONData titleObj = item.Properties.ContainsKey("title_text") ? item.Properties["title_text"] : null; if (titleObj != null && titleObj.Type == Json.JSONData.DataType.Object && titleObj.Properties.ContainsKey("tx")) { title = titleObj.Properties["tx"].StringValue; } else { title = null; } string copyright; Json.JSONData copyrightObj = item.Properties.ContainsKey("copyright_text") ? item.Properties["copyright_text"] : null; if (copyrightObj != null && copyrightObj.Type == Json.JSONData.DataType.Object && copyrightObj.Properties.ContainsKey("tx")) { copyright = copyrightObj.Properties["tx"].StringValue; } else { copyright = null; } string urlField = portrait.Value ? "image_fullscreen_001_portrait" : "image_fullscreen_001_landscape"; if (item.Properties.ContainsKey(urlField) && item.Properties[urlField].Type == Json.JSONData.DataType.Object) { item = item.Properties[urlField]; if (item.Properties.ContainsKey("u") && item.Properties.ContainsKey("sha256") && item.Properties.ContainsKey("fileSize") && item.Properties["u"].Type == Json.JSONData.DataType.String && item.Properties["sha256"].Type == Json.JSONData.DataType.String && item.Properties["fileSize"].Type == Json.JSONData.DataType.String) { int fileSizeParsed = 0; if (int.TryParse(item.Properties["fileSize"].StringValue, out fileSizeParsed)) { SpotlightImage image = new SpotlightImage() { Uri = item.Properties["u"].StringValue, Sha256 = item.Properties["sha256"].StringValue, FileSize = fileSizeParsed, Title = title, Copyright = copyright }; try { System.Convert.FromBase64String(image.Sha256); } catch { image.Sha256 = null; } if (!String.IsNullOrEmpty(image.Uri) && !String.IsNullOrEmpty(image.Sha256) && image.FileSize > 0) { images.Add(image); } else { Console.Error.WriteLine("SpotlightAPI: Ignoring image with empty uri, hash and/or file size less or equal to 0."); } } else { Console.Error.WriteLine("SpotlightAPI: Ignoring image with invalid, non-number file size."); } } else { Console.Error.WriteLine("SpotlightAPI: Ignoring item image uri with missing 'u', 'sha256' and/or 'fileSize' field(s)."); } } else { Console.Error.WriteLine("SpotlightAPI: Ignoring item image with missing uri."); } } else { Console.Error.WriteLine("SpotlightAPI: Ignoring item with missing 'ad' object."); } } else { Console.Error.WriteLine("SpotlightAPI: Ignoring non-object item while parsing 'batchrsp/items' field in JSON API response."); } } } else { throw new InvalidDataException("SpotlightAPI: 'batchrsp/items' field in JSON API response is not an array."); } } else { throw new InvalidDataException("SpotlightAPI: Missing 'batchrsp/items' field in JSON API response." + (locale != null ? " Locale '" + locale + "' may be invalid." : "")); } } else { throw new InvalidDataException("SpotlightAPI: API did not return a 'batchrsp' JSON object."); } return(images.ToArray()); }
static void Main(string[] args) { if (args.Length > 0) { string action = null; bool singleImage = false; bool maximumRes = false; bool? portrait = false; string outputDir = "."; string outputName = "spotlight"; bool integrityCheck = true; bool downloadMany = false; bool metadata = false; string fromFile = null; switch (args[0].ToLower()) { case "urls": case "download": case "wallpaper": case "lockscreen": action = args[0].ToLower(); break; default: Console.Error.WriteLine("Unknown action: " + args[0]); Environment.Exit(1); break; } if (args.Length > 1) { for (int i = 1; i < args.Length; i++) { switch (args[i].ToLower()) { case "--single": singleImage = true; break; case "--many": downloadMany = true; break; case "--maxres": maximumRes = true; break; case "--portrait": portrait = true; break; case "--landscape": portrait = false; break; case "--outdir": i++; if (i < args.Length) { outputDir = args[i]; } else { Console.Error.WriteLine("--outdir expects an additional argument."); Environment.Exit(1); } if (!Directory.Exists(outputDir)) { Console.Error.WriteLine("Output directory '" + outputDir + "' does not exist."); Environment.Exit(1); } break; case "--outname": i++; if (i < args.Length) { outputName = args[i]; } else { Console.Error.WriteLine("--outname expects an additional argument."); Environment.Exit(1); } foreach (char invalidChar in Path.GetInvalidFileNameChars()) { if (outputName.Contains(invalidChar)) { Console.Error.WriteLine("Invalid character '" + invalidChar + "' in specified output file name."); Environment.Exit(1); } } break; case "--skip-integrity": integrityCheck = false; break; case "--metadata": metadata = true; break; case "--from-file": i++; if (i < args.Length) { fromFile = args[i]; } else { Console.Error.WriteLine("--from-file expects an additional argument."); Environment.Exit(1); } if (!File.Exists(fromFile)) { Console.Error.WriteLine("Input file '" + fromFile + "' does not exist."); Environment.Exit(1); } break; case "--from-dir": i++; if (i < args.Length) { fromFile = args[i]; } else { Console.Error.WriteLine("--from-dir expects an additional argument."); Environment.Exit(1); } if (Directory.Exists(fromFile)) { string[] jpegFiles = Directory.EnumerateFiles(fromFile, "*.jpg", SearchOption.AllDirectories).ToArray(); if (jpegFiles.Any()) { fromFile = jpegFiles[new Random().Next(0, jpegFiles.Length)]; } else { Console.Error.WriteLine("Input directory '" + fromFile + "' does not contain JPG files."); Environment.Exit(1); } } else { Console.Error.WriteLine("Input directory '" + fromFile + "' does not exist."); Environment.Exit(1); } break; case "--restore": if (action == "lockscreen") { if (FileSystemAdmin.IsAdmin()) { try { Lockscreen.RestoreDefaultGlobalLockscreen(); Environment.Exit(0); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(4); } } else { Console.Error.WriteLine("This program must run as administrator to restore the global lockscreen."); Environment.Exit(4); } } break; default: Console.Error.WriteLine("Unknown argument: " + args[i]); Environment.Exit(1); break; } } } try { int downloadCount = 0; int noNewImgCount = 0; do { SpotlightImage[] images = (fromFile != null && (action == "wallpaper" || action == "lockscreen")) ? new[] { new SpotlightImage() } // Skip API request, we'll use a local file : Spotlight.GetImageUrls(maximumRes, portrait); if (images.Length < 1) { Console.Error.WriteLine(Program.Name + " received an empty image set from Spotlight API."); Environment.Exit(2); } SpotlightImage randomImage = images.OrderBy(p => new Guid()).First(); if (action == "urls") { if (singleImage) { Console.WriteLine(randomImage.Uri); } else { foreach (SpotlightImage image in images) { Console.WriteLine(image.Uri); } } Environment.Exit(0); } try { if (singleImage || action == "wallpaper" || action == "lockscreen") { string outputFile = fromFile ?? randomImage.DownloadToFile(outputDir, integrityCheck, metadata, outputName); Console.WriteLine(outputFile); if (action == "wallpaper") { try { Desktop.SetWallpaper(fromFile ?? outputFile); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(4); } } else if (action == "lockscreen") { if (FileSystemAdmin.IsAdmin()) { try { Lockscreen.SetGlobalLockscreen(fromFile ?? outputFile); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(4); } } else { Console.Error.WriteLine("This program must run as administrator to change the global lockscreen."); Environment.Exit(4); } } Environment.Exit(0); } downloadCount = 0; foreach (SpotlightImage image in images) { string imagePath = image.GetFilePath(outputDir); if (!File.Exists(imagePath)) { Console.WriteLine(image.DownloadToFile(outputDir, integrityCheck, metadata)); downloadCount++; } } Console.Error.WriteLine("Successfully downloaded: " + downloadCount + " images."); Console.Error.WriteLine("Already downloaded: " + (images.Length - downloadCount) + " images."); if (downloadCount == 0) { noNewImgCount++; } else { noNewImgCount = 0; } } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(3); } Console.WriteLine(noNewImgCount); //} while (downloadMany && (downloadCount > 0 || noNewImgCount < 10)); } while (downloadMany && noNewImgCount < 1000); Environment.Exit(0); } catch (Exception e) { Console.Error.WriteLine(e.GetType() + ": " + e.Message); Environment.Exit(2); } } foreach (string str in new[] { " ==== " + Program.Name + " v" + Program.Version + " - By ORelio - Microzoom.fr ====", "", "Retrieve Windows Spotlight images by requesting the Microsoft Spotlight API.", Program.Name + " can also define images as wallpaper and system-wide lockscreen image.", "", "Usage:", " " + Program.Name + ".exe <action> [arguments]", " Only one action must be provided, as first argument", " Then, provide any number of arguments from the list below.", "", "Actions:", " urls Query Spotlight API and print image URLs to standard output", " download Download all images and print file path to standard output", " wallpaper Download one random image and define it as wallpaper", " lockscreen Download one random image and define it as global lockscreen", "", "Arguments:", " --single Print only one random url or download only one image as spotlight.jpg", " --many Try downloading as much images as possible by calling API many times", " --maxres Force maximum image resolution instead of tailoring to current screen res", " --portrait Force portrait image instead of autodetecting from current screen res", " --landscape Force landscape image instead of autodetecting from current screen res", " --outdir <dir> Set output directory instead of defaulting to working directory", " --outname <name> Set output file name as <name>.jpg in single image mode, ignored otherwise", " --skip-integrity Skip integrity check of downloaded files: file size and sha256 hash", " --metadata Also save image metadata such as title & copyright as <image-name>.txt", " --from-file Set the specified file as wallpaper/lockscreen instead of downloading", " --from-dir Set a random image from the specified directory as wallpaper/lockscreen", " --restore Restore the default lockscreen image, has no effect with other actions", "", "Exit codes:", " 0 Success", " 1 Invalid arguments", " 2 Spotlight API request failure", " 3 Image download failure or Failed to write image to disk", " 4 Failed to define image as wallpaper or lock screen image" }) { Console.Error.WriteLine(str); } Environment.Exit(1); }
/// <summary> /// Load an input image, adjust to screen res, embed metadata using current desktop scaling factor and save the result into a new image file /// </summary> /// <param name="inputImageFile">Input image file</param> /// <param name="outputDir">Output directory</param> /// <param name="outputName">Output file name</param> /// <param name="adjustToScreen">Auto adjust image to current screen resolution</param> /// <param name="adjustToScaling">Auto adjust text to current UI scaling factor</param> /// <returns>Output file path</returns> public static string EmbedMetadata(string inputImageFile, string outputDir, string outputName, bool adjustToScreen = true, bool adjustToScaling = true) { //Windows 7 or lower cannot use PNG as wallpaper or will convert PNG to JPG, better use BMP for best quality string fileExtension = ".bmp"; var imageFormat = System.Drawing.Imaging.ImageFormat.Bmp; //Windows 8 and 10 will convert BMP to JPG, better use PNG for best quality if ((WindowsVersion.WinMajorVersion == 6 && WindowsVersion.WinMinorVersion >= 2) || WindowsVersion.WinMajorVersion >= 10) { fileExtension = ".png"; imageFormat = System.Drawing.Imaging.ImageFormat.Png; } if (String.IsNullOrEmpty(outputName)) { outputName = Path.GetFileNameWithoutExtension(inputImageFile); } string outputFile = Path.Combine(outputDir, outputName + fileExtension); Image img = Image.FromFile(inputImageFile); if (adjustToScreen) { Rectangle screen = System.Windows.Forms.Screen.PrimaryScreen.Bounds; Image img2 = FixedImageResize(img, screen.Width, screen.Height, true); img.Dispose(); img = img2; } string metadataFile = GetMetaLocation(inputImageFile); if (File.Exists(metadataFile)) { SpotlightImage meta = LoadMeta(metadataFile); Graphics gfx = Graphics.FromImage(img); gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; gfx.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; int fontSize = 11; if (adjustToScaling) { fontSize = (int)((float)fontSize * Desktop.GetScalingFactor()); } Font font = new Font("Segoe UI Semilight", fontSize); SizeF titleSize = gfx.MeasureString(meta.Title, font); if (titleSize.Width < img.Size.Width - 20) { gfx.DrawString( meta.Title, font, Brushes.White, new Rectangle( img.Size.Width - 10 - (int)Math.Ceiling(titleSize.Width), 10, (int)Math.Ceiling(titleSize.Width), (int)Math.Ceiling(titleSize.Height) ) ); gfx.Flush(); } } img.Save(outputFile, imageFormat); img.Dispose(); return(outputFile); }