commit bcb1ff0477aefcc50ab6653114560b748169da1f Author: xzeldon Date: Sat Apr 17 04:12:25 2021 +0300 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b72800a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,357 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-utils" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "ctrlc" +version = "3.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "232295399409a8b7ae41276757b5a1cc21032848d42bff2352261f958b3ca29a" +dependencies = [ + "nix", + "winapi", +] + +[[package]] +name = "dirs" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "embed-resource" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e03c3dae04b8f252f2866d25e0ec8f2f488efba43bc6e307274b65c4321f94" +dependencies = [ + "cc", + "vswhom", + "winreg", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" + +[[package]] +name = "nix" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rdr2_screenshot_converter" +version = "1.0.0" +dependencies = [ + "colored", + "ctrlc", + "dirs", + "embed-resource", + "serde", + "serde_json", + "winapi", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "rust-argon2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "serde" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f5402d3d0e79a069714f7b48e3ecc60be7775a2c049cb839457457a239532" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winreg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d107f8c6e916235c4c01cabb3e8acf7bea8ef6a63ca2e7fa0527c049badfc48c" +dependencies = [ + "winapi", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1184c3d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "rdr2_screenshot_converter" +version = "1.0.0" +authors = ["Timofey Gelazoniya "] +description = "Convert and save screenshots from rdr2 photo mode to JPEG format" +readme = "README.md" +keywords = ["rdr2", "screenshot", "screenshots", "convert", "jpeg"] +license = "MIT" +edition = "2018" +build = "build/build.rs" + +[dependencies] +dirs = "3.0.1" +colored = "2.0.0" +serde = { version = "1.0", features = ["derive"] } +ctrlc = { version = "3.0", features = ["termination"] } +serde_json = "1.0" + +[target.'cfg(target_os="windows")'.dependencies.winapi] +version = "0.3" +features = ["consoleapi", "errhandlingapi", "fileapi", "handleapi", "processenv"] + +[build-dependencies] +embed-resource = "1.6" \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..761ed76 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# RDR2 Screensht converter [![Licence](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) + +Convert and save screenshots from rdr2 photo mode to JPEG format + +![Imgur](https://i.imgur.com/ZGbmHYd.png) + +## QuickStart +Just download the executable file from releases and run it. It will automatically find your screenshots and save them. + +## Arguments +You can define a path for saving screenshots. To do this, open a command prompt, specify the path to the executable file and the path to save the screenshots. +``` +rdr2_screenshot_converter.exe C:\screenshots +``` +This command will save screenshots to ```C:\screenshots``` + +## Building +All instructions tested on Windows 10 Pro for workstations 19042.928. + +You need: +* [Rust](https://www.rust-lang.org) +``` +rustup override set nightly +cargo build --release +``` diff --git a/build/assets/icon.ico b/build/assets/icon.ico new file mode 100644 index 0000000..759fe6a Binary files /dev/null and b/build/assets/icon.ico differ diff --git a/build/assets/icon.rc b/build/assets/icon.rc new file mode 100644 index 0000000..b62fca7 --- /dev/null +++ b/build/assets/icon.rc @@ -0,0 +1 @@ +rdr2_scrn_converter ICON "./icon.ico" \ No newline at end of file diff --git a/build/build.rs b/build/build.rs new file mode 100644 index 0000000..083f4e1 --- /dev/null +++ b/build/build.rs @@ -0,0 +1,7 @@ +use embed_resource; +use std::{env, path::Path}; + +fn main() { + let curr_dir = env::current_dir().unwrap(); + embed_resource::compile(Path::new(&curr_dir).join("build").join("assets").join("icon.rc")); +} \ No newline at end of file diff --git a/src/buffertrim.rs b/src/buffertrim.rs new file mode 100644 index 0000000..9fe96e8 --- /dev/null +++ b/src/buffertrim.rs @@ -0,0 +1,10 @@ +fn is_not_empty(e: &u8) -> bool { + *e != 0x00 +} + +pub fn trim(buffer: &[u8]) -> Vec { + let begin = buffer.iter().position(is_not_empty); + let end = buffer.iter().rev().position(is_not_empty).map(|j| buffer.len() - j); + let vec = begin.and_then(|i| end.map(|j| buffer[i..j].iter().cloned().collect())).unwrap_or(Vec::new()); + vec +} \ No newline at end of file diff --git a/src/console.rs b/src/console.rs new file mode 100644 index 0000000..960aac3 --- /dev/null +++ b/src/console.rs @@ -0,0 +1,92 @@ +#[cfg(windows)] +pub fn enable_ansi_support() -> Result<(), u32> { + // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76% + + use std::ffi::OsStr; + use std::iter::once; + use std::os::windows::ffi::OsStrExt; + use std::ptr::null_mut; + use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; + use winapi::um::errhandlingapi::GetLastError; + use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING}; + use winapi::um::handleapi::INVALID_HANDLE_VALUE; + use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE}; + + const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004; + + unsafe { + // ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + // Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected + let console_out_name: Vec = OsStr::new("CONOUT$").encode_wide().chain(once(0)).collect(); + let console_handle = CreateFileW( + console_out_name.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + null_mut(), + OPEN_EXISTING, + 0, + null_mut(), + ); + if console_handle == INVALID_HANDLE_VALUE + { + return Err(GetLastError()); + } + + // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode + let mut console_mode: u32 = 0; + if 0 == GetConsoleMode(console_handle, &mut console_mode) + { + return Err(GetLastError()); + } + + // VT processing not already enabled? + if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 { + // https://docs.microsoft.com/en-us/windows/console/setconsolemode + if 0 == SetConsoleMode(console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) + { + return Err(GetLastError()); + } + } + } + + return Ok(()); +} + +pub fn set_ctrl_c_handler() { + use std::sync; + use std::process; + + let running = sync::Arc::new(sync::atomic::AtomicBool::new(true)); + let r = running.clone(); + + ctrlc::set_handler(move || { + r.store(false, sync::atomic::Ordering::SeqCst); + }).expect("> Error setting Ctrl-C handler"); + println!("> Press Ctrl + C for exit"); + while running.load(sync::atomic::Ordering::SeqCst) {} + println!("> Exiting..."); + process::exit(0); +} + +pub fn get_raw_command_line() -> String { + // use winapi::um::processenv::GetCommandLineW; + + unsafe { + let line = GetCommandLineW(); + + let mut cursor = line; + let mut length = 0; + while *cursor != 0 { + length += 1; + cursor = cursor.add(1); + } + let array: &[u16] = std::slice::from_raw_parts(line, length); + + String::from_utf16(array).expect("Invalid unicode") + } +} + +#[link(name="kernel32")] +extern "system" { + fn GetCommandLineW() -> *const u16; +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5839af0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,205 @@ +mod buffertrim; + +use dirs; +use colored::*; +use serde::Deserialize; +use fs::File; +use io::Read; +use std::{fs, io, path::{Path, PathBuf}}; + +pub fn run(config: Config) -> Result<(), String> { + + let mut profiles = Vec::new(); + let paths = fs::read_dir(config.profile_path).unwrap(); + + for path in paths { + profiles.push(path.unwrap().path()); + } + + if profiles.len() <= 0 { + return Err(format!("{}: {} {} \n{}", "> Error".red().bold(), "Profile folder not found.".white(), "You must run the game at least once!".white().bold(), "> Aborting.".red())); + } + + let scrns = grab_scrn_files(&profiles); + + if scrns.len() <= 0 { + return Err(format!("{}: {} \n{}", "> Error".red().bold(), "Screenshot files not found".white(), "> Aborting.".red())); + } + + println!("{} {} {} \n{}", ">".green(), scrns.len().to_string().green(), "Screenshots found.".green(), "> Converting...".green().bold()); + + let mut images = Vec::new(); + + for file in &scrns { + let image = convert_file(file.to_path_buf()).unwrap(); + images.push(image); + } + + for image in &images { + match fs::write(Path::new(&config.export_path).join(image.metadata.uid.to_string() + ".jpg"), &image.image_data) { + Ok(ok) => ok, + Err(_err) => { + return Err(format!("{}: {} \n{}", "> Error".red().bold(), "System cannot find or create the specified path", "> Aborting.".red())) + } + } + } + + println!("{}", "> Converting completed!".green()); + println!("{} {}", "> Files saved to".green().bold(), Path::new(&config.export_path).to_string_lossy().bright_blue()); + + println!("{}", "> Removing old files...".green()); + for path in scrns { + let _remove = fs::remove_file(path).unwrap(); + } + + Ok(()) +} + +pub struct Config { + pub profile_path: PathBuf, + pub export_path: PathBuf, +} + +impl Config { + pub fn new() -> Result { + let home_dir = dirs::home_dir().unwrap(); + let profile_path = Path::new(&home_dir).join("Documents").join("Rockstar Games").join("Red Dead Redemption 2").join("Profiles"); + let export_path = Path::new(&home_dir).join("Documents").join("Rockstar Games").join("Red Dead Redemption 2").join("Screenshots"); + + let _create_dirs = fs::create_dir_all(&export_path); + + Ok(Config {profile_path, export_path}) + } + + pub fn set_custom_export_path<'a>(&'a mut self, path: &[String]) -> Result<&'a mut Config, String> { + if path.len() < 2 { + return Err(format!("{}", "Not enough arguments")); + } + + let path = path[1].clone(); + let custom_export_path = Path::new(&path).to_path_buf(); + // TODO: Folders containing Cyrillic characters and spaces are created incorrectly i. e. anything after a space is ignored + // let _create_dirs = fs::create_dir_all(&custom_export_path); + + self.export_path = custom_export_path; + + Ok(self) + } +} + +fn grab_scrn_files(profile_paths: &[PathBuf]) -> Vec { + let mut prdr3s = Vec::new(); + + for path in profile_paths { + match fs::read_dir(path) { + Err(err) => println!("! {:?}", err.kind()), + Ok(paths) => for path in paths { + let file_path = path.unwrap().path(); + let file_stem = file_path.file_stem().unwrap().to_str().unwrap(); + + if file_stem.chars().count() >= 5 { + let file_stem_substr = &file_stem[0..5]; + + if file_stem_substr == "PRDR3" { + prdr3s.push(file_path) + } + } + } + } + } + prdr3s +} + +fn read_file_buf(path: PathBuf) -> Result, io::Error> { + let mut file = File::open(path)?; + let mut data = Vec::new(); + file.read_to_end(&mut data)?; + + return Ok(data); +} + +fn find_index_in_buf(buffer: &Vec, index: &[u8]) -> usize { + let index = buffer.windows(index.len()).position(|window| window == index).unwrap(); + index +} + +fn grab_image_from_buf(buffer: &Vec) -> Vec { + let first_index = find_index_in_buf(&buffer, b"JPEG"); + let last_index = find_index_in_buf(&buffer, b"JSON"); + let image_data = buffertrim::trim(&buffer[first_index + 12..last_index]); + image_data +} + +fn grab_metadata_from_buf(buffer: &Vec) -> Vec { + let first_index = find_index_in_buf(&buffer, b"JSON"); + let last_index = find_index_in_buf(&buffer, b"TITL"); + let metadata = buffertrim::trim(&buffer[first_index + 8..last_index]); + metadata +} + +#[derive(Deserialize, Debug)] +struct Loc { + x: f64, + y: f64, + z: f64 +} + +#[derive(Deserialize, Debug)] +struct Time { + hour: i32, + minute: i32, + second: i32, + day: i32, + month: i32, + year: i32 +} + +#[derive(Deserialize, Debug)] +struct Meta { + horse: Option> +} + +#[derive(Deserialize, Debug)] +struct ImageMetadata { + loc: Loc, + regionname: usize, + districtname: usize, + statename: usize, + nm: String, + sid: String, + crewid: usize, + mid: String, + mode: String, + meme: bool, + mug: bool, + uid: usize, + time: Time, + creat: usize, + slf: bool, + drctr: bool, + rsedtr: bool, + inphotomode: bool, + advanced: bool, + width: usize, + height: usize, + size: usize, + sign: usize, + meta: Meta +} + +#[derive(Deserialize, Debug)] +struct Image { + metadata: ImageMetadata, + image_data: Vec +} + +fn convert_file(path: PathBuf) -> Result { + let mut file_buf = read_file_buf(path).unwrap(); + file_buf = buffertrim::trim(&file_buf); + + let image_data = grab_image_from_buf(&file_buf); + let metadata = grab_metadata_from_buf(&file_buf); + let parsed_metadata: ImageMetadata = serde_json::from_slice(&metadata).unwrap(); + + Ok(Image { metadata: parsed_metadata, image_data }) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..4f77bc8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,23 @@ +mod buffertrim; +mod console; + +use rdr2_screenshot_converter::Config; +use std::env; + +fn main() { + let args: Vec = env::args().collect(); + + let mut config = Config::new().unwrap(); + + if args.len() >= 2 { + config.set_custom_export_path(&args).unwrap(); + } + + let _ansi_support = console::enable_ansi_support(); + + if let Err(e) = rdr2_screenshot_converter::run(config) { + eprintln!("{}", e); + } + + let _ctrl_c_handler = console::set_ctrl_c_handler(); +} \ No newline at end of file