So as to not lose my work

This commit is contained in:
Joshua Holmer 2015-12-16 08:01:05 -05:00
commit 7d3a601686
5 changed files with 151 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
target
Cargo.lock

8
Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "optipng"
version = "2.0.0"
authors = ["Joshua Holmer <jholmer.in@gmail.com>"]
[dependencies]
flate2 = "0.2"
png = "0.4"

5
src/compress.rs Normal file
View file

@ -0,0 +1,5 @@
extern crate png;
pub fn compress(idat: Vec<u8>, f: u8, i: u8, zc: u8, zm: u8, zs: u8, zw: u32) -> Vec<u8> {
}

91
src/lib.rs Normal file
View file

@ -0,0 +1,91 @@
extern crate png;
use std::path::Path;
use std::fs::File;
use std::io;
use std::collections::HashSet;
mod compress;
pub struct Options<'a> {
pub backup: bool,
pub out_file: &'a Path,
pub fix_errors: bool,
pub force: bool,
pub clobber: bool,
pub create: bool,
pub preserve_attrs: bool,
pub verbosity: Option<u8>,
pub f: HashSet<u8>,
pub i: u8,
pub zc: HashSet<u8>,
pub zm: HashSet<u8>,
pub zs: HashSet<u8>,
pub zw: u32,
pub bit_depth_reduction: bool,
pub color_type_reduction: bool,
pub palette_reduction: bool,
pub idat_recoding: bool,
pub idat_paranoia: bool,
}
// Processing: /Users/holmerj/Downloads/renpy-6.99.7-sdk/doc/_images/frame_example.png
// 579x354 pixels, PNG format
// 3x8 bits/pixel, RGB
// IDAT size = 45711 bytes
// file size = 45881 bytes
// Trying: 8 combinations
// Output:
// IDAT size = 45711 bytes (no change)
// file size = 45821 bytes (60 bytes = 0.13% decrease)
pub fn optimize(filepath: &Path, opts: Options) -> Result<(), io::Error> {
// Decode PNG from file
println!("Processing: {}", filepath.to_str().unwrap());
let in_file = try!(File::open(filepath));
let decoder = png::Decoder::new(in_file);
let (info, mut reader) = try!(decoder.read_info());
let mut img_buf = vec![0; info.buffer_size()];
try!(reader.next_frame(&mut img_buf));
// Read and print
let info = reader.info();
let (width, height) = info.size();
let depth = (info.bytes_per_pixel(), info.bits_per_pixel() / info.bytes_per_pixel());
// FIXME
let idat_current_size = img_buf.len();
let file_current_size = filepath.metadata().unwrap().len();
if opts.verbosity.is_some() {
println!("{}x{} pixels, PNG format", width, height);
if let Some(palette) = info.palette.clone() {
println!("{} bits/pixel, {} colors in palette", depth.1, palette.len() / 3);
} else {
println!("{}x{} bits/pixel, {:?}", depth.0, depth.1, info.color_type);
}
println!("IDAT size = {} bytes", idat_current_size);
println!("File size = {} bytes", file_current_size);
}
// TODO: Bit depth/palette reduction
// Go through selected permutations and determine the best
if opts.idat_recoding {
let combinations = opts.f.len() * opts.zc.len() * opts.zm.len() * opts.zs.len();
println!("Trying: {} combinations", combinations);
// TODO: Multithreading
for f in &opts.f {
for zc in &opts.zc {
for zm in &opts.zm {
for zs in &opts.zs {
// TODO: Test compressions
}
}
}
}
}
// TODO: Backup before writing?
// TODO: Write output file
Ok(())
}

45
src/main.rs Normal file
View file

@ -0,0 +1,45 @@
extern crate optipng;
use std::env;
use std::path::Path;
use std::collections::HashSet;
fn main() {
// TODO: Handle wildcards
let filename = env::args().skip(1).next().unwrap();
let infile = Path::new(&filename);
let mut f = HashSet::new();
f.insert(0);
f.insert(5);
let mut zc = HashSet::new();
zc.insert(9);
let mut zm = HashSet::new();
zm.insert(9);
let mut zs = HashSet::new();
for i in 0..4 {
zs.insert(i);
}
let default_opts = optipng::Options {
backup: false,
out_file: infile,
fix_errors: false,
force: false,
clobber: true,
create: true,
preserve_attrs: false,
verbosity: Some(0),
f: f,
i: 0,
zc: zc,
zm: zm,
zs: zs,
zw: 4096,
bit_depth_reduction: true,
color_type_reduction: true,
palette_reduction: true,
idat_recoding: true,
idat_paranoia: false,
};
optipng::optimize(infile, default_opts);
}