svg2img 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: facc47fc0eab418cfe750f69e9bbfe715d275712ce9cfdab91c1636464227e1a
4
- data.tar.gz: 69c80ee30083e9a1606d671917933956ef3252371ef2534af36402a301096b83
3
+ metadata.gz: 73a2ea65b81532ded264b2ec92e94d3ac146fda59529c2501625e1ac0fa6472c
4
+ data.tar.gz: 1a378f708361feec86a69733148206d175cb58b354f4f140ab7f2e5fa10faf9d
5
5
  SHA512:
6
- metadata.gz: bc06eaf11a13413293ae4ad3580ab60a72811b854eb4e7a17ea65c7ef5d6ad36506a21af607fc9a63e8963c7bc3b82e60ddaa8e9b2c78e1c0bab74c84cf5b195
7
- data.tar.gz: 81cdd0a53eb265ec5763777235c4f7da633e4d352f19855d9b0694eeff3afa203bf464a2d2ce3431e71b5c8fbc1608b7b6f0b39bbed71219237717411d367dee
6
+ metadata.gz: e0ae235c6a4addf8c2495bd2674f1508359ec58d08d77d1944587cab178dee8a32657f5b6c77c68a1a541a4a7b01889d9eae8980b18cd1dd96235bd1f8d55899
7
+ data.tar.gz: b7af313204aaac5b70b08b614cacced3eb56d35c54febbb4da93c316842f724236729ab41b12575779284e60e36cacf7dc17df02bca4269b1f002f6ef76f5f81
data/Cargo.toml CHANGED
@@ -5,3 +5,7 @@
5
5
  [workspace]
6
6
  members = ["./ext/svg2img"]
7
7
  resolver = "2"
8
+
9
+ [profile.release]
10
+ lto = true
11
+ strip = true
data/README.md CHANGED
@@ -73,6 +73,7 @@ send_data(png_data, type: 'image/png', disposition: 'inline')
73
73
  - `format` - output format, one of `:png`, `:jpg`, `:webp`, `:gif`
74
74
  - `output_path` - path to the output image. If not provided, a temporary file will be created and the path to it will be returned.
75
75
  - `size` - size of the output image as a proc that receives the width and height of the SVG and returns an array with the width and height of the output image. If the provides size has a different aspect ratio than the SVG, the image will be resized to fit in the center of the provided size. If not provided, the output image will have the same size as the SVG.
76
+ - `super_sampling` - supersample factor. The output image will be rendered `super_sampling` times larger than the SVG and then resized to the desired size. This can be used to improve the quality of the output image. Default is 2. Must be a power of 2. 1 means no super sampling.
76
77
 
77
78
  ## Development
78
79
 
@@ -1,10 +1,10 @@
1
1
  [package]
2
- name = "svg2img"
3
- version = "0.1.0"
4
- edition = "2021"
5
2
  authors = ["Orvar Segerström <orvarsegerstrom@gmail.com>"]
3
+ edition = "2021"
6
4
  license = "MIT"
5
+ name = "svg2img"
7
6
  publish = false
7
+ version = "0.1.0"
8
8
 
9
9
  [lib]
10
10
  crate-type = ["cdylib"]
@@ -1,5 +1,5 @@
1
1
  use anyhow::Context;
2
- use image::{DynamicImage, ImageBuffer};
2
+ use image::{DynamicImage, ImageBuffer, ImageEncoder};
3
3
  use magnus::{block::Proc, function, prelude::*, Error, Ruby};
4
4
  use std::panic::{self, AssertUnwindSafe};
5
5
 
@@ -27,12 +27,23 @@ fn process_svg_rb(svg: String, options: magnus::RHash) -> Result<String, magnus:
27
27
  }
28
28
  };
29
29
  }
30
+
31
+ let super_sampling = get_option::<u32>(&options, "super_sampling")?.unwrap_or(2);
32
+ // super_sampling must me a power of 2
33
+ if super_sampling == 0 || super_sampling & (super_sampling - 1) != 0 {
34
+ return Err(magnus::Error::new(
35
+ magnus::exception::arg_error(),
36
+ "svg2img: Invalid super_sampling value, must be a power of 2",
37
+ ));
38
+ }
39
+
30
40
  let options = Options {
31
41
  size: get_option::<Proc>(&options, "size")?
32
42
  .map(convert_size_proc)
33
43
  .unwrap_or_else(default_size),
34
- format,
35
44
  output_path: get_option(&options, "output_path")?,
45
+ format,
46
+ super_sampling,
36
47
  };
37
48
  process_svg(svg, options)
38
49
  .map_err(|err| magnus::Error::new(magnus::exception::runtime_error(), format!("{err:?}")))
