use super::bit_matrix::BitMatrix;
use image::{Rgba, RgbaImage};
static L_PATTERNS: [[u8; 7]; 10] = [
[0, 0, 0, 1, 1, 0, 1],
[0, 0, 1, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1, 1],
[0, 1, 1, 1, 1, 0, 1],
[0, 1, 0, 0, 0, 1, 1],
[0, 1, 1, 0, 0, 0, 1],
[0, 1, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 0, 1, 1],
[0, 1, 1, 0, 1, 1, 1],
[0, 0, 0, 1, 0, 1, 1],
];
static G_PATTERNS: [[u8; 7]; 10] = [
[0, 1, 0, 0, 1, 1, 1],
[0, 1, 1, 0, 0, 1, 1],
[0, 0, 1, 1, 0, 1, 1],
[0, 1, 0, 0, 0, 0, 1],
[0, 0, 1, 1, 1, 0, 1],
[0, 1, 1, 1, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 0, 1],
[0, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 1, 1],
];
static R_PATTERNS: [[u8; 7]; 10] = [
[1, 1, 1, 0, 0, 1, 0],
[1, 1, 0, 0, 1, 1, 0],
[1, 1, 0, 1, 1, 0, 0],
[1, 0, 0, 0, 0, 1, 0],
[1, 0, 1, 1, 1, 0, 0],
[1, 0, 0, 1, 1, 1, 0],
[1, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 1, 0, 0],
[1, 0, 0, 1, 0, 0, 0],
[1, 1, 1, 0, 1, 0, 0],
];
static FIRST_DIGIT_PATTERNS: [[u8; 6]; 10] = [
[0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 1], [0, 0, 1, 1, 0, 1], [0, 0, 1, 1, 1, 0], [0, 1, 0, 0, 1, 1], [0, 1, 1, 0, 0, 1], [0, 1, 1, 1, 0, 0], [0, 1, 0, 1, 0, 1], [0, 1, 0, 1, 1, 0], [0, 1, 1, 0, 1, 0], ];
fn calculate_checksum(digits: &[u8; 12]) -> u8 {
let mut sum = 0u32;
for (i, &d) in digits.iter().enumerate() {
if i % 2 == 0 {
sum += d as u32;
} else {
sum += d as u32 * 3;
}
}
((10 - (sum % 10)) % 10) as u8
}
pub fn encode(content: &str, height: i32, bar_width: i32) -> Result<RgbaImage, String> {
let digits: Vec<u8> = content
.chars()
.filter(|c| c.is_ascii_digit())
.map(|c| c as u8 - b'0')
.collect();
if digits.len() < 12 {
return Err(format!(
"EAN-13: need at least 12 digits, got {}",
digits.len()
));
}
let mut d12 = [0u8; 12];
d12.copy_from_slice(&digits[..12]);
let check = calculate_checksum(&d12);
let first_digit = d12[0] as usize;
let parity_pattern = &FIRST_DIGIT_PATTERNS[first_digit];
let module_count = 95;
let total_width = module_count;
let mut bm = BitMatrix::new(total_width, 1);
let mut pos = 0;
bm.set(pos, 0, true);
pos += 1;
pos += 1; bm.set(pos, 0, true);
pos += 1;
for i in 0..6 {
let digit = d12[i + 1] as usize;
let pattern = if parity_pattern[i] == 0 {
&L_PATTERNS[digit]
} else {
&G_PATTERNS[digit]
};
for &bit in pattern {
if bit == 1 {
bm.set(pos, 0, true);
}
pos += 1;
}
}
pos += 1;
bm.set(pos, 0, true);
pos += 1;
pos += 1;
bm.set(pos, 0, true);
pos += 1;
pos += 1;
let right_digits = [d12[7], d12[8], d12[9], d12[10], d12[11], check];
for &digit in &right_digits {
let pattern = &R_PATTERNS[digit as usize];
for &bit in pattern {
if bit == 1 {
bm.set(pos, 0, true);
}
pos += 1;
}
}
bm.set(pos, 0, true);
pos += 1;
pos += 1;
bm.set(pos, 0, true);
let bw = bar_width.max(1) as usize;
let h = height.max(1) as usize;
let guard_extension = (5 * bw).max((h as f32 * 0.12).ceil() as usize).max(6);
let total_height = h + guard_extension;
let is_guard_module = |m: usize| -> bool { m <= 2 || (45..=49).contains(&m) || m >= 92 };
let iw = module_count * bw;
let black = Rgba([0, 0, 0, 255]);
let mut img = RgbaImage::from_pixel(iw as u32, total_height as u32, Rgba([0, 0, 0, 0]));
for m in 0..module_count {
if bm.get(m, 0) {
let bar_h = if is_guard_module(m) { total_height } else { h };
for b in 0..bw {
let px = (m * bw + b) as u32;
for py in 0..bar_h as u32 {
if px < img.width() {
img.put_pixel(px, py, black);
}
}
}
}
}
Ok(img)
}