Make 'image' crate optional (#764)

Discussion at #763.
main
Igor Strebz 2024-10-22 04:28:58 +03:00 committed by GitHub
parent 6fdf81d1ba
commit bf5ccac4b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 36 additions and 43 deletions

View File

@ -18,7 +18,8 @@ name = "docx_rs"
path = "src/lib.rs" path = "src/lib.rs"
[features] [features]
wasm = ["wasm-bindgen", "ts-rs"] default = ["image"]
wasm = ["wasm-bindgen", "ts-rs", "image"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -29,7 +30,7 @@ zip = { version = "0.6.3", default-features = false, features = ["deflate"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = {version = "1.0" } serde_json = {version = "1.0" }
base64 = "0.13.1" base64 = "0.13.1"
image = { version = "0.24.4", default-features = false, features=["gif", "jpeg", "png", "bmp", "tiff"] } image = { version = "0.24.4", default-features = false, features=["gif", "jpeg", "png", "bmp", "tiff"], optional = true }
wasm-bindgen = { version = "0.2.78", optional = true } wasm-bindgen = { version = "0.2.78", optional = true }
ts-rs = { version = "6.1", optional = true } ts-rs = { version = "6.1", optional = true }

View File

@ -163,12 +163,8 @@ mod tests {
#[test] #[test]
fn test_drawing_build_with_pic() { fn test_drawing_build_with_pic() {
use std::io::Read; let pic = Pic::new_with_dimensions(Vec::new(), 320, 240);
let d = Drawing::new().pic(pic).build();
let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap();
let mut buf = Vec::new();
let _ = img.read_to_end(&mut buf).unwrap();
let d = Drawing::new().pic(Pic::new(&buf)).build();
assert_eq!( assert_eq!(
str::from_utf8(&d).unwrap(), str::from_utf8(&d).unwrap(),
r#"<w:drawing> r#"<w:drawing>
@ -212,12 +208,8 @@ mod tests {
#[test] #[test]
fn test_drawing_build_with_pic_overlap() { fn test_drawing_build_with_pic_overlap() {
use std::io::Read; let pic = Pic::new_with_dimensions(Vec::new(), 320, 240).overlapping();
let d = Drawing::new().pic(pic).build();
let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap();
let mut buf = Vec::new();
let _ = img.read_to_end(&mut buf).unwrap();
let d = Drawing::new().pic(Pic::new(&buf).overlapping()).build();
assert_eq!( assert_eq!(
str::from_utf8(&d).unwrap(), str::from_utf8(&d).unwrap(),
r#"<w:drawing> r#"<w:drawing>
@ -262,12 +254,7 @@ mod tests {
#[test] #[test]
fn test_drawing_build_with_pic_align_right() { fn test_drawing_build_with_pic_align_right() {
use std::io::Read; let mut pic = Pic::new_with_dimensions(Vec::new(), 320, 240).floating();
let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap();
let mut buf = Vec::new();
let _ = img.read_to_end(&mut buf).unwrap();
let mut pic = Pic::new(&buf).floating();
pic = pic.relative_from_h(RelativeFromHType::Column); pic = pic.relative_from_h(RelativeFromHType::Column);
pic = pic.relative_from_v(RelativeFromVType::Paragraph); pic = pic.relative_from_v(RelativeFromVType::Paragraph);
pic = pic.position_h(DrawingPosition::Align(PicAlign::Right)); pic = pic.position_h(DrawingPosition::Align(PicAlign::Right));
@ -323,12 +310,7 @@ mod tests {
#[test] #[test]
fn test_issue686() { fn test_issue686() {
use std::io::Read; let pic = Pic::new_with_dimensions(Vec::new(), 320, 240)
let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap();
let mut buf = Vec::new();
let _ = img.read_to_end(&mut buf).unwrap();
let pic = Pic::new(&buf)
.size(320 * 9525, 240 * 9525) .size(320 * 9525, 240 * 9525)
.floating() .floating()
.offset_x(300 * 9525) .offset_x(300 * 9525)

View File

@ -1,4 +1,3 @@
use image::*;
use serde::Serialize; use serde::Serialize;
use crate::documents::*; use crate::documents::*;
@ -50,18 +49,28 @@ pub struct Pic {
} }
impl Pic { impl Pic {
#[cfg(feature = "image")]
/// Make a `Pic`.
///
/// Converts the passed image to PNG internally and computes its size.
pub fn new(buf: &[u8]) -> Pic { pub fn new(buf: &[u8]) -> Pic {
let id = create_pic_rid(generate_pic_id()); let img = ::image::load_from_memory(buf).expect("Should load image from memory.");
let dimg = image::load_from_memory(buf).expect("Should load image from memory."); let (w, h) = ::image::GenericImageView::dimensions(&img);
let size = dimg.dimensions(); let mut buf = std::io::Cursor::new(vec![]);
let mut image = std::io::Cursor::new(vec![]); img.write_to(&mut buf, ::image::ImageFormat::Png)
// For now only png supported
dimg.write_to(&mut image, ImageFormat::Png)
.expect("Unable to write dynamic image"); .expect("Unable to write dynamic image");
Self::new_with_dimensions(buf.into_inner(), w, h)
}
/// Make a `Pic` element. For now only PNG is supported.
///
/// Use [Pic::new] method, to call `image` crate do conversion for you.
pub fn new_with_dimensions(buffer: Vec<u8>, width_px: u32, height_px: u32) -> Pic {
let id = create_pic_rid(generate_pic_id());
Self { Self {
id, id,
image: image.into_inner(), image: buffer,
size: (from_px(size.0), from_px(size.1)), size: (from_px(width_px), from_px(height_px)),
position_type: DrawingPositionType::Inline, position_type: DrawingPositionType::Inline,
simple_pos: false, simple_pos: false,
simple_pos_x: 0, simple_pos_x: 0,
@ -236,12 +245,7 @@ mod tests {
#[test] #[test]
fn test_pic_build() { fn test_pic_build() {
use std::io::Read; let b = Pic::new_with_dimensions(Vec::new(), 320, 240).build();
let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap();
let mut buf = Vec::new();
let _ = img.read_to_end(&mut buf).unwrap();
let b = Pic::new(&buf).build();
assert_eq!( assert_eq!(
str::from_utf8(&b).unwrap(), str::from_utf8(&b).unwrap(),
r#"<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"> r#"<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">

View File

@ -43,7 +43,6 @@ mod xml_docx;
pub(crate) use build_xml::BuildXML; pub(crate) use build_xml::BuildXML;
pub(crate) use history_id::HistoryId; pub(crate) use history_id::HistoryId;
pub(crate) use hyperlink_id::*; pub(crate) use hyperlink_id::*;
use image::ImageFormat;
pub(crate) use paragraph_id::*; pub(crate) use paragraph_id::*;
pub(crate) use paragraph_property_change_id::ParagraphPropertyChangeId; pub(crate) use paragraph_property_change_id::ParagraphPropertyChangeId;
pub(crate) use pic_id::*; pub(crate) use pic_id::*;
@ -246,15 +245,22 @@ impl Docx {
path: impl Into<String>, path: impl Into<String>,
buf: Vec<u8>, buf: Vec<u8>,
) -> Self { ) -> Self {
#[cfg(feature = "image")]
if let Ok(dimg) = image::load_from_memory(&buf) { if let Ok(dimg) = image::load_from_memory(&buf) {
let mut png = std::io::Cursor::new(vec![]); let mut png = std::io::Cursor::new(vec![]);
// For now only png supported // For now only png supported
dimg.write_to(&mut png, ImageFormat::Png) dimg.write_to(&mut png, image::ImageFormat::Png)
.expect("Unable to write dynamic image"); .expect("Unable to write dynamic image");
self.images self.images
.push((id.into(), path.into(), Image(buf), Png(png.into_inner()))); .push((id.into(), path.into(), Image(buf), Png(png.into_inner())));
} }
#[cfg(not(feature = "image"))]
// without 'image' crate we can only test for PNG file signature
if buf.starts_with(&[137, 80, 78, 71, 13, 10, 26, 10]) {
self.images
.push((id.into(), path.into(), Image(buf.clone()), Png(buf)));
}
self self
} }