@@ -97,10 +108,17 @@ struct Options {
97
108
  size: ProcessSize,
98
109
  format: image::ImageFormat,
99
110
  output_path: Option<String>,
111
+ super_sampling: u32,
100
112
  }
101
113
 
102
114
  fn process_svg(svg: String, options: Options) -> Result<String, anyhow::Error> {
103
- let mut image = image_from_svg(svg.as_bytes(), options.size)?;
115
+ let image = image_from_svg(svg.as_bytes(), options.size, options.super_sampling)?;
116
+
117
+ let mut image = image.resize_exact(
118
+ image.width() / options.super_sampling,
119
+ image.height() / options.super_sampling,
120
+ image::imageops::FilterType::Lanczos3,
121
+ );
104
122
 
105
123
  if options.format == image::ImageFormat::Jpeg {
106
124
  // Convert from rgba8 to rgb8
@@ -109,9 +127,27 @@ fn process_svg(svg: String, options: Options) -> Result<String, anyhow::Error> {
109
127
 
110
128
  let mut buf = Vec::new();
111
129
  let mut cursor = std::io::Cursor::new(&mut buf);
112
- image
113
- .write_to(&mut cursor, options.format)
114
- .context("Failed to write image to buffer")?;
130
+ match options.format {
131
+ image::ImageFormat::Png => {
132
+ image::codecs::png::PngEncoder::new_with_quality(
133
+ &mut cursor,
134
+ image::codecs::png::CompressionType::Best,
135
+ image::codecs::png::FilterType::Adaptive,
136
+ )
137
+ .write_image(
138
+ &image.to_rgba8().into_raw(),
139
+ image.width(),
140
+ image.height(),
141
+ image.color().into(),
142
+ )
143
+ .context("Failed to encode PNG")?;
144
+ }
145
+ _ => {
146
+ image
147
+ .write_to(&mut cursor, options.format)
148
+ .context("Failed to write image to buffer")?;
149
+ }
150
+ };
115
151
 
116
152
  let output_path = options.output_path.unwrap_or_else(|| {
117
153
  let random_filename = format!(
@@ -133,7 +169,11 @@ fn process_svg(svg: String, options: Options) -> Result<String, anyhow::Error> {
133
169
  Ok(output_path)
134
170
  }
135
171
 
136
- fn image_from_svg(bytes: &[u8], size: ProcessSize) -> Result<DynamicImage, anyhow::Error> {
172
+ fn image_from_svg(
173
+ bytes: &[u8],
174
+ size: ProcessSize,
175
+ super_sampling: u32,
176
+ ) -> Result<DynamicImage, anyhow::Error> {
137
177
  let svg = resvg::usvg::Tree::from_data(bytes, &resvg::usvg::Options::default())
138
178
  .context("Failed to parse SVG")?;
139
179
  let svg_width = svg.size().width();
@@ -141,6 +181,8 @@ fn image_from_svg(bytes: &[u8], size: ProcessSize) -> Result<DynamicImage, anyho
141
181
  let svg_ratio = svg_width / svg_height;
142
182
 
143
183
  let (image_width, image_height) = size(svg_width as u32, svg_height as u32)?;
184
+ let image_width = image_width * super_sampling;
185
+ let image_height = image_height * super_sampling;
144
186
  let image_ratio = image_width as f32 / image_height as f32;
145
187
 
146
188
  let scale = if svg_ratio > image_ratio {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Svg2Img
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.4"
5
5
  end
@@ -5,3 +5,7 @@
5
5
  [workspace]
6
6
  members = ["./ext/svg2img"]
7
7
  resolver = "2"
8
+
9
+ [profile.release]
10
+ lto = true
11
+ strip = true
@@ -1,10 +1,10 @@
1
1
  [package]
2
- name = "svg2img"
3
- version = "0.1.0"
4
- edition = "2021"
5
2
  authors = ["Orvar Segerström <orvarsegerstrom@gmail.com>"]
3
+ edition = "2021"
6
4
  license = "MIT"
5
+ name = "svg2img"
7
6
  publish = false
7
+ version = "0.1.0"
8
8
 
9
9
  [lib]
10
10
  crate-type = ["cdylib"]
@@ -5,3 +5,7 @@
5
5
  [workspace]
6
6
  members = ["./ext/svg2img"]
7
7
  resolver = "2"
8
+
9
+ [profile.release]
10
+ lto = true
11
+ strip = true
@@ -1,10 +1,10 @@
1
1
  [package]
2
- name = "svg2img"
3
- version = "0.1.0"
4
- edition = "2021"
5
2
  authors = ["Orvar Segerström <orvarsegerstrom@gmail.com>"]
3
+ edition = "2021"
6
4
  license = "MIT"
5
+ name = "svg2img"
7
6
  publish = false
7
+ version = "0.1.0"
8
8
 
9
9
  [lib]
10
10
  crate-type = ["cdylib"]