Compare commits

..

No commits in common. 'master' and 'v0.1.1' have entirely different histories.

  1. 1
      .gitignore
  2. 2
      Cargo.lock
  3. 2
      Cargo.toml
  4. 30
      Makefile
  5. 214
      src/main.rs

1
.gitignore vendored

@ -1,3 +1,2 @@
/target /target
/.idea /.idea
/release

2
Cargo.lock generated

@ -4,4 +4,4 @@ version = 3
[[package]] [[package]]
name = "pngrip" name = "pngrip"
version = "0.1.3" version = "0.1.1"

2
Cargo.toml

@ -1,6 +1,6 @@
[package] [package]
name = "pngrip" name = "pngrip"
version = "0.1.3" version = "0.1.1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

30
Makefile

@ -1,30 +0,0 @@
cross: clean
cargo build --release --target x86_64-pc-windows-gnu
cargo build --release --target x86_64-unknown-linux-musl
cargo build --release --target i686-unknown-linux-musl
cargo build --release --target i686-pc-windows-gnu
mkdir -p release/pngrip_x86_64-pc-windows-gnu
mkdir -p release/pngrip_x86_64-unknown-linux-musl
mkdir -p release/pngrip_i686-unknown-linux-musl
mkdir -p release/pngrip_i686-pc-windows-gnu
cp LICENSE release/pngrip_x86_64-pc-windows-gnu
cp LICENSE release/pngrip_x86_64-unknown-linux-musl
cp LICENSE release/pngrip_i686-unknown-linux-musl
cp LICENSE release/pngrip_i686-pc-windows-gnu
cp target/x86_64-pc-windows-gnu/release/pngrip.exe release/pngrip_x86_64-pc-windows-gnu
cp target/x86_64-unknown-linux-musl/release/pngrip release/pngrip_x86_64-unknown-linux-musl
cp target/i686-unknown-linux-musl/release/pngrip release/pngrip_i686-unknown-linux-musl
cp target/i686-pc-windows-gnu/release/pngrip.exe release/pngrip_i686-pc-windows-gnu
cd release && \
zip -r pngrip_x86_64-pc-windows-gnu pngrip_x86_64-pc-windows-gnu/ && \
zip -r pngrip_x86_64-unknown-linux-musl pngrip_x86_64-unknown-linux-musl && \
zip -r pngrip_i686-unknown-linux-musl pngrip_i686-unknown-linux-musl && \
zip -r pngrip_i686-pc-windows-gnu pngrip_i686-pc-windows-gnu
clean:
rm -rf release

214
src/main.rs

