-
-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot add Png image to pdf page #119
Comments
One thing to notice is when I try to use $> img2pdf inputs/screenshot.png
WARNING:root:Image contains transparency which cannot be retained in PDF.
WARNING:root:img2pdf will not perform a lossy operation.
WARNING:root:You can remove the alpha channel using imagemagick:
WARNING:root: $ convert input.png -background white -alpha remove -alpha off output.png
ERROR:root:error: Refusing to work on images with alpha channel |
see #84 |
as I see, the only way to solve this problem to is convert |
@fschutt I manage to solve the problem by converting ImageXObject with color space Rgba to color space Rgb with white background. Editted: this only works with Rgba8 or Bgra8 image. This is the function: use printpdf::{xobject::ImageXObject, ColorSpace};
pub fn remove_alpha_channel_from_image_x_object(image_x_object: ImageXObject) -> ImageXObject {
if !matches!(image_x_object.color_space, ColorSpace::Rgba)
{
return image_x_object;
};
let ImageXObject {
color_space,
image_data,
..
} = image_x_object;
let new_image_data = image_data
.chunks(4)
.map(|rgba| {
let [red, green, blue, alpha]: [u8; 4] = rgba.try_into().ok().unwrap();
let alpha = alpha as f64 / 255.0;
let new_red = ((1.0 - alpha) * 255.0 + alpha * red as f64) as u8;
let new_green = ((1.0 - alpha) * 255.0 + alpha * green as f64) as u8;
let new_blue = ((1.0 - alpha) * 255.0 + alpha * blue as f64) as u8;
return [new_red, new_green, new_blue];
})
.collect::<Vec<[u8; 3]>>()
.concat();
let new_color_space = match color_space {
ColorSpace::Rgba => ColorSpace::Rgb,
ColorSpace::GreyscaleAlpha => ColorSpace::Greyscale,
other_type => other_type,
};
ImageXObject {
color_space: new_color_space,
image_data: new_image_data,
..image_x_object
}
} Do you want this to be part of printpdf source code? |
@anhtumai yeah at least for now it would be a good workaround because this issue comes up again and again |
/edit: the workaround works as expected, I just had an interfering let mut image = Image::try_from(PngDecoder::new(&mut image_file).unwrap()).unwrap();
image.image = remove_alpha_channel_from_image_x_object(image.image); this PNG (ColourType=Rgba8) renders like this (colorful background for illustration purposes): |
@flying-sheep How would you render the image? I rendered the image with printpdf 0.5.3 and it looks like this: Here is my code use std::{fs::File, io::BufWriter};
use image_crate::codecs::png::PngDecoder;
use printpdf::{
image_crate, xobject::ImageXObject, ColorSpace, Image, ImageTransform, Mm, PdfDocument,
};
pub fn remove_alpha_channel_from_image_x_object(image_x_object: ImageXObject) -> ImageXObject {
if !matches!(image_x_object.color_space, ColorSpace::Rgba) {
return image_x_object;
};
let ImageXObject {
color_space,
image_data,
..
} = image_x_object;
let new_image_data = image_data
.chunks(4)
.map(|rgba| {
let [red, green, blue, alpha]: [u8; 4] = rgba.try_into().ok().unwrap();
let alpha = alpha as f64 / 255.0;
let new_red = ((1.0 - alpha) * 255.0 + alpha * red as f64) as u8;
let new_green = ((1.0 - alpha) * 255.0 + alpha * green as f64) as u8;
let new_blue = ((1.0 - alpha) * 255.0 + alpha * blue as f64) as u8;
return [new_red, new_green, new_blue];
})
.collect::<Vec<[u8; 3]>>()
.concat();
let new_color_space = match color_space {
ColorSpace::Rgba => ColorSpace::Rgb,
ColorSpace::GreyscaleAlpha => ColorSpace::Greyscale,
other_type => other_type,
};
ImageXObject {
color_space: new_color_space,
image_data: new_image_data,
..image_x_object
}
}
fn main() {
let img_file_name = "/tmp/polygon.png"; // the full path to your polygon image
// open file
let mut image_file = File::open(&img_file_name).unwrap();
let mut image = Image::try_from(PngDecoder::new(&mut image_file).unwrap()).unwrap();
// turn rbga to rgb
image.image = remove_alpha_channel_from_image_x_object(image.image);
// use printpdf to render that image to the new pdf file
let doc = PdfDocument::empty("output-pdf-file");
let (page, layer_index) = doc.add_page(Mm(10.0), Mm(10.0), "ImageLayer");
let current_layer = doc.get_page(page).get_layer(layer_index);
image.add_to_layer(current_layer, ImageTransform::default());
doc.save(&mut BufWriter::new(
File::create("output-pdf-file.pdf").unwrap(),
))
.unwrap();
} Here is my Cargo.toml content [package]
name = "test-remove-alpha"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
printpdf = { version = "0.5.3", features = ["embedded_images"] } |
you’re going to have to render it in front of anything that isn’t white background to see if it renders correctly or not. |
Can you paste your code here? |
@flying-sheep have you solved the problem? |
I looked into it and it’s because in the shape drawing example, global state is modified, sorry. (bit hard to see but it’s all transparent) Adding a PS: I think there should be some things implementing use std::{fs::File, io::BufWriter};
use image_crate::codecs::png::PngDecoder;
use printpdf::{
image_crate, xobject::ImageXObject, ColorSpace, Image, ImageTransform, Mm, PdfDocument, Line, Point, PdfLayerReference, Color, Cmyk, Rgb, LineDashPattern, BlendMode, LineCapStyle, LineJoinStyle, SeperableBlendMode, Greyscale,
};
const OCTAGON_BYTES: &'static [u8] = include_bytes!("octagon.png");
pub fn remove_alpha_channel_from_image_x_object(image_x_object: ImageXObject) -> ImageXObject {
if !matches!(image_x_object.color_space, ColorSpace::Rgba) {
return image_x_object;
};
let ImageXObject {
color_space,
image_data,
..
} = image_x_object;
let new_image_data = image_data
.chunks(4)
.map(|rgba| {
let [red, green, blue, alpha]: [u8; 4] = rgba.try_into().ok().unwrap();
let alpha = alpha as f64 / 255.0;
let new_red = ((1.0 - alpha) * 255.0 + alpha * red as f64) as u8;
let new_green = ((1.0 - alpha) * 255.0 + alpha * green as f64) as u8;
let new_blue = ((1.0 - alpha) * 255.0 + alpha * blue as f64) as u8;
return [new_red, new_green, new_blue];
})
.collect::<Vec<[u8; 3]>>()
.concat();
let new_color_space = match color_space {
ColorSpace::Rgba => ColorSpace::Rgb,
ColorSpace::GreyscaleAlpha => ColorSpace::Greyscale,
other_type => other_type,
};
ImageXObject {
color_space: new_color_space,
image_data: new_image_data,
..image_x_object
}
}
fn draw_bg(layer: PdfLayerReference) {
let points1 = vec![
(Point::new(Mm(4.0), Mm(4.0)), false),
(Point::new(Mm(4.0), Mm(7.0)), false),
(Point::new(Mm(7.0), Mm(7.0)), false),
(Point::new(Mm(7.0), Mm(4.0)), false),
];
let line1 = Line {
points: points1,
is_closed: true,
has_fill: true,
has_stroke: true,
is_clipping_path: false,
};
let fill_color_2 = Color::Cmyk(Cmyk::new(0.0, 0.0, 0.0, 0.0, None));
let outline_color_2 = Color::Greyscale(Greyscale::new(0.45, None));
// More advanced graphical options
layer.set_overprint_stroke(true);
layer.set_blend_mode(BlendMode::Seperable(SeperableBlendMode::Multiply));
layer.set_line_cap_style(LineCapStyle::Round);
layer.set_line_join_style(LineJoinStyle::Round);
layer.set_fill_color(fill_color_2);
layer.set_outline_color(outline_color_2);
layer.set_outline_thickness(15.0);
layer.add_shape(line1);
// layer.set_blend_mode(BlendMode::Seperable(SeperableBlendMode::Normal));
}
fn main() {
// open file
let mut image = Image::try_from(PngDecoder::new(OCTAGON_BYTES).unwrap()).unwrap();
// turn rbga to rgb
image.image = remove_alpha_channel_from_image_x_object(image.image);
// use printpdf to render that image to the new pdf file
let doc = PdfDocument::empty("output-pdf-file");
let (page, layer_index) = doc.add_page(Mm(10.0), Mm(10.0), "ImageLayer");
let current_layer = doc.get_page(page).get_layer(layer_index);
draw_bg(current_layer.clone());
image.add_to_layer(current_layer.clone(), ImageTransform::default());
doc.save(&mut BufWriter::new(
File::create("output-pdf-file.pdf").unwrap(),
))
.unwrap();
} |
@wjcroom can you try running https://github.com/fschutt/printpdf/blob/master/examples/image.rs with your image and seeing if that fixes it? |
@fschutt my printpdf is 0.7 . i dont know how to test it . |
@wjcroom test it like in #200 (comment) , reopen if necessary. Was fixed in master, so this issue can be closed. |
remove alpa? if we need alpa, how should we show a png,or bmp ,with alpa message ?I can see all in new pdf form png ,it is a good work , |
Every time I try to decode a PNG file with PngDecoded and add it to the PDF page, the PDF page is blank.
My Rust code:
Cargo.toml:
The PNG file,

inputs/screenshot.png
:The output PDF,

output.pdf
:P/s: This problem does not happen when I decode JPEG files with JpegDecoder. Maybe it is only applied for PNG files
The text was updated successfully, but these errors were encountered: