mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 02:27:08 -06:00
Merge pull request #1193 from MarekSpodBiedry/issue-1178
This commit is contained in:
+12
-2
@@ -66,7 +66,7 @@ pub enum PageLayout {
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
pub struct PdfOptions {
|
||||
pub layout: PageLayout,
|
||||
/// Raster resolution of slide artwork (dots per inch).
|
||||
/// Raster resolution of slide artwork (dots per inch), lowered for a slide whose raster would pass 64M pixels.
|
||||
pub dpi: f64,
|
||||
/// Slide indices to export (0-based); `None` = all.
|
||||
pub slides: Option<Vec<usize>>,
|
||||
@@ -423,6 +423,16 @@ fn backdrop(mut img: deckcraft_render::Image) -> Image {
|
||||
Image::from_rgba8(img.pixels, img.width, img.height)
|
||||
}
|
||||
|
||||
/// Most pixels one slide raster may have; it is RGBA, and the backdrop and the content are two rasters.
|
||||
const MAX_RASTER_PIXELS: f64 = 64_000_000.0;
|
||||
|
||||
/// Render scale for a slide of `slide` units drawn `box_width` points wide at `dpi`, with the total pixel count capped.
|
||||
fn raster_scale(box_width: f64, slide: (f64, f64), dpi: f64) -> f64 {
|
||||
let scale = (box_width / 72.0 * dpi.clamp(36.0, 600.0)) / slide.0;
|
||||
let pixels = slide.0 * scale * slide.1 * scale;
|
||||
if pixels > MAX_RASTER_PIXELS { scale * (MAX_RASTER_PIXELS / pixels).sqrt() } else { scale }
|
||||
}
|
||||
|
||||
impl Exporter<'_> {
|
||||
fn font(&mut self, face: &deckcraft_fonts::FontFace) -> Result<Font> {
|
||||
if let Some(font) = self.fonts.get(&face.id()) {
|
||||
@@ -439,7 +449,7 @@ impl Exporter<'_> {
|
||||
let (sw, sh) = (pres.slide_size.width.max(1.0), pres.slide_size.height.max(1.0));
|
||||
let k = b.width() / sw;
|
||||
// Raster at the requested dpi relative to the box size on paper.
|
||||
let scale = (b.width() / 72.0 * self.opts.dpi.clamp(36.0, 600.0)) / sw;
|
||||
let scale = raster_scale(b.width(), (sw, sh), self.opts.dpi);
|
||||
let ropts = RenderOpts { scale, threads: 4, ..Default::default() };
|
||||
// Two rasters per slide: the backdrop (background, master and layout graphics) is the same
|
||||
// on every slide that shares its layout, so the writer stores it once, and the slide's own
|
||||
|
||||
@@ -530,3 +530,14 @@ fn glyph_ranges_follow_shaping_clusters() {
|
||||
// A run starting mid-paragraph, multi-byte characters in visual (right-to-left) order.
|
||||
assert_eq!(glyph_text_ranges("αβγ", (3, 6), &[(5, 'γ'), (4, 'β'), (3, 'α')], 3), vec![4..6, 2..4, 0..2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn raster_scale_caps_total_pixels_not_each_side() {
|
||||
// A huge square slide at 600 dpi would be 16,000 x 16,000 px (~1 GB RGBA) without the cap.
|
||||
let s = raster_scale(20_000.0, (20_000.0, 20_000.0), 600.0);
|
||||
let px = 20_000.0 * s * 20_000.0 * s;
|
||||
assert!(px <= MAX_RASTER_PIXELS * 1.0001, "{px}");
|
||||
// A normal slide keeps the requested dpi.
|
||||
let s = raster_scale(720.0, (960.0, 540.0), 200.0);
|
||||
assert!((s - 720.0 / 72.0 * 200.0 / 960.0).abs() < 1e-12);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user