Skip to content

Commit

Permalink
feat: support more image output format
Browse files Browse the repository at this point in the history
  • Loading branch information
vicanso committed Jan 12, 2024
1 parent f5ddaec commit 3d5b958
Show file tree
Hide file tree
Showing 21 changed files with 56 additions and 29 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "charts-rs"
version = "0.2.2"
version = "0.3.0"
authors = ["Tree Xie <tree.xie@outlook.com>"]
edition = "2021"
categories = ["multimedia::images"]
Expand All @@ -21,8 +21,8 @@ readme = "./README.md"
[dependencies]
charts-rs-derive = { path = "./charts-rs-derive", version = "0.1.22" }
fontdue = "0.8.0"
image = { version = "0.24.7", features = ["webp-encoder", "avif-encoder"], optional = true }
once_cell = "1.19.0"
png = { version = "0.17.10", optional = true }
regex = "1.10.2"
resvg = { version = "0.37.0", default-features = false, features = [ "text", "system-fonts" ], optional = true }
serde = { version = "1.0.193", features = ["derive"] }
Expand All @@ -31,7 +31,7 @@ snafu = "0.8.0"
substring = "1.4.5"

[features]
image = ["resvg", "png"]
image-encoder = ["resvg", "image"]

[dev-dependencies]
criterion = "0.5.1"
Expand All @@ -43,4 +43,4 @@ harness = false

[package.metadata.docs.rs]
# Whether to pass `--all-features` to Cargo (default: false)
all-features = true
all-features = true
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
fmt:
cargo fmt
test:
cargo test --features "image"
cargo test --features "image-encoder"
lint:
cargo clippy
udeps:
cargo +nightly udeps
bench:
cargo bench --features "image"
cargo bench --features "image-encoder"
4 changes: 2 additions & 2 deletions README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

## 概要

`charts-rs`提供简单的方式生成图表,它支持`svg``png`两种输出格式,以及支持`light``dark``grafana``ant``vintage`, `walden`, `westeros`, `chalk``shine`主题,默认的主题为`light`。现已支持以下类型的图表:`Bar``HorizontalBar``Line``Pie``Radar``Scatter``Candlestick``Table` 以及 `MultiChart`,其相关样式参考`Apache ECharts`
`charts-rs`提供简单的方式生成图表,它支持`svg``png``jepg``webp`以及`avif`等多种输出格式,以及支持`light``dark``grafana``ant``vintage`, `walden`, `westeros`, `chalk``shine`主题,默认的主题为`light`。现已支持以下类型的图表:`Bar``HorizontalBar``Line``Pie``Radar``Scatter``Candlestick``Table` 以及 `MultiChart`,其相关样式参考`Apache ECharts`

## 更多主题色

Expand All @@ -32,7 +32,7 @@
- 支持两组Y轴线的展示
- 图表中的所有元素均支持颜色、字体、字体颜色等基本属性配置
- 支持以`json`的形式初始化图表,更简单易用
- svg与png的格式便于更多的应用场景
- svg、png、jpeg、webp以及avif的格式便于更多的应用场景
- 网页版的json编辑器可用于一步式尝试各选项的效果,填充简化与完整版的配置选择

## 示例
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
- Multiple legends for all charts, for example: `round rect`, `circle` and `rect`
- Supports two y axises, which are useful
- New from json is simple and easy
- Svg and png format support more available scenarios
- Svg, png, jpeg, webp and avif format support more available scenarios
- Web json editor to try using more options by one step

## Demo
Expand Down
Binary file modified asset/image/candlestick.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified asset/image/horizontal-bar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified asset/image/line.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added asset/image/line_mixin.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified asset/image/mix-line-bar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed asset/image/multi-chart.png
Binary file not shown.
Binary file added asset/image/multi-chart.webp
Binary file not shown.
Binary file modified asset/image/pie.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified asset/image/radar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified asset/image/scatter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added asset/image/table.avif
Binary file not shown.
Binary file removed asset/image/table.png
Binary file not shown.
10 changes: 5 additions & 5 deletions src/charts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod canvas;
mod color;
mod common;
mod component;
#[cfg(feature = "image")]
#[cfg(feature = "image-encoder")]
mod encoder;
mod font;
mod horizontal_bar_chart;
Expand All @@ -29,11 +29,11 @@ pub use component::{
Axis, Circle, Grid, Legend, LegendCategory, Line, Pie, Polygon, Polyline, Rect, SmoothLine,
SmoothLineFill, StraightLine, StraightLineFill, Text,
};
#[cfg(feature = "image")]
#[cfg(feature = "image-encoder")]
pub(crate) use encoder::get_or_init_fontdb;
#[cfg(feature = "image")]
pub use encoder::svg_to_png;
#[cfg(feature = "image")]
#[cfg(feature = "image-encoder")]
pub use encoder::*;
#[cfg(feature = "image-encoder")]
pub use encoder::Error as EncoderError;

pub use candlestick_chart::CandlestickChart;
Expand Down
8 changes: 4 additions & 4 deletions src/charts/bar_chart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,11 +571,11 @@ mod tests {
bar_chart.svg().unwrap()
);

