mirror of
https://github.com/typst/typst
synced 2025-08-14 23:18:32 +08:00
Fix page range issue
This commit is contained in:
parent
27c5e0081a
commit
9b5ee82c16
@ -52,10 +52,13 @@ pub fn convert(
|
||||
};
|
||||
|
||||
let mut document = Document::new_with(settings);
|
||||
let page_index_converter = PageIndexConverter::new(&typst_document, &options);
|
||||
let named_destinations = collect_named_destinations(&typst_document, &page_index_converter);
|
||||
let mut gc = GlobalContext::new(
|
||||
typst_document,
|
||||
options,
|
||||
collect_named_destinations(typst_document, options),
|
||||
named_destinations,
|
||||
page_index_converter
|
||||
);
|
||||
|
||||
convert_pages(&mut gc, &mut document)?;
|
||||
@ -68,12 +71,9 @@ pub fn convert(
|
||||
}
|
||||
|
||||
fn convert_pages(gc: &mut GlobalContext, document: &mut Document) -> SourceResult<()> {
|
||||
let mut skipped_pages = 0;
|
||||
|
||||
for (i, typst_page) in gc.document.pages.iter().enumerate() {
|
||||
if gc.page_excluded(i) {
|
||||
if gc.page_index_converter.pdf_page_index(i).is_none() {
|
||||
// Don't export this page.
|
||||
skipped_pages += 1;
|
||||
continue;
|
||||
} else {
|
||||
let mut settings = PageSettings::new(
|
||||
@ -93,7 +93,7 @@ fn convert_pages(gc: &mut GlobalContext, document: &mut Document) -> SourceResul
|
||||
// the real (not logical) page numbers. Here, the final PDF page number
|
||||
// will differ, but we can at least use labels to indicate what was
|
||||
// the corresponding real page number in the Typst document.
|
||||
(skipped_pages > 0).then(|| PageLabel::arabic(i + 1))
|
||||
gc.page_index_converter.has_skipped_pages().then(|| PageLabel::arabic(i + 1))
|
||||
})
|
||||
{
|
||||
settings = settings.with_page_label(label);
|
||||
@ -219,35 +219,31 @@ pub(crate) struct GlobalContext<'a> {
|
||||
/// Options for PDF export.
|
||||
pub(crate) options: &'a PdfOptions<'a>,
|
||||
/// Mapping between locations in the document and named destinations.
|
||||
pub(crate) loc_to_named: HashMap<Location, NamedDestination>,
|
||||
pub(crate) loc_to_names: HashMap<Location, NamedDestination>,
|
||||
/// The languages used throughout the document.
|
||||
pub(crate) languages: BTreeMap<Lang, usize>,
|
||||
pub(crate) page_index_converter: PageIndexConverter
|
||||
}
|
||||
|
||||
impl<'a> GlobalContext<'a> {
|
||||
pub(crate) fn new(
|
||||
document: &'a PagedDocument,
|
||||
options: &'a PdfOptions,
|
||||
loc_to_named: HashMap<Location, NamedDestination>,
|
||||
loc_to_names: HashMap<Location, NamedDestination>,
|
||||
page_index_converter: PageIndexConverter
|
||||
) -> GlobalContext<'a> {
|
||||
Self {
|
||||
fonts_forward: HashMap::new(),
|
||||
fonts_backward: HashMap::new(),
|
||||
document,
|
||||
options,
|
||||
loc_to_named,
|
||||
loc_to_names,
|
||||
image_to_spans: HashMap::new(),
|
||||
image_spans: HashSet::new(),
|
||||
languages: BTreeMap::new(),
|
||||
page_index_converter
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn page_excluded(&self, page_index: usize) -> bool {
|
||||
self.options
|
||||
.page_ranges
|
||||
.as_ref()
|
||||
.is_some_and(|ranges| !ranges.includes_page_index(page_index))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle_frame(
|
||||
@ -556,7 +552,7 @@ fn finish(
|
||||
|
||||
fn collect_named_destinations(
|
||||
document: &PagedDocument,
|
||||
options: &PdfOptions,
|
||||
pic: &PageIndexConverter
|
||||
) -> HashMap<Location, NamedDestination> {
|
||||
let mut locs_to_names = HashMap::new();
|
||||
|
||||
@ -582,11 +578,7 @@ fn collect_named_destinations(
|
||||
let y = (pos.point.y - Abs::pt(10.0)).max(Abs::zero());
|
||||
|
||||
// Only add named destination if page belonging to the position is exported.
|
||||
if options
|
||||
.page_ranges
|
||||
.as_ref()
|
||||
.is_some_and(|ranges| !ranges.includes_page_index(index))
|
||||
{
|
||||
if let Some(index) = pic.pdf_page_index(index) {
|
||||
let named = NamedDestination::new(
|
||||
label.resolve().to_string(),
|
||||
XyzDestination::new(
|
||||
@ -631,3 +623,38 @@ fn get_configuration(options: &PdfOptions) -> SourceResult<Configuration> {
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub(crate) struct PageIndexConverter {
|
||||
page_indices: HashMap<usize, usize>,
|
||||
skipped_pages: usize,
|
||||
}
|
||||
|
||||
impl PageIndexConverter {
|
||||
pub fn new(document: &PagedDocument, options: &PdfOptions) -> Self {
|
||||
let mut page_indices = HashMap::new();
|
||||
let mut skipped_pages = 0;
|
||||
|
||||
for i in 0..document.pages.len() {
|
||||
if options
|
||||
.page_ranges
|
||||
.as_ref()
|
||||
.is_some_and(|ranges| !ranges.includes_page_index(i))
|
||||
{
|
||||
skipped_pages += 1;
|
||||
} else {
|
||||
page_indices.insert(i, i - skipped_pages);
|
||||
}
|
||||
}
|
||||
|
||||
Self { page_indices, skipped_pages }
|
||||
}
|
||||
|
||||
pub(crate) fn has_skipped_pages(&self) -> bool {
|
||||
self.skipped_pages > 0
|
||||
}
|
||||
|
||||
/// Get the PDF page index of a page index, if it's not excluded.
|
||||
pub(crate) fn pdf_page_index(&self, page_index: usize) -> Option<usize> {
|
||||
self.page_indices.get(&page_index).copied()
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ pub(crate) fn handle_link(
|
||||
}
|
||||
Destination::Position(p) => *p,
|
||||
Destination::Location(loc) => {
|
||||
if let Some(nd) = gc.loc_to_named.get(loc) {
|
||||
if let Some(nd) = gc.loc_to_names.get(loc) {
|
||||
// If a named destination has been registered, it's already guaranteed to
|
||||
// not point to an excluded page.
|
||||
fc.push_annotation(
|
||||
@ -79,13 +79,13 @@ pub(crate) fn handle_link(
|
||||
};
|
||||
|
||||
let page_index = pos.page.get() - 1;
|
||||
if !gc.page_excluded(page_index) {
|
||||
if let Some(index) = gc.page_index_converter.pdf_page_index(page_index) {
|
||||
fc.push_annotation(
|
||||
LinkAnnotation::new(
|
||||
rect,
|
||||
None,
|
||||
Target::Destination(krilla::destination::Destination::Xyz(
|
||||
XyzDestination::new(page_index, pos.point.to_krilla()),
|
||||
XyzDestination::new(index, pos.point.to_krilla()),
|
||||
)),
|
||||
)
|
||||
.into(),
|
||||
|
@ -127,10 +127,10 @@ impl<'a> HeadingNode<'a> {
|
||||
let pos = gc.document.introspector.position(loc);
|
||||
let page_index = pos.page.get() - 1;
|
||||
|
||||
if !gc.page_excluded(page_index) {
|
||||
if let Some(index) = gc.page_index_converter.pdf_page_index(page_index) {
|
||||
let y = (pos.point.y - Abs::pt(10.0)).max(Abs::zero());
|
||||
let dest = XyzDestination::new(
|
||||
page_index,
|
||||
index,
|
||||
krilla::geom::Point::from_xy(pos.point.x.to_f32(), y.to_f32()),
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user