mirror of
https://framagit.org/almet/jardiflore.git
synced 2025-04-28 20:12:38 +02:00
Generate a PDF out of the images
This commit is contained in:
parent
b64dd9a32c
commit
68981092ad
2 changed files with 70 additions and 25 deletions
|
@ -13,6 +13,8 @@ calamine = "0.26.1"
|
||||||
chrono = "0.4.40"
|
chrono = "0.4.40"
|
||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
imageproc = "0.25.0"
|
imageproc = "0.25.0"
|
||||||
|
printpdf = { version = "0.8.2", features = ["png"] }
|
||||||
serde = "1.0.217"
|
serde = "1.0.217"
|
||||||
small_uid = "0.2.4"
|
small_uid = "0.2.4"
|
||||||
structopt = "0.3.26"
|
structopt = "0.3.26"
|
||||||
|
tempfile = "3.19.1"
|
||||||
|
|
93
main.rs
93
main.rs
|
@ -1,13 +1,19 @@
|
||||||
use calamine::{open_workbook, Data, Reader, Xlsx};
|
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 structopt::StructOpt;
|
||||||
|
|
||||||
use ab_glyph::{FontRef, PxScale};
|
use ab_glyph::{FontRef, PxScale};
|
||||||
use image::{ImageBuffer, Rgba};
|
use image::{EncodableLayout, ImageBuffer, Rgba};
|
||||||
use imageproc::drawing::draw_text_mut;
|
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
|
// Configuration for the label
|
||||||
const DPI: f32 = 300.0;
|
const DPI: f32 = 300.0;
|
||||||
const MM_TO_PX: f32 = DPI / 25.4;
|
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)
|
Ok(records)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The label looks like this:
|
fn generate_label(record: Record) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
|
||||||
//
|
|
||||||
// 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 {
|
|
||||||
let font_data = include_bytes!("./assets/DejaVuSans.ttf");
|
let font_data = include_bytes!("./assets/DejaVuSans.ttf");
|
||||||
let font = FontRef::try_from_slice(font_data).unwrap();
|
let font = FontRef::try_from_slice(font_data).unwrap();
|
||||||
let logo = image::open("./assets/logo.png").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
|
// Fill in the background
|
||||||
for pixel in label.pixels_mut() {
|
for pixel in label.pixels_mut() {
|
||||||
|
@ -167,13 +162,62 @@ fn generate_label(output_dir: &String, record: Record) -> PathBuf {
|
||||||
&font,
|
&font,
|
||||||
&species_varieties,
|
&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()));
|
// Create a new PDF document
|
||||||
label.save(output_path.clone()).unwrap();
|
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)]
|
#[derive(StructOpt)]
|
||||||
|
@ -190,10 +234,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let week_number = "s".to_owned() + &opts.week;
|
let week_number = "s".to_owned() + &opts.week;
|
||||||
let records = parse_xlsx(&week_number)?;
|
let records = parse_xlsx(&week_number)?;
|
||||||
|
|
||||||
|
let mut labels = Vec::new();
|
||||||
for record in records {
|
for record in records {
|
||||||
let path = generate_label(&opts.output_dir, record);
|
labels.push(generate_label(record));
|
||||||
println!("{}", path.into_os_string().into_string().unwrap())
|
|
||||||
}
|
}
|
||||||
|
combine_labels(&labels, &opts.output_dir)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue