Generate a PDF out of the images

This commit is contained in:
Alexis Métaireau 2025-04-04 01:44:32 +02:00
parent b64dd9a32c
commit 68981092ad
No known key found for this signature in database
GPG key ID: 1C21B876828E5FF2
2 changed files with 70 additions and 25 deletions

View file

@ -13,6 +13,8 @@ calamine = "0.26.1"
chrono = "0.4.40"
image = "0.25.6"
imageproc = "0.25.0"
printpdf = { version = "0.8.2", features = ["png"] }
serde = "1.0.217"
small_uid = "0.2.4"
structopt = "0.3.26"
tempfile = "3.19.1"

93
main.rs
View file

@ -1,13 +1,19 @@
use calamine::{open_workbook, Data, Reader, Xlsx};
use printpdf::image::RawImage;
use printpdf::{
Mm, Op, PdfDocument, PdfPage, PdfSaveOptions, PdfWarnMsg, RawImageData, RawImageFormat,
XObjectTransform,
};
use structopt::StructOpt;
use ab_glyph::{FontRef, PxScale};
use image::{ImageBuffer, Rgba};
use image::{EncodableLayout, ImageBuffer, Rgba};
use imageproc::drawing::draw_text_mut;
use small_uid::SmallUid;
use std::path::{Path, PathBuf};
// A4 dimensions
const A4_WIDTH: f32 = 210.0;
const A4_HEIGHT: f32 = 297.0;
// Configuration for the label
const DPI: f32 = 300.0;
const MM_TO_PX: f32 = DPI / 25.4;
@ -98,24 +104,13 @@ fn parse_xlsx(delivery_week_filter: &str) -> Result<Vec<Record>, Box<dyn std::er
Ok(records)
}
// The label looks like this:
//
// Tomate (Solanum lycopersicum) (species) /^\
// Variété: San Marzano (variety) / j \
// / ard \
// / iflore\
// ---------
// SEMAINE DE LIVRAISON: 22
//
// 123 Allée des Récoltes
// Tél: Téléphone.
//
fn generate_label(output_dir: &String, record: Record) -> PathBuf {
fn generate_label(record: Record) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
let font_data = include_bytes!("./assets/DejaVuSans.ttf");
let font = FontRef::try_from_slice(font_data).unwrap();
let logo = image::open("./assets/logo.png").unwrap();
let mut label = ImageBuffer::new(LABEL_WIDTH as u32, LABEL_HEIGHT as u32);
let mut label: ImageBuffer<Rgba<u8>, Vec<u8>> =
ImageBuffer::new(LABEL_WIDTH as u32, LABEL_HEIGHT as u32);
// Fill in the background
for pixel in label.pixels_mut() {
@ -167,13 +162,62 @@ fn generate_label(output_dir: &String, record: Record) -> PathBuf {
&font,
&species_varieties,
);
return label;
}
// Save the label
fn combine_labels(
labels: &[ImageBuffer<Rgba<u8>, Vec<u8>>],
output_dir: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let labels_per_page = (A4_HEIGHT / LABEL_HEIGHT).floor() as usize;
let output_path = Path::new(output_dir).join(format!("label_{}.png", SmallUid::new()));
label.save(output_path.clone()).unwrap();
// Create a new PDF document
let mut doc = PdfDocument::new("Labels Document");
let mut pages = Vec::new();
let mut warnings: Vec<PdfWarnMsg> = Vec::new();
return output_path;
// Group labels by page
for chunk in labels.chunks(labels_per_page) {
let mut page_contents = Vec::new();
let mut y_position = A4_HEIGHT - LABEL_HEIGHT;
for label in chunk {
// let image = RawImage::decode_from_bytes(label.as_raw(), &mut Vec::new()).unwrap();
// let bytes = include_bytes!("output/label_GV-Ek9pYRis.png");
let pixels = label.clone().into_raw();
let image = RawImage {
pixels: RawImageData::U8(pixels),
width: LABEL_WIDTH as usize,
height: LABEL_HEIGHT as usize,
data_format: RawImageFormat::RGBA8,
tag: Vec::new(),
};
let image_id = doc.add_image(&image);
// Add image to page at current y position
page_contents.push(Op::UseXobject {
id: image_id,
transform: XObjectTransform::default(),
});
// Move y position up for next label
y_position -= LABEL_HEIGHT;
}
// Create page and add to pages list
let page = PdfPage::new(Mm(A4_WIDTH), Mm(A4_HEIGHT), page_contents);
pages.push(page);
}
// Add all pages to document and save
let pdf_bytes: Vec<u8> = doc
.with_pages(pages)
.save(&PdfSaveOptions::default(), &mut warnings);
// Write PDF bytes to file
std::fs::write("test.pdf", pdf_bytes)?;
Ok(())
}
#[derive(StructOpt)]
@ -190,10 +234,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let week_number = "s".to_owned() + &opts.week;
let records = parse_xlsx(&week_number)?;
let mut labels = Vec::new();
for record in records {
let path = generate_label(&opts.output_dir, record);
println!("{}", path.into_os_string().into_string().unwrap())
labels.push(generate_label(record));
}
Ok(())
combine_labels(&labels, &opts.output_dir)
}