forked from 1b-agent/opencadstudio-upstream
1 parent
010d23fa95
commit
cba64631b8
5 files changed
+398
-97
No files matched your search
Generated
+280
-1
@@ -23,6 +23,7 @@ dependencies = [
|
||||
"fontdb",
|
||||
"getrandom 0.3.4",
|
||||
"glam",
|
||||
"hayro",
|
||||
"i18n-embed",
|
||||
"i18n-embed-fl",
|
||||
"iced",
|
||||
@@ -805,6 +806,17 @@ dependencies = [
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "8.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "5.0.3"
|
||||
@@ -1078,6 +1090,15 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ec7c5eb7a16992b1904d76c517d170ab353b0e0b3d5a0c81a8a0cd1037893cf"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
@@ -1692,6 +1713,12 @@ dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fearless_simd"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97b65636e5b9ef369943878ac74335ba1c55c1cb6adbf1e2c293c624248d693"
|
||||
|
||||
[[package]]
|
||||
name = "find-crate"
|
||||
version = "0.6.3"
|
||||
@@ -2080,6 +2107,23 @@ dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glifo"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d99fc21d493812643aae86d53b7bbd02f376434a90317e8a790bc209fdd6605e"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"foldhash 0.2.0",
|
||||
"hashbrown 0.17.1",
|
||||
"log",
|
||||
"peniko",
|
||||
"png 0.18.1",
|
||||
"skrifa 0.42.1",
|
||||
"smallvec",
|
||||
"vello_common 0.0.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.17.0"
|
||||
@@ -2151,6 +2195,15 @@ dependencies = [
|
||||
"svg_fmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "guillotiere"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab"
|
||||
dependencies = [
|
||||
"euclid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
@@ -2223,6 +2276,99 @@ name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
dependencies = [
|
||||
"foldhash 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hayro"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4caa128ab87fd48ffb7490617cf93f77f606820dffbc9fd9ef6ab0ed077f56d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"hayro-interpret",
|
||||
"image",
|
||||
"kurbo 0.13.1",
|
||||
"pic-scale",
|
||||
"vello_cpu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hayro-ccitt"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f4d0e94ddd48749f06bbe4e5389fb9799a0c45bcaf00495042076ef05e3241a"
|
||||
|
||||
[[package]]
|
||||
name = "hayro-cmap"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d285dc30731c8485de5fa732fbdf2b3affdf01e4da7c2135022ca6fa664bf6"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"hayro-postscript",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hayro-interpret"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2613d0406898995042d0794c4245b2f2fba1246490c8ac593769bba6551129d"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"hayro-cmap",
|
||||
"hayro-syntax",
|
||||
"kurbo 0.13.1",
|
||||
"moxcms",
|
||||
"phf",
|
||||
"rustc-hash 2.1.3",
|
||||
"siphasher",
|
||||
"skrifa 0.42.1",
|
||||
"smallvec",
|
||||
"yoke",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hayro-jbig2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69374b3668dd45aeb3d3145cda68f2c7b4f223aaa2511e67d076f1c7d741388d"
|
||||
dependencies = [
|
||||
"fearless_simd",
|
||||
"hayro-ccitt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hayro-jpeg2000"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75ab947623ef4ccaa7acf0579edf7cbb5a73838e3839a7be73335e522f433a1"
|
||||
dependencies = [
|
||||
"fearless_simd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hayro-postscript"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "885c5ef0654933139a9b9546fc2c69e18d37f38aa2520f079092b1be18f1fcaa"
|
||||
|
||||
[[package]]
|
||||
name = "hayro-syntax"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0edeafd70aa2db743de8ede8637d07ec87db05efe69cde371d03f1b185fcef27"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"hayro-ccitt",
|
||||
"hayro-jbig2",
|
||||
"hayro-jpeg2000",
|
||||
"memchr",
|
||||
"rustc-hash 2.1.3",
|
||||
"smallvec",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -2507,7 +2653,7 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"cryoglyph",
|
||||
"futures",
|
||||
"guillotiere",
|
||||
"guillotiere 0.6.2",
|
||||
"iced_debug",
|
||||
"iced_graphics",
|
||||
"log",
|
||||
@@ -2991,6 +3137,18 @@ dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kurbo"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"euclid",
|
||||
"polycool",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -4140,6 +4298,19 @@ dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peniko"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "839c8299360d2e998bdb106dc0a6cd71dcc5f4df51df1b620361bf50e283cca6"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"color",
|
||||
"kurbo 0.13.1",
|
||||
"linebender_resource_handle",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
@@ -4157,6 +4328,58 @@ dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pic-scale"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6edb0ff645d35accaec252de081d55984a0d6c952cb1e5dc2b9afa7c78f07288"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pico-args"
|
||||
version = "0.5.0"
|
||||
@@ -4264,6 +4487,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
|
||||
|
||||
[[package]]
|
||||
name = "polycool"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
@@ -6167,6 +6399,53 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vello_common"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3361bff7f7d82c0c496b92048db83846691f0e844cc28dee92b1c824291b55ee"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"fearless_simd",
|
||||
"guillotiere 0.7.0",
|
||||
"hashbrown 0.17.1",
|
||||
"log",
|
||||
"peniko",
|
||||
"png 0.18.1",
|
||||
"smallvec",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vello_common"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d672facaa2d697285a786cd9d44d614cd2ce54cdc022504bf339f8fff3b750"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"fearless_simd",
|
||||
"guillotiere 0.7.0",
|
||||
"hashbrown 0.17.1",
|
||||
"log",
|
||||
"peniko",
|
||||
"png 0.18.1",
|
||||
"smallvec",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vello_cpu"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d8ded630e8316bb94a55881256506d1f3b9947b5f66db8a7d32ca7ba02decd0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"glifo",
|
||||
"hashbrown 0.17.1",
|
||||
"png 0.18.1",
|
||||
"vello_common 0.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
|
||||
@@ -37,6 +37,7 @@ cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git",
|
||||
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
||||
flate2 = "1"
|
||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
||||
hayro = "0.7.1"
|
||||
# Rasterises assets/logo.svg into the window icon at startup, so the taskbar
|
||||
# icon comes from the same file every other build target does. Already in the
|
||||
# tree behind iced's svg feature; named here only to use it directly.
|
||||
|
||||
+1
-1
@@ -3397,7 +3397,7 @@ pub enum Message {
|
||||
/// Open file-picker dialog for PDFATTACH command (async).
|
||||
PdfAttachPick,
|
||||
/// Result of the PDFATTACH file picker.
|
||||
PdfAttachPickResult(Result<std::path::PathBuf, String>),
|
||||
PdfAttachPickResult(Result<(std::path::PathBuf, std::sync::Arc<Vec<u8>>), String>),
|
||||
|
||||
// ── XREF ──────────────────────────────────────────────────────────────
|
||||
/// Open file-picker dialog for XATTACH command (async).
|
||||
|
||||
@@ -953,20 +953,25 @@ impl OpenCADStudio {
|
||||
.await;
|
||||
|
||||
match handle {
|
||||
Some(h) => Ok(crate::sys::handle_path(&h)),
|
||||
Some(h) => {
|
||||
let path = crate::sys::handle_path(&h);
|
||||
let bytes = std::sync::Arc::new(h.read().await);
|
||||
Ok((path, bytes))
|
||||
}
|
||||
None => Err("Cancelled".to_string()),
|
||||
}
|
||||
},
|
||||
Message::PdfAttachPickResult,
|
||||
),
|
||||
|
||||
Message::PdfAttachPickResult(Ok(path)) => {
|
||||
Message::PdfAttachPickResult(Ok((path, bytes))) => {
|
||||
use acadrust::objects::{ObjectType, UnderlayDefinition};
|
||||
use crate::command::CadCommand;
|
||||
use crate::modules::insert::pdf_attach::PdfAttachCommand;
|
||||
|
||||
let i = self.active_tab;
|
||||
let path_str = path.to_string_lossy().into_owned();
|
||||
crate::scene::model::pdf_raster::register_source(&path_str, bytes);
|
||||
|
||||
let definition_handle = self.tabs[i].scene.document.allocate_handle();
|
||||
|
||||
|
||||
+109
-93
@@ -1,19 +1,14 @@
|
||||
// PDF underlay rasterisation.
|
||||
//
|
||||
// No PDF crate: the page renders through the system `pdftoppm` (poppler-utils
|
||||
// — present on virtually every Linux desktop, installable on Windows/macOS)
|
||||
// into a temp PNG, which decodes through the existing `image` dependency.
|
||||
// When the tool is missing the caller falls back to the underlay's outline
|
||||
// placeholder, so the feature degrades instead of failing the load.
|
||||
//
|
||||
// Pages are cached per (resolved path, page name): underlays re-tessellate on
|
||||
// every geometry bump, but the expensive external render runs once.
|
||||
//! Cross-platform PDF underlay rasterisation.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
|
||||
/// One rasterised PDF page. `dpi` ties the pixel size back to the page's
|
||||
/// physical size: `inches = px / dpi`, which is what the underlay's world
|
||||
/// quad is sized from (1 underlay unit = 1 PDF inch, AutoCAD's convention).
|
||||
use hayro::hayro_interpret::InterpreterSettings;
|
||||
use hayro::hayro_syntax::Pdf;
|
||||
use hayro::vello_cpu::color::palette::css::WHITE;
|
||||
use hayro::{RenderCache, RenderSettings};
|
||||
|
||||
/// One rasterised PDF page. `dpi` ties its pixel size to its physical size.
|
||||
pub struct PdfPage {
|
||||
pub pixels: Arc<Vec<u8>>,
|
||||
pub width: u32,
|
||||
@@ -21,98 +16,119 @@ pub struct PdfPage {
|
||||
pub dpi: f32,
|
||||
}
|
||||
|
||||
/// Raster resolution. 150 dpi puts an A4 page at ~1240×1754 px — crisp for
|
||||
/// normal zooms without ballooning texture memory.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
const RASTER_DPI: u32 = 150;
|
||||
const RASTER_DPI: f32 = 150.0;
|
||||
|
||||
/// Rasterise `page` (a 1-based page name, e.g. "1") of the PDF at `path`.
|
||||
/// `None` when the file/page can't be rendered (missing file, no pdftoppm,
|
||||
/// bad page) — negative results are cached too, so a missing tool doesn't
|
||||
/// re-spawn a process per tessellation.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
type PageKey = (String, String);
|
||||
|
||||
fn page_cache() -> &'static Mutex<HashMap<PageKey, Option<Arc<PdfPage>>>> {
|
||||
static CACHE: OnceLock<Mutex<HashMap<PageKey, Option<Arc<PdfPage>>>>> = OnceLock::new();
|
||||
CACHE.get_or_init(|| Mutex::new(HashMap::new()))
|
||||
}
|
||||
|
||||
fn source_cache() -> &'static Mutex<HashMap<String, Arc<Vec<u8>>>> {
|
||||
static SOURCES: OnceLock<Mutex<HashMap<String, Arc<Vec<u8>>>>> = OnceLock::new();
|
||||
SOURCES.get_or_init(|| Mutex::new(HashMap::new()))
|
||||
}
|
||||
|
||||
/// Keep bytes selected through a file dialog. Browsers expose no reusable path,
|
||||
/// while native builds also benefit by avoiding a second disk read.
|
||||
pub fn register_source(path: &str, bytes: Arc<Vec<u8>>) {
|
||||
source_cache()
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner())
|
||||
.insert(path.to_string(), bytes);
|
||||
page_cache()
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner())
|
||||
.retain(|(cached_path, _), _| cached_path != path);
|
||||
}
|
||||
|
||||
/// Rasterise a 1-based PDF page, memoised by source path and page name.
|
||||
pub fn rasterize_page(path: &str, page: &str) -> Option<Arc<PdfPage>> {
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
static CACHE: OnceLock<Mutex<HashMap<(String, String), Option<Arc<PdfPage>>>>> =
|
||||
OnceLock::new();
|
||||
let cache = CACHE.get_or_init(|| Mutex::new(HashMap::new()));
|
||||
|
||||
let key = (path.to_string(), page.to_string());
|
||||
if let Ok(c) = cache.lock() {
|
||||
if let Some(hit) = c.get(&key) {
|
||||
return hit.clone();
|
||||
}
|
||||
if let Some(hit) = page_cache()
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner())
|
||||
.get(&key)
|
||||
.cloned()
|
||||
{
|
||||
return hit;
|
||||
}
|
||||
|
||||
let built = rasterize_uncached(path, page);
|
||||
if let Ok(mut c) = cache.lock() {
|
||||
c.insert(key, built.clone());
|
||||
}
|
||||
page_cache()
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner())
|
||||
.insert(key, built.clone());
|
||||
built
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn rasterize_uncached(path: &str, page: &str) -> Option<Arc<PdfPage>> {
|
||||
use std::process::Command;
|
||||
|
||||
if !std::path::Path::new(path).is_file() {
|
||||
return None;
|
||||
}
|
||||
let page_no: u32 = page.trim().parse().unwrap_or(1).max(1);
|
||||
|
||||
// Unique output prefix in the system temp dir; pdftoppm appends
|
||||
// `-<page>` (with version-dependent zero padding) and `.png`.
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
use std::hash::{Hash, Hasher};
|
||||
(path, page_no).hash(&mut hasher);
|
||||
let prefix = std::env::temp_dir().join(format!("ocs_pdf_{:016x}", hasher.finish()));
|
||||
let prefix_str = prefix.to_string_lossy().into_owned();
|
||||
|
||||
let status = Command::new("pdftoppm")
|
||||
.args([
|
||||
"-png",
|
||||
"-r",
|
||||
&RASTER_DPI.to_string(),
|
||||
"-f",
|
||||
&page_no.to_string(),
|
||||
"-l",
|
||||
&page_no.to_string(),
|
||||
path,
|
||||
&prefix_str,
|
||||
])
|
||||
.status()
|
||||
.ok()?;
|
||||
if !status.success() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Find the produced file: `<prefix>-1.png`, `-01.png`, … depending on the
|
||||
// poppler version's padding.
|
||||
let dir = prefix.parent()?;
|
||||
let stem = prefix.file_name()?.to_string_lossy().into_owned();
|
||||
let mut produced: Option<std::path::PathBuf> = None;
|
||||
for entry in std::fs::read_dir(dir).ok()?.flatten() {
|
||||
let name = entry.file_name().to_string_lossy().into_owned();
|
||||
if name.starts_with(&stem) && name.ends_with(".png") {
|
||||
produced = Some(entry.path());
|
||||
break;
|
||||
}
|
||||
}
|
||||
let png = produced?;
|
||||
let decoded = image::open(&png).ok()?.to_rgba8();
|
||||
let _ = std::fs::remove_file(&png);
|
||||
let (width, height) = decoded.dimensions();
|
||||
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 = hayro::render(
|
||||
page,
|
||||
&RenderCache::new(),
|
||||
&InterpreterSettings::default(),
|
||||
&RenderSettings {
|
||||
x_scale: scale,
|
||||
y_scale: scale,
|
||||
bg_color: WHITE,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let width = u32::from(pixmap.width());
|
||||
let height = u32::from(pixmap.height());
|
||||
Some(Arc::new(PdfPage {
|
||||
pixels: Arc::new(decoded.into_raw()),
|
||||
pixels: Arc::new(pixmap.data_as_u8_slice().to_vec()),
|
||||
width,
|
||||
height,
|
||||
dpi: RASTER_DPI as f32,
|
||||
dpi: RASTER_DPI,
|
||||
}))
|
||||
}
|
||||
|
||||
/// wasm: no external process — underlays keep their outline placeholder.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn rasterize_page(_path: &str, _page: &str) -> Option<Arc<PdfPage>> {
|
||||
None
|
||||
fn source_bytes(path: &str) -> Option<Arc<Vec<u8>>> {
|
||||
if let Some(bytes) = source_cache()
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner())
|
||||
.get(path)
|
||||
.cloned()
|
||||
{
|
||||
return Some(bytes);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
std::fs::read(path).ok().map(Arc::new)
|
||||
}
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_arch = "wasm32")))]
|
||||
mod tests {
|
||||
use printpdf::{Mm, PdfDocument, PdfPage as OutputPage, PdfSaveOptions};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn registered_pdf_bytes_render_without_a_filesystem_path() {
|
||||
let mut document = PdfDocument::new("PDF underlay test");
|
||||
document
|
||||
.pages
|
||||
.push(OutputPage::new(Mm(25.4), Mm(25.4), Vec::new()));
|
||||
let bytes = document.save(&PdfSaveOptions::default(), &mut Vec::new());
|
||||
let path = "memory://pdf-underlay-test.pdf";
|
||||
|
||||
register_source(path, Arc::new(bytes));
|
||||
let page = rasterize_page(path, "1").expect("registered PDF should render");
|
||||
|
||||
assert_eq!((page.width, page.height), (150, 150));
|
||||
assert_eq!(page.pixels.len(), 150 * 150 * 4);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user