Skip to content

Commit 62379e9

Browse files
committed
#241 Add macOS-specific fixes and tests for Kaleido compatibility
Introduce macOS-specific arguments for Kaleido to address issue #323. Add new tests to validate image generation (e.g., PNG, JPEG, SVG, PDF) on macOS, ensuring proper functionality. This improves cross-platform support and resolves inconsistencies in the Kaleido backend. issue: #241
1 parent b05315f commit 62379e9

File tree

2 files changed

+171
-14
lines changed

2 files changed

+171
-14
lines changed

plotly/src/plot.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,7 @@ impl PartialEq for Plot {
586586
mod tests {
587587
use std::path::PathBuf;
588588

589-
#[cfg(feature = "kaleido")]
590-
use base64::{engine::general_purpose, Engine as _};
589+
591590
use serde_json::{json, to_value};
592591

593592
use super::*;
@@ -866,4 +865,31 @@ mod tests {
866865
const LEN: usize = 10;
867866
assert_eq!(expected[..LEN], image_svg[..LEN]);
868867
}
868+
869+
#[cfg(target_os = "macos")]
870+
#[test]
871+
#[cfg(feature = "kaleido")]
872+
fn save_surface_to_png() {
873+
use crate::Surface;
874+
let mut plot = Plot::new();
875+
let z_matrix = vec![
876+
vec![1.0, 2.0, 3.0],
877+
vec![4.0, 5.0, 6.0],
878+
vec![7.0, 8.0, 9.0],
879+
];
880+
let x_unique = vec![1.0, 2.0, 3.0];
881+
let y_unique = vec![4.0, 5.0, 6.0];
882+
let surface = Surface::new(z_matrix)
883+
.x(x_unique)
884+
.y(y_unique)
885+
.name("Surface");
886+
887+
plot.add_trace(surface);
888+
let dst = PathBuf::from("example.png");
889+
plot.write_image("example.png", ImageFormat::PNG, 800, 600, 1.0);
890+
assert!(dst.exists());
891+
assert!(std::fs::remove_file(&dst).is_ok());
892+
assert!(!dst.exists());
893+
assert!(!plot.to_base64(ImageFormat::PNG, 1024, 680, 1.0).is_empty());
894+
}
869895
}

plotly_kaleido/src/lib.rs

Lines changed: 143 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,20 +185,34 @@ impl Kaleido {
185185
) -> Result<String, Box<dyn std::error::Error>> {
186186
let p = self.cmd_path.to_str().unwrap();
187187

188+
#[cfg(not(target_os = "macos"))]
189+
let cmd_args = vec![
190+
"plotly",
191+
"--disable-gpu",
192+
"--allow-file-access-from-files",
193+
"--disable-breakpad",
194+
"--disable-dev-shm-usage",
195+
"--disable-software-rasterizer",
196+
"--single-process",
197+
"--no-sandbox",
198+
];
199+
200+
// Add Kaleido issue #323
201+
#[cfg(target_os = "macos")]
202+
let cmd_args = vec![
203+
"plotly",
204+
"--allow-file-access-from-files",
205+
"--disable-breakpad",
206+
"--disable-dev-shm-usage",
207+
"--disable-software-rasterizer",
208+
"--single-process",
209+
"--no-sandbox",
210+
];
211+
188212
#[allow(clippy::zombie_processes)]
189213
let mut process = Command::new(p)
190214
.current_dir(self.cmd_path.parent().unwrap())
191-
.args([
192-
"plotly",
193-
"--disable-gpu",
194-
"--allow-file-access-from-files",
195-
"--disable-breakpad",
196-
"--disable-dev-shm-usage",
197-
"--disable-software-rasterizer",
198-
"--single-process",
199-
"--disable-gpu",
200-
"--no-sandbox",
201-
])
215+
.args(cmd_args)
202216
.stdin(Stdio::piped())
203217
.stdout(Stdio::piped())
204218
.stderr(Stdio::piped())
@@ -210,10 +224,11 @@ impl Kaleido {
210224
"failed to spawn Kaleido binary at {}",
211225
self.cmd_path.to_string_lossy()
212226
)
213-
.to_string()
227+
.to_string()
214228
)
215229
});
216230

