fschutt / printpdf

An easy-to-use library for writing PDF in Rust
https://docs.rs/printpdf/
MIT License
802 stars 96 forks source link

image.add_to_layer() example breaks with newer versions of `image` #124

Closed twiclo closed 2 years ago

twiclo commented 2 years ago

The docs claim that this crate depends on image ^0.23 and ships with it but running the code example produces this error:

extern crate printpdf;

use printpdf::*;
use std::io::Cursor;
use image_crate::bmp::BmpDecoder;
use std::fs::File;
use std::io::BufWriter;

fn main() {
    let (doc, page1, layer1) = PdfDocument::new("printpdf graphics test", Mm(210.0), Mm(297.0), "Layer 1");
    let current_layer = doc.get_page(page1).get_layer(layer1);

    // currently, the only reliable file formats are bmp/jpeg/png
    // this is an issue of the image library, not a fault of printpdf

    let image_bytes = include_bytes!("../assets/img/BMP_test.bmp");
    let mut reader = Cursor::new(image_bytes.as_ref());

    let decoder = BmpDecoder::new(&mut reader).unwrap();
    let image = Image::try_from(decoder).unwrap();

    let rotation_center_x = Px((image.image.width.0 as f64 / 2.0) as usize);
    let rotation_center_y = Px((image.image.height.0 as f64 / 2.0) as usize);

    // layer,
    image.add_to_layer(current_layer.clone(), ImageTransform {
        rotate: Some(ImageRotation {
            angle_ccw_degrees: 45.0,
            rotation_center_x,
            rotation_center_y,
        }),
        translate_x: Some(Mm(10.0)),
        translate_y: Some(Mm(10.0)),
        .. Default::default()
    });

    doc.save(&mut BufWriter::new(File::create("test_image.pdf").unwrap())).unwrap();
}

Error:

error[E0433]: failed to resolve: use of undeclared crate or module `image_crate`
 --> src/main.rs:5:5
  |
5 | use image_crate::bmp::BmpDecoder;
  |     ^^^^^^^^^^^ use of undeclared crate or module `image_crate`

The image crate no longer has image::bmp::BmpDecoder. It has been renamed to image::codecs::bmp::BmpDecoder. Okay, let's add the image crate manually and try again:

Cargo.toml:

[package]
name = "printpdf"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
printpdf = "0.5.0"
image = "0.23.0"

main.rs:

extern crate printpdf;

use printpdf::{ImageRotation, ImageTransform, Mm, Px, Image, PdfDocument};
use image::codecs::bmp::BmpDecoder;
use std::io::Cursor;
use std::fs::File;
use std::io::BufWriter;

fn main() {
    let (doc, page1, layer1) = PdfDocument::new("printpdf graphics test", Mm(210.0), Mm(297.0), "Layer 1");
    let current_layer = doc.get_page(page1).get_layer(layer1);

    // currently, the only reliable file formats are bmp/jpeg/png
    // this is an issue of the image library, not a fault of printpdf

    let image_bytes = include_bytes!("../assets/img/BMP_test.bmp");
    let mut reader = Cursor::new(image_bytes.as_ref());

    let decoder = BmpDecoder::new(&mut reader).unwrap();
    let image = Image::try_from(decoder).unwrap();

    let rotation_center_x = Px((image.image.width.0 as f64 / 2.0) as usize);
    let rotation_center_y = Px((image.image.height.0 as f64 / 2.0) as usize);

    // layer,
    image.add_to_layer(current_layer.clone(), ImageTransform {
        rotate: Some(ImageRotation {
            angle_ccw_degrees: 45.0,
            rotation_center_x,
            rotation_center_y,
        }),
        translate_x: Some(Mm(10.0)),
        translate_y: Some(Mm(10.0)),
        .. Default::default()
    });

    doc.save(&mut BufWriter::new(File::create("test_image.pdf").unwrap())).unwrap();
}

Error:

error[E0277]: the trait bound `printpdf::Image: From<BmpDecoder<&mut std::io::Cursor<_>>>` is not satisfied
  --> src/main.rs:20:17
   |
20 |     let image = Image::try_from(decoder).unwrap();
   |                 ^^^^^^^^^^^^^^^ the trait `From<BmpDecoder<&mut std::io::Cursor<_>>>` is not implemented for `printpdf::Image`
   |
   = help: the trait `From<ImageXObject>` is implemented for `printpdf::Image`
   = note: required because of the requirements on the impl of `Into<printpdf::Image>` for `BmpDecoder<&mut std::io::Cursor<_>>`
   = note: required because of the requirements on the impl of `TryFrom<BmpDecoder<&mut std::io::Cursor<_>>>` for `printpdf::Image`

For more information about this error, try `rustc --explain E0277`.
fschutt commented 2 years ago

Yeah, I have to update the crate

twiclo commented 2 years ago

I can do if you'd let me know what specifically needs to be done

fschutt commented 2 years ago

@twiclo you just need to update the image = ... dependencies in the various .toml files, remove the old Image::try_from implementation and replace every import of image::bmp::BmpDecoder with image::codecs::bmp::BmpDecoder.

twiclo commented 2 years ago

What would be used instead of try_from when creating an Image?

fschutt commented 2 years ago

@twiclo see if it works with the changes in https://github.com/fschutt/printpdf/pull/125

fschutt commented 2 years ago

also image_crate is just a typedef for image, to not confuse it with the printpdf::image module

