Skip to content

Commit

Permalink
Add bitdepth parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
teaearlgraycold committed Sep 3, 2017
1 parent f570f83 commit a9cb002
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "binimage"
version = "0.1.0"
version = "0.1.1"
authors = ["teaearlgraycold <supacoofoo@gmail.com>"]
repository = "https://github.com/teaearlgraycold/binimage"
license = "MIT"
Expand Down
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,25 @@ Build with cargo: `cargo build --release`

```
Usage:
binimage <input> <output> [--width=<pixels>]
binimage <input> <output> [--height=<pixels>]
binimage <input> <output> [--width=<pixels>] [--bitdepth=<bits>]
binimage <input> <output> [--height=<pixels>] [--bitdepth=<bits>]
binimage (-h | --help)
Options:
-h --help Show this screen.
--width=<pixels> Specify output image width (default is sqrt of the file size).
--height=<pixels>
-h --help Show this screen.
--width=<pixels> Specify output image width. Default is sqrt of the file size.
--height=<pixels> Specify output image height. Default is sqrt of the file size.
--bitdepth=<bits> Number of bits per pixel. Default is 24. Less than 12 is grayscale.
Valid values: 1, 2, 4, 8, 12, 24
```

### Example
### Examples

Running `binimage` on an Atari ROM produces interesting results. This is a
cropped output image.

![binimage ran on MarioBros](examples/mario_bros.png)

This is the image produced when `binimage` is ran on its own binary.

![binimage ran on itself](example.png)
![binimage ran on itself](examples/binimage.png)
File renamed without changes
Binary file added examples/mario_bros.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 43 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,34 @@ use std::io::Read;
use std::fs::File;
use std::path::Path;

use image::ColorType;
use docopt::Docopt;

const BITS_PER_BYTE: f32 = 8.0;
const USAGE: &'static str = "
binimage
Create an image from the binary data of a file.
Usage:
binimage <input> <output> [--width=<pixels>]
binimage <input> <output> [--height=<pixels>]
binimage <input> <output> [--width=<pixels>] [--bitdepth=<bits>]
binimage <input> <output> [--height=<pixels>] [--bitdepth=<bits>]
binimage (-h | --help)
Options:
-h --help Show this screen.
--width=<pixels> Specify output image width (default is sqrt of the file size).
--height=<pixels>
-h --help Show this screen.
--width=<pixels> Specify output image width. Default is sqrt of the file size.
--height=<pixels> Specify output image height. Default is sqrt of the file size.
--bitdepth=<bits> Number of bits per pixel. Default is 24. Less than 12 is grayscale.
Valid values: 1, 2, 4, 8, 12, 24
";

#[derive(Debug, Deserialize)]
struct Args {
arg_input: String,
arg_output: String,
flag_width: u32,
flag_height: u32
flag_height: u32,
flag_bitdepth: u8
}

fn main() {
Expand All @@ -41,10 +46,30 @@ fn main() {
render_file(args);
}

fn colortype_from_bitdepth(bitdepth: u8) -> ColorType {
match bitdepth {
0 => image::RGB(8),
1 => image::Gray(1),
2 => image::Gray(2),
4 => image::Gray(4),
8 => image::Gray(8),
12 => image::RGB(4),
24 => image::RGB(8),
_ => panic!("Invalid bit-depth: {}", bitdepth)
}
}

fn bits_per_pixel(c: ColorType) -> u32 {
match c {
ColorType::Gray(n) => n as u32,
ColorType::RGB(n) => 3 * n as u32,
_ => panic!("Unsupported ColorType")
}
}

// The shape to give an image from its file size
fn image_shape(buffer_size: usize, arg_width: u32, arg_height: u32) -> (u32, u32) {
let arg_size = (arg_width, arg_height);
let num_pixels = (buffer_size as f32) / 3.0;
fn image_shape(buffer_size: usize, arg_size: (u32, u32), colortype: ColorType) -> (u32, u32) {
let num_pixels = ((buffer_size as f32) * BITS_PER_BYTE / bits_per_pixel(colortype) as f32).ceil();

if arg_size.0 > num_pixels as u32 || arg_size.1 > num_pixels as u32 {
panic!("Neither height nor width can be greater than the file size / 3.");
Expand All @@ -69,9 +94,10 @@ fn image_shape(buffer_size: usize, arg_width: u32, arg_height: u32) -> (u32, u32
}

// The number of additional bytes necessary to match the buffer size and image size (in pixels)
fn bytes_to_add(buffer_size: usize, dims: (u32, u32)) -> u32 {
let bytes_required = dims.0 * dims.1 * 3; // 3 bytes per pixel
return bytes_required - (buffer_size as u32);
fn bytes_to_add(buffer_size: usize, dims: (u32, u32), colortype: ColorType) -> u32 {
let bits_required = dims.0 * dims.1 * bits_per_pixel(colortype);
let bytes_required = (bits_required as f32 / BITS_PER_BYTE).ceil() as u32;
return bytes_required - buffer_size as u32;
}

fn render_file(args: Args) {
Expand All @@ -90,14 +116,16 @@ fn render_file(args: Args) {
Err(why) => panic!("Couldn't read {}: {}", input_path.display(), why.description())
};

let dims = image_shape(size, args.flag_width, args.flag_height);
let size_diff = bytes_to_add(size, dims);
let colortype = colortype_from_bitdepth(args.flag_bitdepth);
let arg_size = (args.flag_width, args.flag_height);
let dims = image_shape(size, arg_size, colortype);
let size_diff = bytes_to_add(size, dims, colortype);

// Add any extra bytes onto the end as black pixels
for _ in 0..size_diff {
buffer.push(0);
}

// Write image
image::save_buffer(&output_path, &buffer, dims.0, dims.1, image::RGB(8)).unwrap();
image::save_buffer(&output_path, &buffer, dims.0, dims.1, colortype).unwrap();
}

0 comments on commit a9cb002

Please sign in to comment.