231+
217232
{
218233
let plot_data = PlotData::new(plotly_data, format, width, height, scale).to_json();
219234
let mut process_stdin = process.stdin.take().unwrap();
@@ -287,6 +302,46 @@ mod tests {
287302
.unwrap()
288303
}
289304

305+
fn create_test_surface() -> Value {
306+
to_value(json!({
307+
"data": [
308+
{
309+
"name": "Surface",
310+
"type": "surface",
311+
"x": [
312+
1.0,
313+
2.0,
314+
3.0
315+
],
316+
"y": [
317+
4.0,
318+
5.0,
319+
6.0
320+
],
321+
"z": [
322+
[
323+
1.0,
324+
2.0,
325+
3.0
326+
],
327+
[
328+
4.0,
329+
5.0,
330+
6.0
331+
],
332+
[
333+
7.0,
334+
8.0,
335+
9.0
336+
]
337+
]
338+
}
339+
],
340+
"layout": {}
341+
}))
342+
.unwrap()
343+
}
344+
290345
#[test]
291346
fn can_find_kaleido_executable() {
292347
let _k = Kaleido::new();
@@ -378,4 +433,80 @@ mod tests {
378433
assert!(r.is_ok());
379434
assert!(std::fs::remove_file(dst.as_path()).is_ok());
380435
}
436+
437+
// Issue #241 workaround until https://github.com/plotly/Kaleido/issues/323 is resolved
438+
#[cfg(target_os = "macos")]
439+
#[test]
440+
fn save_surface_png() {
441+
let test_plot = create_test_surface();
442+
let k = Kaleido::new();
443+
let dst = PathBuf::from("example.png");
444+
let r = k.save(dst.as_path(), &test_plot, "png", 1200, 900, 4.5);
445+
assert!(r.is_ok());
446+
assert!(dst.exists());
447+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
448+
let file_size = metadata.len();
449+
assert!(file_size > 0,);
450+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
451+
}
452+
453+
#[cfg(target_os = "macos")]
454+
#[test]
455+
fn save_surface_jpeg() {
456+
let test_plot = create_test_surface();
457+
let k = Kaleido::new();
458+
let dst = PathBuf::from("example.jpeg");
459+
let r = k.save(dst.as_path(), &test_plot, "jpeg", 1200, 900, 4.5);
460+
assert!(r.is_ok());
461+
assert!(dst.exists());
462+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
463+
let file_size = metadata.len();
464+
assert!(file_size > 0,);
465+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
466+
}
467+
468+
#[cfg(target_os = "macos")]
469+
#[test]
470+
fn save_surface_webp() {
471+
let test_plot = create_test_surface();
472+
let k = Kaleido::new();
473+
let dst = PathBuf::from("example.webp");
474+
let r = k.save(dst.as_path(), &test_plot, "webp", 1200, 900, 4.5);
475+
assert!(r.is_ok());
476+
assert!(dst.exists());
477+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
478+
let file_size = metadata.len();
479+
assert!(file_size > 0,);
480+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
481+
}
482+
483+
#[cfg(target_os = "macos")]
484+
#[test]
485+
fn save_surface_svg() {
486+
let test_plot = create_test_surface();
487+
let k = Kaleido::new();
488+
let dst = PathBuf::from("example.svg");
489+
let r = k.save(dst.as_path(), &test_plot, "svg", 1200, 900, 4.5);
490+
assert!(r.is_ok());
491+
assert!(dst.exists());
492+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
493+
let file_size = metadata.len();
494+
assert!(file_size > 0,);
495+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
496+
}
497+
498+
#[cfg(target_os = "macos")]
499+
#[test]
500+
fn save_surface_pdf() {
501+
let test_plot = create_test_surface();
502+
let k = Kaleido::new();
503+
let dst = PathBuf::from("example.pdf");
504+
let r = k.save(dst.as_path(), &test_plot, "pdf", 1200, 900, 4.5);
505+
assert!(r.is_ok());
506+
assert!(dst.exists());
507+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
508+
let file_size = metadata.len();
509+
assert!(file_size > 0,);
510+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
511+
}
381512
}

0 commit comments

Comments
 (0)