#[cfg(feature = "image")]
#[cfg(feature = "image-encoder")]
{
use crate::svg_to_png;
let buf = svg_to_png(&bar_chart.svg().unwrap()).unwrap();
std::fs::write("./asset/line_mixin.png", buf).unwrap();
use crate::svg_to_jpeg;
let buf = svg_to_jpeg(&bar_chart.svg().unwrap()).unwrap();
std::fs::write("./asset/image/line_mixin.jpeg", buf).unwrap();
}
}

Expand Down
35 changes: 31 additions & 4 deletions src/charts/encoder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use once_cell::sync::OnceCell;
use resvg::usvg::{fontdb, Tree, TreeParsing, TreeTextToPath};
use snafu::{ResultExt, Snafu};
use std::io::Cursor;

#[derive(Debug, Snafu)]
pub enum Error {
Expand All @@ -14,7 +15,7 @@ pub enum Error {
#[snafu(display("Error to parse: {source}"))]
Parse { source: resvg::usvg::Error },
#[snafu(display("Encode fail: {source}"))]
Png { source: png::EncodingError },
Image { source: image::ImageError },
}
pub type Result<T, E = Error> = std::result::Result<T, E>;

Expand All @@ -33,8 +34,7 @@ pub(crate) fn get_or_init_fontdb(fonts: Option<Vec<&[u8]>>) -> &fontdb::Database
})
}

/// Converts svg to png
pub fn svg_to_png(svg: &str) -> Result<Vec<u8>, Error> {
fn save_image(svg: &str, format: image::ImageOutputFormat) -> Result<Vec<u8>> {
let fontdb = get_or_init_fontdb(None);
let mut tree = Tree::from_str(svg, &resvg::usvg::Options::default()).context(ParseSnafu {})?;
tree.convert_text(fontdb);
Expand All @@ -46,5 +46,32 @@ pub fn svg_to_png(svg: &str) -> Result<Vec<u8>, Error> {
height: pixmap_size.height(),
})?;
rtree.render(resvg::tiny_skia::Transform::default(), &mut pixmap.as_mut());
pixmap.encode_png().context(PngSnafu {})

let rgba_image =
image::RgbaImage::from_raw(pixmap.width(), pixmap.height(), pixmap.data().to_vec())
.unwrap();
let mut buf = Cursor::new(vec![]);

rgba_image.write_to(&mut buf, format).context(ImageSnafu)?;
Ok(buf.into_inner())
}

/// Converts svg to png
pub fn svg_to_png(svg: &str) -> Result<Vec<u8>> {
save_image(svg, image::ImageOutputFormat::Png)
}

/// Converts svg to jpeg
pub fn svg_to_jpeg(svg: &str) -> Result<Vec<u8>> {
save_image(svg, image::ImageOutputFormat::Jpeg(80))
}

/// Converts svg to webp
pub fn svg_to_webp(svg: &str) -> Result<Vec<u8>> {
save_image(svg, image::ImageOutputFormat::WebP)
}

/// Converts svg to avif
pub fn svg_to_avif(svg: &str) -> Result<Vec<u8>> {
save_image(svg, image::ImageOutputFormat::Avif)
}
2 changes: 1 addition & 1 deletion src/charts/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub fn get_or_try_init_fonts(fonts: Option<Vec<&[u8]>>) -> Result<&'static HashM
}
}
}
#[cfg(feature = "image")]
#[cfg(feature = "image-encoder")]
crate::get_or_init_fontdb(Some(font_datas));
Ok(m)
})
Expand Down
12 changes: 6 additions & 6 deletions tests/image.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#[test]
#[cfg(feature = "image")]
#[cfg(feature = "image-encoder")]
fn generate_image() {
use charts_rs::{
svg_to_png, Align, BarChart, Box, CandlestickChart, HorizontalBarChart, LineChart,
svg_to_png, svg_to_webp, svg_to_avif, Align, BarChart, Box, CandlestickChart, HorizontalBarChart, LineChart,
MarkLine, MarkLineCategory, MultiChart, PieChart, RadarChart, ScatterChart, SeriesCategory,
TableCellStyle, TableChart, THEME_GRAFANA,
};
Expand Down Expand Up @@ -397,8 +397,8 @@ fn generate_image() {
},
];
table_chart.title_text = "NASDAQ".to_string();
let buf = svg_to_png(&table_chart.svg().unwrap()).unwrap();
std::fs::write("./asset/image/table.png", buf).unwrap();
let buf = svg_to_avif(&table_chart.svg().unwrap()).unwrap();
std::fs::write("./asset/image/table.avif", buf).unwrap();

let mut multi_chart = MultiChart::from_json(
r###"{
Expand Down Expand Up @@ -891,6 +891,6 @@ fn generate_image() {
}"###,
)
.unwrap();
let buf = svg_to_png(&multi_chart.svg().unwrap()).unwrap();
std::fs::write("./asset/image/multi-chart.png", buf).unwrap();
let buf = svg_to_webp(&multi_chart.svg().unwrap()).unwrap();
std::fs::write("./asset/image/multi-chart.webp", buf).unwrap();
}

0 comments on commit 3d5b958

Please sign in to comment.