forked from 1b-agent/opencadstudio-upstream
web: render plot preview in-page instead of a new tab
AutoCAD's plot preview renders the plotted result on screen instead of producing a file. The web build now does the same: the plotted PDF bytes are rasterised with the hayro pipeline already used for PDF underlays (150 DPI, first 12 pages) and shown in an in-page overlay with Download-PDF and Close actions. The previous strategy opened a new tab via window.open from the async plot task; browsers withhold popups without a live user gesture, and embedded hosts ship no PDF viewer plugin at all — so the fallback download fired and preview behaved like an export. Plain PNG <img> elements need neither permission.
This commit is contained in:
1 parent
e3c86eca29
commit
8722d84910
3 files changed
+277
-102
No files matched your search
@@ -67,8 +67,30 @@ fn rasterize_uncached(path: &str, page: &str) -> Option<Arc<PdfPage>> {
|
||||
let bytes = source_bytes(path)?;
|
||||
let pdf = Pdf::new(bytes).ok()?;
|
||||
let page_no = page.trim().parse::<usize>().unwrap_or(1).max(1);
|
||||
let page = pdf.pages().get(page_no - 1)?;
|
||||
let scale = RASTER_DPI / 72.0;
|
||||
let pixmap = raster_page(&pdf, page_no - 1, RASTER_DPI)?;
|
||||
let RasterizedPage {
|
||||
pixels,
|
||||
width,
|
||||
height,
|
||||
} = pixmap;
|
||||
Some(Arc::new(PdfPage {
|
||||
pixels,
|
||||
width,
|
||||
height,
|
||||
dpi: RASTER_DPI,
|
||||
}))
|
||||
}
|
||||
|
||||
struct RasterizedPage {
|
||||
pixels: Arc<Vec<u8>>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
/// Rasterise one 0-based page index at `dpi` onto a white background.
|
||||
fn raster_page(pdf: &Pdf, index: usize, dpi: f32) -> Option<RasterizedPage> {
|
||||
let page = pdf.pages().get(index)?;
|
||||
let scale = dpi / 72.0;
|
||||
let pixmap = hayro::render(
|
||||
page,
|
||||
&RenderCache::new(),
|
||||
@@ -80,14 +102,32 @@ fn rasterize_uncached(path: &str, page: &str) -> Option<Arc<PdfPage>> {
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let width = u32::from(pixmap.width());
|
||||
let height = u32::from(pixmap.height());
|
||||
Some(Arc::new(PdfPage {
|
||||
Some(RasterizedPage {
|
||||
pixels: Arc::new(pixmap.data_as_u8_slice().to_vec()),
|
||||
width,
|
||||
height,
|
||||
dpi: RASTER_DPI,
|
||||
}))
|
||||
width: u32::from(pixmap.width()),
|
||||
height: u32::from(pixmap.height()),
|
||||
})
|
||||
}
|
||||
|
||||
/// One-shot rasterisation of freshly generated PDF bytes (plot preview).
|
||||
/// Uncached: the bytes differ on every plot, so a cache would only grow.
|
||||
/// Returns at most `max_pages` pages; larger plots preview their first pages.
|
||||
pub fn rasterize_bytes_pages(bytes: Arc<Vec<u8>>, dpi: f32, max_pages: usize) -> Vec<Arc<PdfPage>> {
|
||||
let Ok(pdf) = Pdf::new(bytes) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let count = pdf.pages().len().min(max_pages);
|
||||
(0..count)
|
||||
.filter_map(|index| {
|
||||
let page = raster_page(&pdf, index, dpi)?;
|
||||
Some(Arc::new(PdfPage {
|
||||
pixels: page.pixels,
|
||||
width: page.width,
|
||||
height: page.height,
|
||||
dpi,
|
||||
}))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn source_bytes(path: &str) -> Option<Arc<Vec<u8>>> {
|
||||
@@ -131,4 +171,23 @@ mod tests {
|
||||
assert_eq!((page.width, page.height), (150, 150));
|
||||
assert_eq!(page.pixels.len(), 150 * 150 * 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_pages_render_every_page_up_to_the_cap() {
|
||||
let mut document = PdfDocument::new("multi-page");
|
||||
for _ in 0..3 {
|
||||
document
|
||||
.pages
|
||||
.push(OutputPage::new(Mm(50.8), Mm(25.4), Vec::new()));
|
||||
}
|
||||
let bytes = Arc::new(document.save(&PdfSaveOptions::default(), &mut Vec::new()));
|
||||
|
||||
let all = rasterize_bytes_pages(bytes.clone(), 72.0, 10);
|
||||
assert_eq!(all.len(), 3);
|
||||
assert_eq!((all[0].width, all[0].height), (144, 72));
|
||||
assert_eq!(all[0].dpi, 72.0);
|
||||
|
||||
let capped = rasterize_bytes_pages(bytes, 72.0, 2);
|
||||
assert_eq!(capped.len(), 2);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user