use lopdf::xobject; use lopdf::Document; use std::fmt::Write; use std::io::{Error, ErrorKind}; use std::path::Path; use std::str::FromStr; #[cfg(feature = "async")] use tokio::runtime::Builder; fn convert_number_to_bits(num: T, size: usize) -> Vec { let bin = format!("{:b}", num); let pad = "0".repeat(size - bin.len()); let mut bytes = (pad + &bin).into_bytes(); bytes.reverse(); bytes } fn generate_barcode(page: u32, code: u16) -> Vec<(f64, f64, f64, f64, u8)> { assert!(page > 0 && page <= 255, "Page number should within range: 1-255"); assert!(code <= 511, "Bar code should within range: 0-511"); let page_bits = convert_number_to_bits(page, 8); let code_bits = convert_number_to_bits(code, 9); let mut rects = vec![]; let mut x = 0.0; let y = 0.0; let w = 9.0; let h = 10.0; { let mut add_flag = |w, bit| { rects.push((x, y, w, h, bit)); x += w; }; add_flag(w, b'0'); for bit in page_bits { add_flag(w, bit); } add_flag(w, code_bits[0]); add_flag(6.53, b'0'); add_flag(w, code_bits[1]); add_flag(w, code_bits[2]); add_flag(w, code_bits[3]); add_flag(w, code_bits[4]); add_flag(w, b'1'); add_flag(w, b'0'); add_flag(w, code_bits[5]); add_flag(w, code_bits[6]); add_flag(w, code_bits[7]); add_flag(w, code_bits[8]); } rects } fn generate_operations(rects: Vec<(f64, f64, f64, f64, u8)>) -> String { let mut operations = String::new(); let mut current_color = b'\0'; for (x, y, w, h, bit) in rects { if bit != current_color { operations.push_str(match bit { b'0' => "1 1 1 rg\n", b'1' => "0 0 0 rg\n", _ => "\n", }); current_color = bit; } write!(&mut operations, "{} {} {} {} re\nf\n", x, y, w, h).unwrap(); } operations } #[cfg(not(feature = "async"))] fn load_pdf>(path: P) -> Result { Document::load(path).map_err(|e| Error::new(ErrorKind::Other, e.to_string())) } #[cfg(feature = "async")] fn load_pdf>(path: P) -> Result { Ok(Builder::new_current_thread().build().unwrap().block_on(async move { Document::load(path) .await .map_err(|e| Error::new(ErrorKind::Other, e.to_string())) })?) } #[allow(non_upper_case_globals)] const mm2pt: f32 = 2.834; fn main() { let args: Vec = std::env::args().collect(); assert!(args.len() == 4, "Not enough arguments: pdf_file bar_code output_file"); let pdf_file = &args[1]; let code = u16::from_str(&args[2]).expect("error in parsing code argument"); let output_file = &args[3]; let mut doc = load_pdf(pdf_file).unwrap(); for (page_number, page_id) in doc.get_pages() { let operations = generate_operations(generate_barcode(page_number, code)); let barcode = xobject::form( vec![0.0, 0.0, 595.0 - 12.44 * mm2pt * 2.0, 10.0 * mm2pt], vec![mm2pt, 0.0, 0.0, mm2pt, 12.44 * mm2pt, 842.0 - 14.53 * mm2pt], operations.as_bytes().to_vec(), ); doc.insert_form_object(page_id, barcode).unwrap(); } // Store file in current working directory. doc.save(output_file).unwrap(); }