use crate::types::{Barcode, BarcodeModules, QuickCodesError, Result};
use image::{ImageBuffer, Rgb, RgbImage};
use std::io::Cursor;
pub fn export_png(barcode: &Barcode) -> Result<Vec<u8>> {
match &barcode.modules {
BarcodeModules::Linear(pattern) => export_linear_png(barcode, pattern),
BarcodeModules::Matrix(matrix) => export_matrix_png(barcode, matrix),
}
}
fn export_linear_png(barcode: &Barcode, pattern: &[bool]) -> Result<Vec<u8>> {
let module_width = 2u32; let height = 60u32; let margin = barcode.config.margin;
let total_width = (pattern.len() as u32 * module_width) + (2 * margin);
let total_height = height + (2 * margin);
let mut img: RgbImage = ImageBuffer::new(total_width, total_height);
for pixel in img.pixels_mut() {
*pixel = Rgb([255, 255, 255]);
}
let mut x = margin;
for &is_black in pattern {
if is_black {
for y in margin..(margin + height) {
for bar_x in x..(x + module_width) {
if bar_x < total_width && y < total_height {
img.put_pixel(bar_x, y, Rgb([0, 0, 0]));
}
}
}
}
x += module_width;
}
let mut buffer = Vec::new();
let mut cursor = Cursor::new(&mut buffer);
img.write_to(&mut cursor, image::ImageFormat::Png)
.map_err(|e| QuickCodesError::ExportError(format!("PNG export failed: {}", e)))?;
Ok(buffer)
}
fn export_matrix_png(barcode: &Barcode, matrix: &[Vec<bool>]) -> Result<Vec<u8>> {
if matrix.is_empty() || matrix[0].is_empty() {
return Err(QuickCodesError::ExportError("Matrix is empty".to_string()));
}
let module_size = 4u32; let margin = barcode.config.margin;
let matrix_width = matrix[0].len() as u32 * module_size;
let matrix_height = matrix.len() as u32 * module_size;
let total_width = matrix_width + (2 * margin);
let total_height = matrix_height + (2 * margin);
let mut img: RgbImage = ImageBuffer::new(total_width, total_height);
for pixel in img.pixels_mut() {
*pixel = Rgb([255, 255, 255]);
}
for (row, row_data) in matrix.iter().enumerate() {
for (col, &is_black) in row_data.iter().enumerate() {
if is_black {
let start_x = margin + (col as u32 * module_size);
let start_y = margin + (row as u32 * module_size);
for y in start_y..(start_y + module_size) {
for x in start_x..(start_x + module_size) {
if x < total_width && y < total_height {
img.put_pixel(x, y, Rgb([0, 0, 0]));
}
}
}
}
}
}
let mut buffer = Vec::new();
let mut cursor = Cursor::new(&mut buffer);
img.write_to(&mut cursor, image::ImageFormat::Png)
.map_err(|e| QuickCodesError::ExportError(format!("PNG export failed: {}", e)))?;
Ok(buffer)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generators::ean13::generate_ean13;
use crate::generators::qr::generate_qr;
#[test]
fn test_png_export_qr() {
let barcode = generate_qr("Test").unwrap();
let png_data = export_png(&barcode);
assert!(png_data.is_ok());
let data = png_data.unwrap();
assert!(!data.is_empty());
assert_eq!(&data[0..8], &[137, 80, 78, 71, 13, 10, 26, 10]);
}
#[test]
fn test_png_export_ean13() {
let barcode = generate_ean13("123456789012").unwrap();
let png_data = export_png(&barcode);
assert!(png_data.is_ok());
let data = png_data.unwrap();
assert!(!data.is_empty());
assert_eq!(&data[0..8], &[137, 80, 78, 71, 13, 10, 26, 10]);
}
}