Initial commit
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/target
 | 
				
			||||||
							
								
								
									
										1196
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1196
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "yabinary"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					clap = { version = "4.5.9", features = ["derive"] }
 | 
				
			||||||
 | 
					image = "0.25.2"
 | 
				
			||||||
							
								
								
									
										107
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					use clap::{Parser, ValueEnum};
 | 
				
			||||||
 | 
					use image::ImageReader;
 | 
				
			||||||
 | 
					use std::fs::File;
 | 
				
			||||||
 | 
					use std::io::{Read, Write};
 | 
				
			||||||
 | 
					use std::path::PathBuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const WHITE: u8 = 0x88;
 | 
				
			||||||
 | 
					const BLACK: u8 = 0xCC;
 | 
				
			||||||
 | 
					const SCREEN_WIDTH: usize = 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(ValueEnum, Clone, Copy)]
 | 
				
			||||||
 | 
					enum Color {
 | 
				
			||||||
 | 
					    White,
 | 
				
			||||||
 | 
					    Black,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Color {
 | 
				
			||||||
 | 
					    fn as_bytes(&self) -> u8 {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Color::White => WHITE,
 | 
				
			||||||
 | 
					            Color::Black => BLACK,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl std::fmt::Display for Color {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::White => f.write_str("white"),
 | 
				
			||||||
 | 
					            Self::Black => f.write_str("black"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Parser)]
 | 
				
			||||||
 | 
					struct Cli {
 | 
				
			||||||
 | 
					    #[arg(long, requires_all=["header_lines"])]
 | 
				
			||||||
 | 
					    header_from: Option<PathBuf>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    header_lines: Option<usize>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    image: PathBuf,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[arg(long, requires_all=["footer_lines"])]
 | 
				
			||||||
 | 
					    footer_from: Option<PathBuf>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    footer_lines: Option<usize>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[arg(long, default_value_t = Color::White)]
 | 
				
			||||||
 | 
					    background: Color,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output: PathBuf,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
				
			||||||
 | 
					    let c = Cli::parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let img = ImageReader::open(c.image)?.decode()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if SCREEN_WIDTH < img.width() as usize {
 | 
				
			||||||
 | 
					        println!(
 | 
				
			||||||
 | 
					            "WARN: {} pixels are ignored",
 | 
				
			||||||
 | 
					            img.width() as usize - SCREEN_WIDTH
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut output = File::create(&c.output)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if let Some(header_path) = c.header_from {
 | 
				
			||||||
 | 
					        let mut buffer = vec![0; c.header_lines.unwrap() * SCREEN_WIDTH];
 | 
				
			||||||
 | 
					        File::open(header_path)?.read_exact(&mut buffer)?;
 | 
				
			||||||
 | 
					        output.write(&buffer)?;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for row in img.to_rgba8().rows() {
 | 
				
			||||||
 | 
					        let buffer: Vec<_> = (0..SCREEN_WIDTH)
 | 
				
			||||||
 | 
					            .into_iter()
 | 
				
			||||||
 | 
					            .zip(
 | 
				
			||||||
 | 
					                row.into_iter()
 | 
				
			||||||
 | 
					                    .map(|v| {
 | 
				
			||||||
 | 
					                        let brightness =
 | 
				
			||||||
 | 
					                            (v[0] as f32 / 256.0 + v[1] as f32 / 256.0 + v[2] as f32 / 256.0) / 3.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if brightness > 0.2 {
 | 
				
			||||||
 | 
					                            Color::White
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            Color::Black
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .chain(std::iter::repeat(c.background)),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .map(|(_, color)| color.as_bytes())
 | 
				
			||||||
 | 
					            .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        output.write(&buffer)?;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if let Some(footer_path) = c.footer_from {
 | 
				
			||||||
 | 
					        let mut buffer = vec![0; c.footer_lines.unwrap() * SCREEN_WIDTH];
 | 
				
			||||||
 | 
					        File::open(footer_path)?.read_exact(&mut buffer)?;
 | 
				
			||||||
 | 
					        output.write(&buffer)?;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user