Skip to content

Commit 603b7f4

Browse files
committed
Update the bitmap backend not to relies on image, only the image encoding part relies on it
1 parent 0ccec8b commit 603b7f4

File tree

12 files changed

+93
-66
lines changed

12 files changed

+93
-66
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
- Font description is greatly improved, general font family is supported: `serif`, `serif-sans`, `monospace` (Thanks to @Tatrix)
1212
- Tested the font loading on Linux, OSX and Windowns. Make font loading more reliable.
13+
- `BitMapBackend` isn't depdends on `image` crate now. Only the image encoding part relies on the `image` crate
1314

1415
## Plotters 0.2.10 (2019-10-23)
1516

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ version = "0.3.29"
4040
features = ['Document', 'Element', 'HtmlElement', 'Node', 'Window', 'HtmlCanvasElement', 'CanvasRenderingContext2d']
4141

4242
[features]
43-
default = ["bitmap", "svg", "chrono", "palette_ext", "make_partial_axis", "gif_backend"]
43+
default = ["image_encoder", "svg", "chrono", "palette_ext", "make_partial_axis", "gif_backend"]
44+
image_encoder = ["image"]
4445
palette_ext = ["palette", "num-traits"]
45-
bitmap = ["image"]
46-
gif_backend = ["bitmap", "gif"]
46+
gif_backend = ["gif"]
4747
datetime = ["chrono"]
4848
evcxr = ["svg"]
4949
piston = ["piston_window"]

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Plotters - A Rust drawing library focus on data plotting for both WASM and native applications 🦀📈🚀
1+
# Plotters - A Rust drawing library focus on data plotting for both WASM and native applications 🦀📈🚀
22

33
<a href="https://crates.io/crates/plotters">
44
<img style="display: inline!important" src="https://img.shields.io/crates/v/plotters.svg"></img>
@@ -479,11 +479,12 @@ This is the full list of features that is defined by `Plotters` crate. Use `defa
479479

480480
| Name | Description | Additional Dependency |Default?|
481481
|---------|--------------|--------|------------|
482-
| bitmap | Enable `BitMapBackend` Support| image | Yes |
482+
| image\_encoder | Allow `BitMapBackend` save the result to bitmap files | image | Yes |
483483
| svg | Enable `SVGBackend` Support | svg | Yes |
484484
| datetime| Enable Date and Time Coordinate Support| chrono | Yes |
485485
| gif\_backend| Opt-in GIF animation Rendering support for `BitMapBackend`, implies `bitmap` enabled | gif | Yes |
486486
| piston | Enable `PistonWindowBackend` | piston\_window | No |
487+
| cairo | Enable `CairoBackend` | cairo-rs | No |
487488
| palette\_ext | Use crate `palette` for color expression| palette | Yes |
488489
| evcxr | Enable Evcxr support, which allows use `Plotters` in Jupyter Note Book | None | No |
489490
| make\_partial\_axis | Support for API `make_partial_axis`, which allows configuring partial axis from visible portion. | num-trait| Yes |

doc-template/readme.template.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,12 @@ This is the full list of features that is defined by `Plotters` crate. Use `defa
249249

250250
| Name | Description | Additional Dependency |Default?|
251251
|---------|--------------|--------|------------|
252-
| bitmap | Enable `BitMapBackend` Support| image | Yes |
252+
| image\_encoder | Allow `BitMapBackend` save the result to bitmap files | image | Yes |
253253
| svg | Enable `SVGBackend` Support | svg | Yes |
254254
| datetime| Enable Date and Time Coordinate Support| chrono | Yes |
255255
| gif\_backend| Opt-in GIF animation Rendering support for `BitMapBackend`, implies `bitmap` enabled | gif | Yes |
256256
| piston | Enable `PistonWindowBackend` | piston\_window | No |
257+
| cairo | Enable `CairoBackend` | cairo-rs | No |
257258
| palette\_ext | Use crate `palette` for color expression| palette | Yes |
258259
| evcxr | Enable Evcxr support, which allows use `Plotters` in Jupyter Note Book | None | No |
259260
| make\_partial\_axis | Support for API `make_partial_axis`, which allows configuring partial axis from visible portion. | num-trait| Yes |

