mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 17:56:50 -06:00
Merge pull request #2988 from 00xJS/fix/2675-pdf-invisible-text
PDF import: say when invisible text is left out (part of #2675)
This commit is contained in:
@@ -149,6 +149,10 @@ pub const PAST_PAGE_NOTE: &str = "art reaching past the page was clipped to it,
|
||||
|
||||
/// Warning: glyphs were kept as outlines rather than read as type.
|
||||
pub const OUTLINED_TEXT_NOTE: &str = "text was converted to outlines";
|
||||
/// Warning: text drawn invisibly (text rendering mode 3, as a scanned page's OCR layer is) was left
|
||||
/// out: VectorCraft has no type that is kept but not drawn, so a PDF saved from it loses that
|
||||
/// searchable text (#2675).
|
||||
pub const INVISIBLE_TEXT_NOTE: &str = "invisible text (such as a scanned page's searchable OCR layer) was left out";
|
||||
/// Warning: glyphs that differ from the installed font of their name were kept as outlines.
|
||||
pub const UNMATCHED_GLYPHS_NOTE: &str = "text whose glyphs differ from the installed font of the same name was kept as outlines";
|
||||
/// The end of the warning that glyphs whose characters the file doesn't name were kept as
|
||||
@@ -1963,7 +1967,10 @@ impl<'a> Device<'a> for Builder<'_> {
|
||||
) {
|
||||
self.pending = false;
|
||||
let stroke = match draw_mode {
|
||||
GlyphDrawMode::Invisible => return,
|
||||
GlyphDrawMode::Invisible => {
|
||||
self.warn(INVISIBLE_TEXT_NOTE);
|
||||
return;
|
||||
}
|
||||
GlyphDrawMode::Fill => None,
|
||||
GlyphDrawMode::Stroke(p) => Some(p.clone()),
|
||||
};
|
||||
|
||||
@@ -74,8 +74,8 @@ pub use encrypt::Encryption;
|
||||
pub use export::{export, export_with_report, page_areas};
|
||||
pub use file_info::{FileInfo, file_info};
|
||||
pub use import::{
|
||||
OFF_ARTBOARD_NOTE, OUTLINED_TEXT_NOTE, PAST_PAGE_NOTE, UNMATCHED_GLYPHS_NOTE, UNNAMED_CHARACTERS_NOTE, holds_outlines, import,
|
||||
import_with_report, is_glyph_outlines, is_outlines_note,
|
||||
INVISIBLE_TEXT_NOTE, OFF_ARTBOARD_NOTE, OUTLINED_TEXT_NOTE, PAST_PAGE_NOTE, UNMATCHED_GLYPHS_NOTE, UNNAMED_CHARACTERS_NOTE, holds_outlines,
|
||||
import, import_with_report, is_glyph_outlines, is_outlines_note,
|
||||
};
|
||||
pub use pages::{PageInfo, PdfInfo, has_illustrator_data, illustrator_data, info, is_postscript};
|
||||
pub use post::{THUMBNAIL_SIZE, Thumbnail};
|
||||
|
||||
@@ -177,3 +177,36 @@ pub(crate) fn transfer_contract() {
|
||||
fn soft_mask_inversion_uses_quantized_transfer_endpoints() {
|
||||
transfer_contract();
|
||||
}
|
||||
|
||||
/// #2675: text in rendering mode 3 (invisible, as a scanned page's OCR layer) isn't kept, and the
|
||||
/// import now says so, for type and outlines alike. Visible text beside it still comes in, and a
|
||||
/// page without invisible text gets no such warning.
|
||||
#[test]
|
||||
fn invisible_text_is_reported_when_left_out() {
|
||||
let open = |content: &str, text_as: TextAs| import_with_report(&text_pdf(content), &ImportOptions { text_as, ..Default::default() }).unwrap();
|
||||
let invisible = "BT /F1 20 Tf 3 Tr 1 0 0 1 10 40 Tm (AB) Tj 0 Tr 1 0 0 1 10 10 Tm (CA) Tj ET";
|
||||
for text_as in [TextAs::Text, TextAs::Outlines] {
|
||||
let r = open(invisible, text_as);
|
||||
assert!(r.warnings.iter().any(|w| w == crate::INVISIBLE_TEXT_NOTE), "{text_as:?}: {:?}", r.warnings);
|
||||
// What came in: the type's text, and where the art lies. On the 60 pt page the visible
|
||||
// line (baseline 10 pt up) lies 35–50 pt down, the invisible one (40 pt up) 5–20 pt down.
|
||||
let (mut text, mut tops) = (String::new(), vec![]);
|
||||
r.document.walk(|n| {
|
||||
if let NodeKind::Text(t) = &n.kind {
|
||||
text.push_str(&t.plain_text());
|
||||
}
|
||||
if matches!(n.kind, NodeKind::Text(_) | NodeKind::Path { .. } | NodeKind::Compound { .. })
|
||||
&& let Some(b) = n.visual_bounds()
|
||||
{
|
||||
tops.push(b.y0);
|
||||
}
|
||||
});
|
||||
if text_as == TextAs::Text {
|
||||
assert!(text.contains("CA") && !text.contains("AB"), "{text_as:?}: {text:?}");
|
||||
}
|
||||
assert!(!tops.is_empty(), "{text_as:?}: the visible line still comes in");
|
||||
assert!(tops.iter().all(|y| *y > 25.0), "{text_as:?}: only the visible line's art, tops at {tops:?}");
|
||||
let visible = open("BT /F1 20 Tf 1 0 0 1 10 10 Tm (CA) Tj ET", text_as);
|
||||
assert!(!visible.warnings.iter().any(|w| w == crate::INVISIBLE_TEXT_NOTE), "{text_as:?}: {:?}", visible.warnings);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user