twiclo commented 2 years ago
error[E0599]: no function or associated item named `try_from` found for struct `printpdf::Image` in the current scope
  --> src/pdf/templates/ubb_invoice_template.rs:42:22
   |
42 |         let image = Image::try_from(image::png::PngDecoder::new(&mut image_file).unwrap()).unwrap();
   |                            ^^^^^^^^ function or associated item not found in `printpdf::Image`
   |
   = help: items from traits can only be used if the trait is in scope

Am I still supposed to be using version 0.5.2 of printpdf?

fschutt commented 2 years ago

@twiclo I released 0.5.3 just now

twiclo commented 2 years ago

Image::try_from() Still doesn't exist on 0.5.3

error[E0599]: no function or associated item named `try_from` found for struct `printpdf::Image` in the current scope
  --> src/pdf/templates/ubb_invoice_template.rs:42:22
   |
42 |         let image = Image::try_from(image::codecs::png::PngDecoder::new(&mut image_file).unwrap()).unwrap();
   |                            ^^^^^^^^ function or associated item not found in `printpdf::Image`
   |
   = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
1  | use std::convert::TryFrom;
   |
fschutt commented 2 years ago

@twiclo yeah you need to import use std::convert::TryFrom; as the error message says

twiclo commented 2 years ago
use std::fs::File;
use std::io::BufWriter;
use std::convert::TryFrom;
use image::codecs::png::PngDecoder;
use printpdf::{BuiltinFont, Image, Line, Mm, PdfDocument, Point};

pub struct InvoiceData {
  pub po: String,
  pub invoice_date: String,
  pub invoice_number: u32,
}

pub struct CustomerData {
  pub account_number: u32,
  pub name: String,
  pub address: String,
  pub city: String,
  pub state: String,
  pub zip: u32,
}

#[allow(dead_code)]
pub struct InvoiceItem {
  pub name: String,
  pub qty: u32,
  pub rate: f32,
}

#[allow(dead_code)]
pub fn generate_ubb_invoice_pdf(filename: String, invoice_data: InvoiceData, customer: CustomerData, invoice_items: Vec<InvoiceItem>) {
  let a4_page_width = Mm(210.0);
  let a4_page_height = Mm(297.0);

  let (doc, page1, layer1) = PdfDocument::new(format!("invoice_{}.pdf", invoice_data.invoice_number), a4_page_width, a4_page_height, "Layer 1");
  let current_layer = doc.get_page(page1).get_layer(layer1);

  let helvetica_bold = doc.add_builtin_font(BuiltinFont::HelveticaBold).unwrap();
  let helvetica_bold_italic = doc.add_builtin_font(BuiltinFont::HelveticaBoldOblique).unwrap();
  let helvetica = doc.add_builtin_font(BuiltinFont::Helvetica).unwrap();

  // UBB Header and Address
  {
    let mut image_file = File::open("assets/img/ubb-logo-no-alpha.png").unwrap();
    let image = Image::try_from(PngDecoder::new(&mut image_file).unwrap()).unwrap();

     let section_x_offset = 0.0;
     let section_y_offset = 0.0;

     image.add_to_layer(current_layer.clone(), Some(Mm(15.0 + section_x_offset)), Some(Mm(265.0 + section_y_offset)), None, Some(1.0), Some(1.0), Some(300.0));
error[E0277]: the trait bound `printpdf::Image: std::convert::From<PngDecoder<&mut File>>` is not satisfied
  --> src/pdf/templates/ubb_invoice_template.rs:44:15
   |
44 |         let image = Image::try_from(PngDecoder::new(&mut image_file).unwrap()).unwrap();
   |                     ^^^^^^^^^^^^^^^ the trait `std::convert::From<PngDecoder<&mut File>>` is not implemented for `printpdf::Image`
   |
   = help: the trait `std::convert::From<ImageXObject>` is implemented for `printpdf::Image`
   = note: required because of the requirements on the impl of `Into<printpdf::Image>` for `PngDecoder<&mut File>`
   = note: required because of the requirements on the impl of `TryFrom<PngDecoder<&mut File>>` for `printpdf::Image`

error[E0061]: this function takes 2 arguments but 7 arguments were supplied
  --> src/pdf/templates/ubb_invoice_template.rs:49:9
   |
49 | ...ge.add_to_layer(current_layer.clone(), Some(Mm(15.0 + section_x_offset)), Some(Mm(265.0 + section_y_offset)), None, Some(1.0), Some(1.0), Some(300.0...
   |       ^^^^^^^^^^^^                        ---------------------------------  ----------------------------------  ----  ---------  ---------  ----------- argument unexpected
   |                                           |                                  |                                   |     |          |
   |                                           |                                  |                                   |     |          argument unexpected
   |                                           |                                  |                                   |     argument unexpected
   |                                           |                                  |                                   argument unexpected
   |                                           |                                  argument unexpected
   |                                           expected struct `ImageTransform`, found enum `std::option::Option`
   |
   = note: expected struct `ImageTransform`
                found enum `std::option::Option<Mm>`
note: associated function defined here
  --> /home/twiclo/.cargo/registry/src/github.com-1ecc6299db9ec823/printpdf-0.5.2/src/image.rs:79:12
   |
79 |     pub fn add_to_layer(self, layer: PdfLayerReference, transform: ImageTransform)
   |            ^^^^^^^^^^^^
help: remove the extra arguments
   |
49 |         image.add_to_layer(current_layer.clone(), /* ImageTransform */);
   |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sorry if I'm missing something here

fschutt commented 2 years ago

Yeah okay, then it's an issue in the library. I'll look into it.