首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将图像从Windows 10锁定屏幕拖到另一个文件夹

将图像从Windows 10锁定屏幕拖到另一个文件夹
EN

Code Review用户
提问于 2019-04-19 16:12:28
回答 1查看 48关注 0票数 2

Windows 10有一个有趣的特性,它将在锁定屏幕上显示“有趣的事实”和图像。有时候,这些图片是我想要用作背景的东西。

这些图像存储在%LocalAppData%\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets中。

由于我不确定_cw5n1h2txyewyMicrosoft.Windows.ContentDeliveryManager文件夹中是否是常量,所以我只想搜索%LocalAppData%\Packages目录中的Microsoft.Windows.ContentDeliveryManager*,并提取第一个匹配该模式的目录。

然后,在该目录中,我希望复制图像并从每个图像中读取一个“魔术号”,该数字可以不同,但可以确定图像类型。在本例中,我使用前4个字节作为0x89 0x50 0x4E 0x47 (或0x89,然后是PNG),或使用6到9字节作为0x4A 0x46 0x49 0x46 (JFIF)或0x45 0x78 0x69 0x66 (Exif)。第一个条件将添加png扩展,第二个条件将添加jpg

第一个函数是my detect_file_type,它评估文件内容并确定它是什么图像类型:

代码语言:javascript
复制
fn detect_file_type(data : &Vec<u8>) -> Option<String> {
    if data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 { // ?PNG
        Some("png".to_string())
    } else if data[6] == 0x4A && data[7] == 0x46 && data[8] == 0x49 && data[9] == 0x46 { // JFIF
        Some("jpg".to_string())
    } else if data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66 { // Exif
        Some("jpg".to_string())
    } else { 
        None
    }
}

这是相当简单的。

接下来,我想要我的目录搜索功能:

代码语言:javascript
复制
fn find_dir(search : &str, path : PathBuf) -> Option<PathBuf> {
    for entry in fs::read_dir(path).unwrap() {
        let path = entry.unwrap().path();
        if path.is_dir() {
            if path.file_name().unwrap().to_str().unwrap().starts_with(search) {
                return Some(path);
            }
        }
    }
    return None;
}

再说一遍,很简单。我们坚持使用这两种方法的Option,以便能够处理错误案例(如果需要的话)。

最后,我们有了所有的关键工作:

代码语言:javascript
复制
fn main() {
    let args = 
        App::new("Pull Windows Lock-Screen Pictures")
            .version("0.1")
            .about("Loads the images used for the main Windows 10 Lock-Screen backgrounds to the specified folder (or './out' if not specified).")
            .arg(Arg::with_name("destination")
                .help("The destination directory ('./out' by default)")
                .takes_value(true)
                .required(false))
            .get_matches();

    let my_dirs = Directories::with_prefix("windows_lock_screen_pictures", "Windows_Lock_Screen_Pictures").unwrap();
    let home = my_dirs.bin_home().parent().unwrap().parent().unwrap().join("Packages");
    let dir = find_dir("Microsoft.Windows.ContentDeliveryManager", home).unwrap().join("LocalState").join("Assets");

    for entry in fs::read_dir(dir).unwrap() {
        let path = entry.unwrap().path();
        if !path.is_dir() {
            let data = fs::read(&path).unwrap();
            let path_str = path.display().to_string();
            let file = path.file_name().unwrap().to_str().unwrap().to_string();

            let path_ext =
                match detect_file_type(&data) {
                    Some(path_ext) => {
                        let mut res = ".".to_string();
                        res.push_str(&path_ext);
                        res
                    },
                    _ => "".to_string()
                };

            let mut base_dest_dir = "".to_string();
            let mut default = std::env::current_dir().unwrap().to_str().unwrap().to_string();
            default.push_str("\\out\\");
            let dest_dir = args.value_of("destination").unwrap_or(&default);
            base_dest_dir.push_str(dest_dir);

            if !Path::new(&base_dest_dir).exists() {
                fs::create_dir(Path::new(&base_dest_dir)).expect("Could not create directory");
            }

            base_dest_dir.push_str(&file);
            base_dest_dir.push_str(&path_ext);

            println!("{} -> {}", path_str, base_dest_dir);
            fs::write(Path::new(&base_dest_dir), data).expect("Could not write file");
        }
    }
}

