龙空技术网

用Rust保存Windows聚焦图片

寒江雪归客 103

前言:

此时各位老铁们对“window10聚焦变成图片了”都比较看重,朋友们都想要学习一些“window10聚焦变成图片了”的相关文章。那么小编同时在网络上网罗了一些对于“window10聚焦变成图片了””的相关文章,希望各位老铁们能喜欢,各位老铁们一起来学习一下吧!

简介

Windows聚焦(Windows Spotlight)是Windows 10里新增的一个锁屏壁纸功能,它会自动下载并随机更换锁屏壁纸。Windows聚焦的照片精美震撼,但遗憾的是Windows聚焦只能在锁屏时使用,无法在桌面背景中使用。

Windows聚焦

本文使用Rust语言开发了一个Windows聚焦图片的保持工具,可自动保持Windows聚焦图片。

程序源代码可以访问下载。

Windows聚焦存储

Windows聚焦自动下载图片,下载的图片会临时存储在用户目录下:

Windows聚焦图片存储目录

Windows聚焦的存储目录为:C:\Users\XXX\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets

其中,XXX为用户名,该目录下字母与数字组成的无扩展名的文件即为图片文件。

程序设计思路

这里我希望能够开发一个程序,自动扫描Windows聚焦存储目录下的文件,发现有新的图片时拷贝存储到指定的图片目录中,图片的存储目录,可以在Windows背景图片中作为幻灯片放映的目录使用。

程序会被配置到Windows计划任务中,在开机时或定期执行,如果存储的图片较多的话,我们希望能够把历史图片归档到子目录中。

最终实现的工具命令如下:

PS> spotlight_save.exe -helpspotlight_save 1.0.0Steven Lee <leexgone@163.com>Save splotlight images in Win10.USAGE:    spotlight_save.exe [FLAGS] [DIR]FLAGS:    -a, --archive    Archive images by year    -h, --help       Prints help information    -V, --version    Prints version information    -v, --verbose    Use verbose outputARGS:    <DIR>    Target image dir. Default dir is '${HOME}/Pictures/Spotlight/'
代码开发

创建一个Rust工程,在Cargo.toml中引入我们需要的第三方包:

[dependencies]clap = "2.33"home = "0.5"image = "0.23"chrono = "0.4"

main.rs文件中编写主逻辑代码:

use std::process;use spotlight_save::Config;fn main() {    let config = Config::new().unwrap_or_else(|err| {        eprintln!("Error when parsing arguments: {}", err);        process::exit(1);    });    if let Err(e) = spotlight_save::run(config) {        eprintln!("Error when saving images: {}", e);        process::exit(1);    }}

lib.rs中编写我们的主要逻辑代码:

use std::{error::Error, fmt::Display, fs, path::PathBuf};use chrono::{DateTime, Duration, Local};use clap::{App, Arg};use image::{GenericImageView, io::Reader};#[derive(Debug)]pub struct Config {    target: PathBuf,    verbose: bool,    archive: bool,}impl Display for Config {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        write!(f, "[target = {}, verbose = {}, archive = {}]", self.target.display(), self.verbose, self.archive)    }}impl Config {    pub fn new() -> Result<Config, String> {        let matches = App::new("spotlight_save")                        .version("1.0.0")                        .author("Steven Lee <leexgone@163.com>")                        .about("Save splotlight images in Win10.")                        .arg(Arg::with_name("DIR")                            .help("Target image dir. Default dir is '${HOME}/Pictures/Spotlight/'")                            .index(1))                        .arg(Arg::with_name("verbose")                            .short("v")                            .long("verbose")                            .help("Use verbose output"))                        .arg(Arg::with_name("archive")                            .short("a")                            .long("archive")                            .help("Archive images by year"))                        .get_matches();        let verbose = matches.is_present("verbose");        let archive = matches.is_present("archive");        let target = if let Some(dir) = matches.value_of("DIR") {            PathBuf::from(dir)        } else {            let home_dir = home::home_dir().unwrap();            let picture_dir = home_dir.join("Pictures");            if !picture_dir.is_dir() {                let msg = format!("Can not find dir '{}'", picture_dir.display());                return Err(msg);            }            picture_dir.join("Spotlight")        };        if !target.is_dir() {            let msg = format!("target dir '{}' does not exist", target.display());            return Err(msg);        }        Ok(Config {            target,            verbose,            archive,        })    }}macro_rules! log {    ($enabled:expr) => {        {if $enabled { println!(); }}    };    ($enabled:expr, $($arg:tt)*) => {        {if $enabled { println!($($arg)*); }}    };}pub fn run(config: Config) -> Result<(), Box<dyn Error>> {    save_images(&config)?;    if config.archive {        archive_images(&config)?;    }    Ok(())}fn get_spotlight_dir() -> Result<PathBuf, Box<dyn Error>> {    let home_dir = home::home_dir().unwrap();    let package_dir = home_dir.join("AppData\\Local\\Packages");    for entry in package_dir.read_dir()? {        let entry = entry?;        let path = entry.path();        if !path.is_dir() {            continue;        }        let pathname = path.file_name().unwrap();        let pathname = pathname.to_str().unwrap();        if pathname.starts_with("Microsoft.Windows.ContentDeliveryManager_") {            let image_dir = path.join("LocalState\\Assets");            return  Ok(image_dir);        }    }    let err = std::io::Error::new(std::io::ErrorKind::NotFound, String::from("Can not find Spotlight image dir"));    Err(Box::new(err))}fn save_images(config: &Config) -> Result<(), Box<dyn Error>> {    let spotlight_dir = get_spotlight_dir()?;    log!(config.verbose, "Scan spotlight dir: {}", spotlight_dir.display());    let mut count = 0;    for entry in spotlight_dir.read_dir()? {        let entry = entry?;        let path = entry.path();        if !path.is_file() {            continue;        }        if save_image(config, &path) {            count += 1;        }    }    log!(config.verbose, "{} images saved!", count);    Ok(())}fn save_image(config: &Config, filepath: &PathBuf) -> bool {    log!(config.verbose, "Scan file: {}...", filepath.display());    let reader = if let Ok(reader) = Reader::open(filepath) {        reader    } else {        return false;    };    let reader = if let Ok(reader) = reader.with_guessed_format() {        reader    } else {        return false;    };    let format = if let Some(format) = reader.format() {        format    } else {        return false;    };    let image = if let Ok(image) = reader.decode() {        image    } else {        return false;    };    if image.width() < image.height() || image.width() < 800 || image.height() < 600 {        return false;    }    let ext = format.extensions_str().first().unwrap();    let mut filename = String::from(filepath.file_name().unwrap().to_str().unwrap());    filename.push_str(".");    filename.push_str(*ext);    let target_file = config.target.join(filename);    if target_file.exists() {        return false;    }    log!(config.verbose, "Saving image: {} ...", target_file.display());    fs::copy(filepath, target_file).is_ok()}fn archive_images(config: &Config) -> Result<(), Box<dyn Error>> {    log!(config.verbose, "Archive images in dir: {}", config.target.display());    let timeline = Local::today() - Duration::days(365);    for entry in config.target.read_dir()? {        let entry = entry?;        let path = entry.path();        if !path.is_file() {            continue;        }        if let Ok(metadata) = entry.metadata() {            let filetime = if let Ok(modified) = metadata.modified() {                modified            } else if let Ok(created) = metadata.created() {                created            } else {                continue;            };            let filedate = DateTime::from(filetime).date();            if filedate < timeline {                    log!(config.verbose, "archive file: {} ...", path.display());                                let year = filedate.format("%Y").to_string();                let dir = config.target.join(year);                if !dir.exists() {                    fs::create_dir(&dir)?;                }                let bak_file = dir.join(path.file_name().unwrap());                fs::copy(&path, &bak_file)?;                fs::remove_file(&path)?;            }        }    }    Ok(())}

使用cargo build --release编译生成工具。

配置计划任务并应用为壁纸

为了定制保持图片,我们在Windows计划任务中配置一个计划任务执行程序,这里我选择开机时执行。

配置计划任务

在Windows背景壁纸中设置幻灯片放映,指定存储照片的目录即可。

在Windows背景中幻灯片播放壁纸

标签: #window10聚焦变成图片了 #window聚焦不换图片怎么办