File: add_barcode.rs

package info (click to toggle)
rust-lopdf 0.34.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 7,620 kB
  • sloc: makefile: 2
file content (106 lines) | stat: -rw-r--r-- 3,438 bytes parent folder | download | duplicates (2)
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();
}