89 lines
2.3 KiB
Rust
89 lines
2.3 KiB
Rust
use image::{ImageBuffer, Luma};
|
|
use proc_macro::{Span, TokenStream};
|
|
use quote::quote;
|
|
use regex::Regex;
|
|
use syn::parse::Parse;
|
|
|
|
fn remove_non_alphanumeric(input: &str) -> String {
|
|
let re = Regex::new(r"[^a-zA-Z0-9_]+").unwrap();
|
|
re.replace_all(input, "").to_string()
|
|
}
|
|
|
|
fn to_format(img: ImageBuffer<Luma<u8>, Vec<u8>>, width: usize, height: usize) -> Vec<u8> {
|
|
let mut output = Vec::new();
|
|
|
|
let mut bit: u8 = 0;
|
|
let mut byte: u8 = 0;
|
|
for y in 0..height {
|
|
for x in 0..width {
|
|
let pixel = img.get_pixel(x as u32, y as u32)[0];
|
|
if pixel >= 127 {
|
|
byte |= 1 << bit;
|
|
}
|
|
bit += 1;
|
|
if bit == 8 {
|
|
output.push(byte);
|
|
byte = 0;
|
|
bit = 0;
|
|
}
|
|
}
|
|
}
|
|
if bit != 0 {
|
|
output.push(byte);
|
|
}
|
|
output
|
|
}
|
|
|
|
fn path_to_image(path: &str) -> (Vec<u8>, usize, usize) {
|
|
let img = match image::open(path) {
|
|
Ok(img) => img.to_luma8(),
|
|
Err(e) => panic!("failed to open image {}: {}", path, e),
|
|
};
|
|
|
|
let width = img.width() as usize;
|
|
let height = img.height() as usize;
|
|
|
|
let bytes = to_format(img, width, height);
|
|
|
|
(bytes, width, height)
|
|
}
|
|
|
|
struct ParsedArgs {
|
|
path: String,
|
|
}
|
|
|
|
impl Parse for ParsedArgs {
|
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
|
let path: syn::LitStr = input.parse()?;
|
|
let path = path.value();
|
|
Ok(ParsedArgs { path })
|
|
}
|
|
}
|
|
|
|
pub fn parse_image(
|
|
input: TokenStream,
|
|
) -> Result<(u8, u8, usize, Vec<proc_macro2::TokenStream>), syn::Error> {
|
|
// parse the input into a comma separated list of arguments
|
|
let parsed_args = syn::parse::<ParsedArgs>(input)?;
|
|
// let parsed_args = parse_macro_input!(input as ParsedArgs);
|
|
let (bytes, width, height) = path_to_image(&parsed_args.path);
|
|
|
|
let width = width as u8;
|
|
let height = height as u8;
|
|
|
|
let byte_array = bytes.as_slice();
|
|
let byte_count = byte_array.len();
|
|
|
|
let byte_tokens = bytes.iter().map(|b| quote! { #b }).collect::<Vec<_>>();
|
|
Ok((width, height, byte_count, byte_tokens))
|
|
}
|
|
|
|
pub fn include_bitmap_image_impl(input: TokenStream) -> TokenStream {
|
|
let (_, _, _, byte_tokens) = parse_image(input).unwrap();
|
|
|
|
let output = quote! {
|
|
[#(#byte_tokens),*]
|
|
};
|
|
output.into()
|
|
}
|