mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-15 15:22:54 +00:00
Export: pin merged RTF writer and preserve empty-page breaks
Use the merged craft-libs #1467 commit for craft-rtf and its codepage dependency, leaving other shared pins unchanged. Flush pending breaks before a second break and at end of input so blank and omitted-image pages retain every boundary. Add semantic readback coverage for those cases.
This commit is contained in:
1 parent
a65719a622
commit
e94fa524ca
4 files changed
+42
-6
No files matched your search
Generated
+2
-2
@@ -1202,7 +1202,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-codepage"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=14b2ebb7c2dda180e026037395abbefe48109eb5#14b2ebb7c2dda180e026037395abbefe48109eb5"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=f29e82f1a7a009e68312bd2e84adab72be23344d#f29e82f1a7a009e68312bd2e84adab72be23344d"
|
||||
|
||||
[[package]]
|
||||
name = "craft-csv"
|
||||
@@ -1364,7 +1364,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-rtf"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=14b2ebb7c2dda180e026037395abbefe48109eb5#14b2ebb7c2dda180e026037395abbefe48109eb5"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=f29e82f1a7a009e68312bd2e84adab72be23344d#f29e82f1a7a009e68312bd2e84adab72be23344d"
|
||||
dependencies = [
|
||||
"craft-codepage",
|
||||
"encoding_rs",
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.
|
||||
craft-pdf = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e2dc681a3", features = ["cos", "crypt", "filters"] }
|
||||
# The writer the RTF export maps onto (storytold/craft-libs#793), at storytold/craft-libs#1467:
|
||||
# its font and colour lookups take constant time, as PdfCraft's own writer did.
|
||||
craft-rtf = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "14b2ebb7c2dda180e026037395abbefe48109eb5" }
|
||||
craft-rtf = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "f29e82f1a7a009e68312bd2e84adab72be23344d" }
|
||||
craft-csv = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e2dc681a3" }
|
||||
craft-xml = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e2dc681a3" }
|
||||
craft-image-codecs = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e2dc681a3" }
|
||||
|
||||
@@ -42,6 +42,12 @@ fn table(t: &Table) -> craft_rtf::Table {
|
||||
craft_rtf::Table { rows }
|
||||
}
|
||||
|
||||
/// Keep a break outside tables, including when no text follows it on its page.
|
||||
fn standalone_page_break(blocks: &mut Vec<Block>) {
|
||||
let run = Run { text: PAGE_BREAK.to_string(), fmt: CharFmt::default() };
|
||||
blocks.push(Block::Para(Para { runs: vec![run], ..Para::default() }));
|
||||
}
|
||||
|
||||
/// Rich Text Format: paragraphs with their sizes, bold, italic and colours, real table rows, page
|
||||
/// breaks between pages (images are left out).
|
||||
pub fn rtf(pages: &[Page]) -> String {
|
||||
@@ -64,14 +70,21 @@ pub fn rtf(pages: &[Page]) -> String {
|
||||
}
|
||||
Item::Table(t) => {
|
||||
if std::mem::take(&mut page_break) {
|
||||
let run = Run { text: PAGE_BREAK.to_string(), fmt: CharFmt::default() };
|
||||
blocks.push(Block::Para(Para { runs: vec![run], ..Para::default() }));
|
||||
standalone_page_break(&mut blocks);
|
||||
}
|
||||
blocks.push(Block::Table(table(&t)));
|
||||
}
|
||||
Item::Img(_) => {}
|
||||
Item::PageBreak => page_break = true,
|
||||
Item::PageBreak => {
|
||||
if page_break {
|
||||
standalone_page_break(&mut blocks);
|
||||
}
|
||||
page_break = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if page_break {
|
||||
standalone_page_break(&mut blocks);
|
||||
}
|
||||
craft_rtf::write(&Document { blocks, pictures_left_out: 0 }, "Helvetica")
|
||||
}
|
||||
@@ -413,6 +413,29 @@ fn rtf_page_breaks_stay_out_of_tables() {
|
||||
assert_eq!(texts.iter().filter(|t| t.starts_with('\u{000C}')).count(), 2, "one break before each later page: {texts:?}");
|
||||
}
|
||||
|
||||
/// Empty and image-only pages still occupy a page when pictures are omitted from RTF.
|
||||
#[test]
|
||||
fn rtf_preserves_breaks_for_pages_without_text() {
|
||||
let mut blank = page();
|
||||
blank.blocks.clear();
|
||||
blank.images.clear();
|
||||
blank.rules.clear();
|
||||
let mut image_only = page();
|
||||
image_only.blocks.clear();
|
||||
for pages in [
|
||||
vec![blank.clone(), blank.clone(), page()],
|
||||
vec![page(), blank.clone(), blank.clone()],
|
||||
vec![page(), blank.clone(), blank.clone(), table_page()],
|
||||
vec![blank.clone(), blank.clone(), blank],
|
||||
vec![page(), image_only.clone(), image_only.clone(), page()],
|
||||
vec![page(), image_only],
|
||||
] {
|
||||
let r = rtf(&pages);
|
||||
let breaks = rtf_paras(&r).iter().flatten().map(|run| run.0.matches(craft_rtf::PAGE_BREAK).count()).sum::<usize>();
|
||||
assert_eq!(breaks, pages.len() - 1, "{r}");
|
||||
}
|
||||
}
|
||||
|
||||
/// A 3-column table with a spanning header row and a hole in the last row.
|
||||
fn table_page() -> Page {
|
||||
let cell = |t: &str, x: f64, y: f64, w: f64| Block {
|
||||
|
||||
Reference in new issue
Block a user