Des images sur une page

Des images placées sur une page.

Rust write_image.rs 124 lignes
  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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! Places images on a page, and writes the result to disk.
//!
//! Each image named on the command line gets a page of its own, exactly as big
//! as the image is: at 72 dots to the inch one pixel is one point, so the page
//! that comes back out of a renderer is the image that went in. That is what
//! makes the output checkable against its own source, pixel for pixel.
//!
//! Named nothing, the example places the two committed fixtures — a JPEG, whose
//! bytes go into the file undecoded, and a PNG whose transparency becomes a
//! soft mask — and adds a page that lays them out the way a document would.
//!
//! Usage: `cargo run --example write_image -- tmp/image.pdf [image...]`

use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use hqf_pdf::content::Content;
use hqf_pdf::cos::Name;
use hqf_pdf::{Document, Image, Page, Rgb};

#[path = "shared/out.rs"]
mod out;

#[path = "shared/licence.rs"]
mod licence;

/// The images the example places when the caller names none: the ones committed
/// for the tests, so that it runs on any machine.
fn default_images() -> Vec<PathBuf> {
    let images = Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("images");
    vec![images.join("photo.jpg"), images.join("logo.png")]
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut args = env::args().skip(1);
    let out = args.next().unwrap_or_else(|| out::default_path("image"));

    let paths: Vec<PathBuf> = args.map(PathBuf::from).collect();
    let showcase = paths.is_empty();
    let paths = if showcase { default_images() } else { paths };

    let mut doc = Document::new();
    doc.set_license(licence::licensed());
    doc.set_info(Name::new("Title"), "hqf-pdf image sample");

    let mut handles = Vec::new();
    for path in &paths {
        let image = Image::parse(fs::read(path)?)?;
        println!(
            "{}: {}x{} {:?}{}, {}, {}",
            path.display(),
            image.width(),
            image.height(),
            image.color_space(),
            if image.has_alpha() {
                ", with a soft mask"
            } else {
                ""
            },
            image.resolution().map_or_else(
                || "stating no resolution of its own".to_owned(),
                |resolution| { format!("{} by {} dots to the inch", resolution.x, resolution.y) },
            ),
            image.orientation().map_or_else(
                || "and no way up".to_owned(),
                |orientation| format!("seen {orientation:?}"),
            )
        );

        let handle = doc.add_image(image);

        // A page the size of the image, with the image filling it. The size is
        // the one the file itself asks for; a file asking for none is laid down
        // one pixel to the point.
        let (width, height) = handle.size();
        let mut c = Content::new();
        c.draw_image(&handle, 0.0, 0.0, width, height)?;

        let mut page = Page::new(width, height);
        page.content = c.into_bytes();
        doc.add_page(page)?;

        handles.push(handle);
    }

    if showcase {
        // One more page, laid out the way a document would lay it out: the
        // photo fitted into a box without being stretched, and the logo, whose
        // transparency lets what is under it show through, over a rule.
        let mut c = Content::new();

        c.set_fill(Rgb::new(0.93, 0.94, 0.96))?;
        c.rect(0.0, 700.0, 595.276, 142.0)?;
        c.fill();

        let photo = &handles[0];
        let (width, height) = photo.fit_within(240.0, 160.0)?;
        c.draw_image(photo, 60.0, 500.0, width, height)?;

        let logo = &handles[1];
        let (width, height) = logo.fit_within(90.0, 90.0)?;
        c.draw_image(logo, 380.0, 730.0, width, height)?;

        let mut page = Page::a4();
        page.content = c.into_bytes();
        doc.add_page(page)?;
    }

    let bytes = doc.to_bytes()?;
    if let Some(parent) = Path::new(&out).parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(&out, &bytes)?;

    println!(
        "wrote {out}: {} bytes, {} page(s)",
        bytes.len(),
        doc.page_count()
    );
    Ok(())
}