总的来说,我们保持的东西相当小,但仍然允许灵活性(以及我们所需要的大部分安全)。

我们的整个计划如下:

外箱拍击;

代码语言:javascript
复制
use std::fs::{self};
use std::path::{Path,PathBuf};
use clap::{App,Arg};
use dirs::{Directories};

fn detect_file_type(data : &Vec<u8>) -> Option<String> {
    if data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 { // ?PNG
        Some("png".to_string())
    } else if data[6] == 0x4A && data[7] == 0x46 && data[8] == 0x49 && data[9] == 0x46 { // JFIF
        Some("jpg".to_string())
    } else if data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66 { // Exif
        Some("jpg".to_string())
    } else { 
        None
    }
}

fn find_dir(search : &str, path : PathBuf) -> Option<PathBuf> {
    for entry in fs::read_dir(path).unwrap() {
        let path = entry.unwrap().path();
        if path.is_dir() {
            if path.file_name().unwrap().to_str().unwrap().starts_with(search) {
                return Some(path);
            }
        }
    }
    return None;
}

fn main() {
    let args = 
        App::new("Pull Windows Lock-Screen Pictures")
            .version("0.1")
            .about("Loads the images used for the main Windows 10 Lock-Screen backgrounds to the specified folder (or './out' if not specified).")
            .arg(Arg::with_name("destination")
                .help("The destination directory ('./out' by default)")
                .takes_value(true)
                .required(false))
            .get_matches();

    let my_dirs = Directories::with_prefix("windows_lock_screen_pictures", "Windows_Lock_Screen_Pictures").unwrap();
    let home = my_dirs.bin_home().parent().unwrap().parent().unwrap().join("Packages");
    let dir = find_dir("Microsoft.Windows.ContentDeliveryManager", home).unwrap().join("LocalState").join("Assets");

    for entry in fs::read_dir(dir).unwrap() {
        let path = entry.unwrap().path();
        if !path.is_dir() {
            let data = fs::read(&path).unwrap();
            let path_str = path.display().to_string();
            let file = path.file_name().unwrap().to_str().unwrap().to_string();

            let path_ext =
                match detect_file_type(&data) {
                    Some(path_ext) => {
                        let mut res = ".".to_string();
                        res.push_str(&path_ext);
                        res
                    },
                    _ => "".to_string()
                };

            let mut base_dest_dir = "".to_string();
            let mut default = std::env::current_dir().unwrap().to_str().unwrap().to_string();
            default.push_str("\\out\\");
            let dest_dir = args.value_of("destination").unwrap_or(&default);
            base_dest_dir.push_str(dest_dir);

            if !Path::new(&base_dest_dir).exists() {
                fs::create_dir(Path::new(&base_dest_dir)).expect("Could not create directory");
            }

            base_dest_dir.push_str(&file);
            base_dest_dir.push_str(&path_ext);

            println!("{} -> {}", path_str, base_dest_dir);
            fs::write(Path::new(&base_dest_dir), data).expect("Could not write file");
        }
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2019-04-20 01:11:11

几个普通的笔记。

  • 应用程序目录应该是一致的。这是一个UWP应用程序,这是应用程序包家族名称的一部分。不过,您的实现很好。
  • 我会利用一些强类型,而不是”jpg””png”字符串。
  • 说到文件类型检测,您可能想要使用像树一样的库_魔术
  • 你真的不应该unwrap(),除非你确信它不应该失败。它实际上是不友好的用户,应该保留开发人员的错误。由于文件权限,大多数unwraps可能会失败。在这样一个小应用程序中,我可能会使用期望来提供更友好的错误信息。在更大的部分中,链接文档包含了在结果类型上所期望的所有方法。

有些事我喜欢:

  • 您很快就接受了习语,比如模式匹配和省略return关键字。

混淆:

我们已经审查对方的密码很长时间了。我一直对你倾向于使用密集逻辑而不是提取方法感到惊讶。我不介意这种密集的逻辑,我只是认为您有一个通用的机会来命名事物并提高抽象级别。对于这个应用程序,我希望代码读起来像这样,隐藏较低层次的细节。

代码语言:javascript
复制
let outdir = parse_args().or_else(“./out”);
let files = get_files();
copy_files(files, outdir);
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/217745

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档