mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-14 06:42:20 +00:00
* M0: remove upstream trademark artwork from contributor fork
Use the existing document icon and a plain project label. Remove trademark
asset entries and regenerate attribution as required for modified forks.
Co-authored-by: OpenAI Codex <codex@openai.com>
* M7: group compatible PDF words and hide source text during editing
Join compatible words across text objects and subset-font spaces, recognize
component colours, and reuse subset fonts with numeric space positioning.
Render a read-only background with the selected glyphs removed while the
inline editor is open. Keep one frame and source line breaks, and reset
the layout width when switching paragraphs. Expose the same preview through page_render.
Add synthetic extraction, save/reopen, preview and UI regressions. Record
the remaining mixed-style paragraph and installed-font limitations.
Co-authored-by: OpenAI Codex <codex@openai.com>
* M7: preserve rich PDF regions and preview text edits in place
Group mixed source runs into complete visual regions, retain run styles and source encodings, and use validated embedded source faces in the inline editor. Preserve source baselines and show a single live frame as text grows or shrinks, backed by a read-only draft geometry tool.
Validation: strict workspace Clippy, workspace tests, all 30 WASM crates, asset and parity gates, licensed synthetic edit/save/reopen and desktop checks, and an opt-in four-page private-document regression.
Co-authored-by: OpenAI Codex <codex@openai.com>
* M7: keep cropped artwork from blocking text editing
Track page/path clipping separately from full image placement, use visible selection bounds, and prioritize text hit testing over overlapping artwork. Preserve fixed clips during image transformations and expose visible bounds through the headless tools.
Validation: strict workspace Clippy, workspace tests, 30 WASM crates, asset/parity gates, synthetic engine/tool/UI and native desktop checks, both private-document UI regressions, and all-page local edit/save/reopen/undo on a four-page cropped-artwork PDF.
Co-authored-by: OpenAI Codex <codex@openai.com>
* M7: resize cropped images with their clipping paths
Keep the visible frame and image pixels under the same transform. Preserve the
opposite corner and respond to diagonal, horizontal-only and vertical-only
corner drags without jumping from an off-centre grip. Refuse shared clipping
scopes that would move unrelated content.
Add synthetic engine/tool/UI regressions and opt-in private-file coverage
for 80 corner gestures and 10 grow/shrink save/reopen/undo render checks.
Co-authored-by: OpenAI Codex <codex@openai.com>
* M7: complete source font subsets and preserve clipped editing
Add explicit document fonts, CFF embedding, range formatting and bounded contextual shaping; isolate shared image clips and verify private Chinese edits on all pages.
Co-authored-by: OpenAI Codex <codex@openai.com>
* Revert "M0: remove upstream trademark artwork from contributor fork"
This reverts commit 3aa539b5b6.
* Test: give the text layer up to 4 s before copying (it flaked on a loaded machine)
---------
Co-authored-by: Kamoliddin Fatkhullaev <komoliddinfatxullayev@MacBook-Pro-Komoliddin.local>
Co-authored-by: OpenAI Codex <codex@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.6 KiB
Rust
67 lines
2.6 KiB
Rust
//! The page beneath an inline text editor, with the source glyphs removed on a COS clone.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use pdfcraft_render::{PageRenderer, RenderConfig, RenderPool, RenderRequest, RenderedPage};
|
|
|
|
use crate::{Document, guard};
|
|
|
|
pub struct TextEditPreview {
|
|
page: usize,
|
|
bytes: Arc<Vec<u8>>,
|
|
config: RenderConfig,
|
|
}
|
|
|
|
impl TextEditPreview {
|
|
pub fn renderer(&self) -> RenderPool {
|
|
RenderPool::new(self.bytes.clone(), 1, self.config.clone())
|
|
}
|
|
|
|
pub fn render_background(&self, scale: f32) -> Result<RenderedPage, String> {
|
|
if !scale.is_finite() || scale <= 0.0 {
|
|
return Err("preview scale must be finite and positive".into());
|
|
}
|
|
guard(|| {
|
|
let mut renderer = PageRenderer::new(self.bytes.clone(), self.config.clone());
|
|
let out = renderer.render(RenderRequest { page: self.page, scale, ..Default::default() });
|
|
if let Some(e) = &out.error {
|
|
return Err(e.clone());
|
|
}
|
|
Ok(out)
|
|
})?
|
|
}
|
|
}
|
|
|
|
impl Document {
|
|
/// Measure a draft without changing bytes, dirty state, or undo history.
|
|
pub fn text_edit_layout(
|
|
&self,
|
|
page: usize,
|
|
block: usize,
|
|
text: &str,
|
|
style: &pdfcraft_edit::BlockStyle,
|
|
) -> Result<pdfcraft_edit::text::TextEditLayout, String> {
|
|
guard(|| {
|
|
let editor = self.editor.as_ref().ok_or("the document can't be read")?;
|
|
pdfcraft_edit::text::text_edit_layout(&editor.cos, page, block, text, style).map_err(|e| e.to_string())
|
|
})?
|
|
}
|
|
|
|
/// Embedded source faces for a text editor, bounded and validated as sfnt programs.
|
|
/// This is read-only; no source font is installed or exported.
|
|
pub fn text_editor_fonts(&self, page: usize) -> Vec<pdfcraft_edit::text::TextEditorFont> {
|
|
self.editor.as_ref().and_then(|e| pdfcraft_edit::text::text_editor_fonts(&e.cos, page).ok()).unwrap_or_default()
|
|
}
|
|
|
|
/// Preparing the background never changes working bytes, dirty state or undo history.
|
|
pub fn text_edit_preview(&self, page: usize, block: usize) -> Result<TextEditPreview, String> {
|
|
guard(|| {
|
|
let editor = self.editor.as_ref().ok_or("the document can't be read")?;
|
|
let mut cos = editor.cos.clone();
|
|
pdfcraft_edit::clear_block(&mut cos, page, block).map_err(|e| e.to_string())?;
|
|
let bytes = Arc::new(pdfcraft_cos::write_incremental(&cos, &pdfcraft_cos::SaveOptions::default()).map_err(|e| e.to_string())?);
|
|
Ok(TextEditPreview { page, bytes, config: self.config.clone() })
|
|
})?
|
|
}
|
|
}
|