doc-template/update_readme.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ NR != FNR{
2222
}' <(${REPO_BASE}/doc-template/render_readme.sh ${REPO_BASE}/doc-template/readme.template.md ${REPO_BASE}/doc-template/rustdoc) ${REPO_BASE}/src/lib.rs > ${REPO_BASE}/src/lib.rs.tmp
2323

2424
mv ${REPO_BASE}/src/lib.rs.tmp ${REPO_BASE}/src/lib.rs
25-
rustfmt ${REPO_BASE}/src/lib.rs
25+
cargo fmt

src/drawing/backend.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,14 @@ pub trait DrawingBackend: Sized {
219219
///
220220
/// - `text`: pos the left upper conner of the bitmap to blit
221221
/// - `src`: The source of the image
222-
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
223222
fn blit_bitmap<'a>(
224223
&mut self,
225224
pos: BackendCoord,
226-
src: &'a image::ImageBuffer<image::Rgb<u8>, &'a [u8]>,
225+
(iw, ih): (u32, u32),
226+
src: &'a [u8],
227227
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
228228
let (w, h) = self.get_size();
229229

230-
let (iw, ih) = src.dimensions();
231230
for dx in 0..iw {
232231
if pos.0 + dx as i32 >= w as i32 {
233232
break;
@@ -236,8 +235,10 @@ pub trait DrawingBackend: Sized {
236235
if pos.1 + dy as i32 >= h as i32 {
237236
break;
238237
}
239-
let pixel = src.get_pixel(dx, dy);
240-
let color = crate::style::RGBColor(pixel.0[0], pixel.0[1], pixel.0[2]);
238+
let r = src[(dx + dy * w) as usize * 3 + 0];
239+
let g = src[(dx + dy * w) as usize * 3 + 1];
240+
let b = src[(dx + dy * w) as usize * 3 + 2];
241+
let color = crate::style::RGBColor(r, g, b);
241242
let result =
242243
self.draw_pixel((pos.0 + dx as i32, pos.1 + dy as i32), &color.to_rgba());
243244
if result.is_err() {

src/drawing/backend_impl/bitmap.rs

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,38 @@
11
use crate::drawing::backend::{BackendCoord, BackendStyle, DrawingBackend, DrawingErrorKind};
22
use crate::style::{Color, RGBAColor};
3+
use std::marker::PhantomData;
34

4-
use image::{ImageBuffer, ImageError, Rgb};
5+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
6+
mod image_encoding_support {
7+
pub(super) use image::{ImageBuffer, ImageError, Rgb};
8+
pub(super) use std::path::Path;
9+
pub(super) type BorrowedImage<'a> = ImageBuffer<Rgb<u8>, &'a mut [u8]>;
10+
}
11+
12+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
13+
use image_encoding_support::*;
14+
15+
#[derive(Debug)]
16+
pub enum BitMapBackendError {
17+
InvalidBuffer,
18+
IOError(std::io::Error),
19+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
20+
ImageError(ImageError),
21+
}
522

6-
use std::path::Path;
23+
impl std::fmt::Display for BitMapBackendError {
24+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25+
write!(f, "{:?}", self)
26+
}
27+
}
728

8-
pub type BorrowedImage<'a> = ImageBuffer<Rgb<u8>, &'a mut [u8]>;
29+
impl std::error::Error for BitMapBackendError {}
930

1031
fn blend(prev: &mut u8, new: u8, a: f64) {
1132
*prev = ((f64::from(*prev)) * (1.0 - a) + a * f64::from(new)).min(255.0) as u8;
1233
}
1334

14-
#[cfg(feature = "gif")]
35+
#[cfg(all(feature = "gif", not(target_arch = "wasm32"), feature = "image"))]
1536
mod gif_support {
1637
use super::*;
1738
use gif::{Encoder as GifEncoder, Frame as GifFrame, Repeat, SetParameter};
@@ -29,15 +50,18 @@ mod gif_support {
2950
path: T,
3051
dim: (u32, u32),
3152
delay: u32,
32-
) -> Result<Self, ImageError> {
53+
) -> Result<Self, BitMapBackendError> {
3354
let mut encoder = GifEncoder::new(
34-
File::create(path.as_ref()).map_err(ImageError::IoError)?,
55+
File::create(path.as_ref()).map_err(BitMapBackendError::IOError)?,
3556
dim.0 as u16,
3657
dim.1 as u16,
3758
&[],
38-
)?;
59+
)
60+
.map_err(BitMapBackendError::IOError)?;
3961

40-
encoder.set(Repeat::Infinite)?;
62+
encoder
63+
.set(Repeat::Infinite)
64+
.map_err(BitMapBackendError::IOError)?;
4165

4266
Ok(Self {
4367
encoder,
@@ -47,34 +71,39 @@ mod gif_support {
4771
})
4872
}
4973

50-
pub(super) fn flush_frame(&mut self, buffer: &[u8]) -> Result<(), ImageError> {
74+
pub(super) fn flush_frame(&mut self, buffer: &[u8]) -> Result<(), BitMapBackendError> {
5175
let mut frame =
5276
GifFrame::from_rgb_speed(self.width as u16, self.height as u16, buffer, 10);
5377

5478
frame.delay = self.delay as u16;
5579

56-
self.encoder.write_frame(&frame)?;
80+
self.encoder
81+
.write_frame(&frame)
82+
.map_err(BitMapBackendError::IOError)?;
5783

5884
Ok(())
5985
}
6086
}
6187
}
6288

6389
enum Target<'a> {
90+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
6491
File(&'a Path),
65-
Buffer,
66-
#[cfg(feature = "gif")]
92+
Buffer(PhantomData<&'a u32>),
93+
#[cfg(all(feature = "gif", not(target_arch = "wasm32"), feature = "image"))]
6794
Gif(Box<gif_support::GifFile>),
6895
}
6996

7097
enum Buffer<'a> {
98+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
7199
Owned(Vec<u8>),
72100
Borrowed(&'a mut [u8]),
73101
}
74102

75103
impl<'a> Buffer<'a> {
76104
fn borrow_buffer(&mut self) -> &mut [u8] {
77105
match self {
106+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
78107
Buffer::Owned(buf) => &mut buf[..],
79108
Buffer::Borrowed(buf) => *buf,
80109
}
@@ -84,20 +113,19 @@ impl<'a> Buffer<'a> {
84113
/// The backend that drawing a bitmap
85114
pub struct BitMapBackend<'a> {
86115
/// The path to the image
116+
#[allow(dead_code)]
87117
target: Target<'a>,
88-
89118
/// The size of the image
90119
size: (u32, u32),
91-
92120
/// The data buffer of the image
93121
buffer: Buffer<'a>,
94-
95122
/// Flag indicates if the bitmap has been saved
96123
saved: bool,
97124
}
98125

99126
impl<'a> BitMapBackend<'a> {
100127
/// Create a new bitmap backend
128+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
101129
pub fn new<T: AsRef<Path> + ?Sized>(path: &'a T, (w, h): (u32, u32)) -> Self {
102130
Self {
103131
target: Target::File(path.as_ref()),
@@ -116,12 +144,12 @@ impl<'a> BitMapBackend<'a> {
116144
/// - `path`: The path to the GIF file to create
117145
/// - `dimension`: The size of the GIF image
118146
/// - `speed`: The amount of time for each frame to display
119-
#[cfg(feature = "gif")]
147+
#[cfg(all(feature = "gif", not(target_arch = "wasm32"), feature = "image"))]
120148
pub fn gif<T: AsRef<Path>>(
121149
path: T,
122150
(w, h): (u32, u32),
123151
frame_delay: u32,
124-
) -> Result<Self, ImageError> {
152+
) -> Result<Self, BitMapBackendError> {
125153
Ok(Self {
126154
target: Target::Gif(Box::new(gif_support::GifFile::new(
127155
path,
@@ -153,7 +181,7 @@ impl<'a> BitMapBackend<'a> {
153181
}
154182

155183
Self {
156-
target: Target::Buffer,
184+
target: Target::Buffer(PhantomData),
157185
size: (w, h),
158186
buffer: Buffer::Borrowed(buf),
159187
saved: false,
@@ -331,33 +359,41 @@ impl<'a> BitMapBackend<'a> {
331359
}
332360

333361
impl<'a> DrawingBackend for BitMapBackend<'a> {
334-
type ErrorType = ImageError;
362+
type ErrorType = BitMapBackendError;
335363

336364
fn get_size(&self) -> (u32, u32) {
337365
self.size
338366
}
339367

340-
fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<ImageError>> {
368+
fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
341369
self.saved = false;
342370
Ok(())
343371
}
344372

345-
fn present(&mut self) -> Result<(), DrawingErrorKind<ImageError>> {
373+
#[cfg(any(target_arch = "wasm32", not(feature = "image")))]
374+
fn present(&mut self) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
375+
Ok(())
376+
}
377+
378+
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
379+
fn present(&mut self) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
346380
let (w, h) = self.get_size();
347381
match &mut self.target {
348382
Target::File(path) => {
349383
if let Some(img) = BorrowedImage::from_raw(w, h, self.buffer.borrow_buffer()) {
350-
img.save(&path)
351-
.map_err(|x| DrawingErrorKind::DrawingError(ImageError::IoError(x)))?;
384+
img.save(&path).map_err(|x| {
385+
DrawingErrorKind::DrawingError(BitMapBackendError::IOError(x))
386+
})?;
352387
self.saved = true;
353388
Ok(())
354389
} else {
355-
Err(DrawingErrorKind::DrawingError(ImageError::DimensionError))
390+
Err(DrawingErrorKind::DrawingError(
391+
BitMapBackendError::InvalidBuffer,
392+
))
356393
}
357394
}
358-
Target::Buffer => Ok(()),
395+
Target::Buffer(_) => Ok(()),
359396

360-
#[cfg(feature = "gif")]
361397
Target::Gif(target) => {
362398
target
363399
.flush_frame(self.buffer.borrow_buffer())
@@ -372,7 +408,7 @@ impl<'a> DrawingBackend for BitMapBackend<'a> {
372408
&mut self,
373409
point: BackendCoord,
374410
color: &RGBAColor,
375-
) -> Result<(), DrawingErrorKind<ImageError>> {
411+
) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
376412
if point.0 < 0 || point.1 < 0 {
377413
return Ok(());
378414
}
@@ -474,10 +510,10 @@ impl<'a> DrawingBackend for BitMapBackend<'a> {
474510
fn blit_bitmap<'b>(
475511
&mut self,
476512
pos: BackendCoord,
477-
src: &'b image::ImageBuffer<image::Rgb<u8>, &'b [u8]>,
513+
(sw, sh): (u32, u32),
514+
src: &'b [u8],
478515
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
479516
let (dw, dh) = self.get_size();
480-
let (sw, sh) = src.dimensions();
481517

482518
let (x0, y0) = pos;
483519
let (x1, y1) = (x0 + sw as i32, y0 + sh as i32);
@@ -498,7 +534,7 @@ impl<'a> DrawingBackend for BitMapBackend<'a> {
498534
let mut dst = &mut self.get_raw_pixel_buffer()[dst_start..];
499535

500536
let src_start = 3 * ((sh as i32 + y0 - y1) * sw as i32 + (sw as i32 + x0 - x1)) as usize;
501-
let mut src = &(**src)[src_start..];
537+
let mut src = &src[src_start..];
502538

503539
if src_gap == 0 && dst_gap == 0 {
504540
chunk_size *= num_chunks;

src/drawing/backend_impl/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ mod svg;
33
#[cfg(feature = "svg")]
44
pub use self::svg::{svg_types, SVGBackend};
55

6-
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
76
mod bitmap;
8-
#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
97
pub use bitmap::BitMapBackend;
108

119
#[cfg(target_arch = "wasm32")]

src/drawing/backend_impl/svg.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,13 +288,13 @@ impl<'a> DrawingBackend for SVGBackend<'a> {
288288
fn blit_bitmap<'b>(
289289
&mut self,
290290
pos: BackendCoord,
291-
src: &'b image::ImageBuffer<image::Rgb<u8>, &'b [u8]>,
291+
(w, h): (u32, u32),
292+
src: &'b [u8],
292293
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
293294
use image::png::PNGEncoder;
294295
use svg::node::element::Image;
295296

296297
let mut data = vec![0; 0];
297-
let (w, h) = src.dimensions();
298298

299299
{
300300
let cursor = Cursor::new(&mut data);
@@ -303,7 +303,7 @@ impl<'a> DrawingBackend for SVGBackend<'a> {
303303

304304
let color = image::ColorType::RGB(8);
305305

306-
encoder.encode(&(**src)[..], w, h, color).map_err(|e| {
306+
encoder.encode(src, w, h, color).map_err(|e| {
307307
DrawingErrorKind::DrawingError(Error::new(
308308
std::io::ErrorKind::Other,
309309
format!("Image error: {}", e),

0 commit comments

Comments
 (0)