1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
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<T: std::fmt::Binary>(num: T, size: usize) -> Vec<u8> {
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<P: AsRef<Path>>(path: P) -> Result<Document, Error> {
Document::load(path).map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
#[cfg(feature = "async")]
fn load_pdf<P: AsRef<Path>>(path: P) -> Result<Document, Error> {
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<String> = 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();
}
|