@ -13,187 +13,131 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::Path; use std::path::Path;
#[derive(Debug)] /// extracts png images from file that path points to, saving every image to destination directory.
struct Position { /// If an error occurs - returns immediately.
start: usize, fn rip_png(path: &Path, destination: &Path) {
end: usize, let png_identifier: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];
} let iend_identifier: [u8; 4] = [73, 69, 78, 68];
// Reads data from specified start_index position,
// if valid png bytes were found - returns exact positions of an image
fn rip_png(data: &[u8], start_index: usize) -> Option<Position> {
const PNG_IDENTIFIER: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0xD, 0xA, 0x1A, 0xA];
const PNG_END_IDENTIFIER: [u8; 8] = [0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82];
if data.len() < PNG_IDENTIFIER.len() + PNG_END_IDENTIFIER.len() ||
start_index + PNG_IDENTIFIER.len() + PNG_END_IDENTIFIER.len() > data.len() {
return None;
}
let mut position: Position = Position{
start: usize::MAX,
end: usize::MAX,
};
for i in start_index..data.len() { let filename;
// start index match path.file_name() {
if i < data.len() - PNG_IDENTIFIER.len() && position.start == usize::MAX { Some(name) => {
if data[i..i + PNG_IDENTIFIER.len()] == PNG_IDENTIFIER { filename = String::from(name.to_string_lossy());
position.start = i;
} }
} None => {
eprintln!("[ERROR] Could not get filename from \"{}\"", path.display());
// end index return;
if i <= data.len() - PNG_END_IDENTIFIER.len() && position.end == usize::MAX {
if data[i..i + PNG_END_IDENTIFIER.len()] == PNG_END_IDENTIFIER {
position.end = i + PNG_END_IDENTIFIER.len();
} }
} }
if position.start != usize::MAX && position.end != usize::MAX { println!("[INFO] Ripping PNGs from \"{}\"...", filename);
break;
}
}
if position.start == usize::MAX || position.end == usize::MAX || position.end <= position.start { let mut file;
return None; match std::fs::File::open(path) {
Ok(f) => {
file = f;
} }
return Some(position); Err(e) => {
eprintln!("[ERROR] On opening \"{}\": {}", filename, e);
return;
} }
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 3 {
println!("pngrip v0.1.3\nUSAGE: pngrip [DESTINATION] [FILES]...");
std::process::exit(0);
} }
// handle DESTINATION argument let mut file_bytes: Vec<u8> = Vec::new();
let mut destination_path = Path::new(&args[1]); match file.read_to_end(&mut file_bytes) {
match destination_path.exists() {
true => {
if !destination_path.is_dir() {
// destination exists, but is not a directory
destination_path = Path::new(".");
eprintln!("[ERROR] Provided destination path is not a directory ! Saving to current directory...");
}
}
false => {
// destination does not exist, create it
match std::fs::create_dir_all(&destination_path) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
destination_path = Path::new("."); eprintln!("[ERROR] On reading \"{}\": {}", filename, e);
eprintln!("[ERROR] Could not create destination directory: {}. Saving to current directory...", e); return;
}
} }
} }
}
// go through all files and try to rip all PNGs
for file_path_index in 0..args[2..].len() {
let file_path: &Path = Path::new(&args[file_path_index]);
print!("\n"); let mut image_count: u64 = 0;
if !file_path.exists() { let mut start_pos: usize = 0;
println!("[ERROR] \"{}\" does not exist", file_path.display()); let mut last_pos: usize = 0;
continue; let mut end_pos: usize = 0;
for i in 0..file_bytes.len()-iend_identifier.len() {
if i < file_bytes.len() - png_identifier.len() {
if file_bytes[i..i + png_identifier.len()] == png_identifier {
start_pos = i;
} }
// get file's metadata
let file_metadata: std::fs::Metadata;
match std::fs::metadata(file_path) {
Ok(metadata) => {
file_metadata = metadata;
} }
Err(error) => {
println!("[ERROR] Could not retrieve \"{}\"'s metadata: {}", file_path.display(), error);
continue;
}
}
// skip directories if file_bytes[i..i + iend_identifier.len()] == iend_identifier {
if file_metadata.is_dir() { end_pos = i + iend_identifier.len();
println!("[INFO] Skipping directory \"{}\"...", file_path.display());
continue;
} }
println!("[INFO] Working with \"{}\"...", file_path.display()); if start_pos < end_pos && start_pos != last_pos {
last_pos = start_pos;
image_count += 1;
let mut file_contents: Vec<u8> = Vec::with_capacity(file_metadata.len() as usize); let mut ripped_image_file;
let mut file_handle: std::fs::File; let ripped_image_filename = format!("{}_{}.png", filename, image_count);
match std::fs::File::open(file_path) { match std::fs::File::create(destination.join(&ripped_image_filename)) {
Ok(f_handle) => { Ok(f) => {
file_handle = f_handle; ripped_image_file = f;
} }
Err(error) => { Err(e) => {
println!("[ERROR] Could not open \"{}\": {}", file_path.display(), error); eprintln!("[ERROR] On creating \"{}\": {}", &ripped_image_filename, e);
continue; return;
} }
} }
match file_handle.read_to_end(&mut file_contents) { match ripped_image_file.write_all(&mut file_bytes[start_pos..end_pos]) {
Ok(_) => {} Ok(_) => {}
Err(error) => { Err(e) => {
println!("[ERROR] Error reading \"{}\": {}", file_path.display(), error); eprintln!("[ERROR] On writing to \"{}\": {}", ripped_image_filename, e);
} return;
} }
let mut positions: Vec<Position> = Vec::new();
let mut cursor_index: usize = 0;
while (cursor_index as u64) < file_metadata.len() {
match rip_png(&file_contents, cursor_index) {
Some(pos) => {
cursor_index = pos.end;
positions.push(pos);
} }
None => {
break;
} }
} }
println!("[INFO] Ripped {} images from \"{}\" in total", image_count, filename);
} }
let file_name: String; fn main() {
match file_path.file_name() { let args: Vec<String> = std::env::args().collect();
Some(fname) => { if args.len() < 3 {
file_name = String::from(fname.to_string_lossy()); println!("USAGE: pngrip [DESTINATION] [FILES]...");
std::process::exit(0);
} }
None => { // handle DESTINATION argument
eprintln!("[ERROR] Could not retrieve this file's name"); let mut destination = Path::new(&args[1]);
continue; match destination.exists() {
true => {
if !destination.is_dir() {
// destination exists, but is not a directory
destination = Path::new(".");
eprintln!("[ERROR] Provided destination path is not a directory ! Saving to current directory...");
} }
} }
false => {
for position_index in 0..positions.len() { // destination does not exist, create it
let output_file_name: String = format!("{}_{}.png", file_name, position_index); match std::fs::create_dir_all(&destination) {
let mut output_file: std::fs::File; Ok(_) => {}
match std::fs::File::create(destination_path.join(&output_file_name)) { Err(e) => {
Ok(f) => { destination = Path::new(".");
output_file = f; eprintln!("[ERROR] Could not create destination directory: {}. Saving to current directory...", e);
} }
Err(error) => {
eprintln!("[ERROR] Error creating output file: {}", error);
continue;
} }
} }
match output_file.write(&file_contents[positions[position_index].start..positions[position_index].end]) {
Ok(_) => {
println!("[INFO] Outputted \"{}\"", output_file_name);
} }
Err(error) => {
eprintln!("[ERROR] Could not write PNG to the output file: {}", error); // go through all files and try to rip all PNGs
for file_to_check in &args[2..] {
let path = Path::new(file_to_check);
if !path.exists() {
eprintln!("[ERROR] \"{}\" does not exist", file_to_check);
continue; continue;
} }
}
} rip_png(path, destination);
} }
} }
Loading…
Cancel
Save