mirror of
https://github.com/typst/typst
synced 2025-08-20 01:48:34 +08:00
Compare commits
4 Commits
8396fd89ee
...
2b58876817
Author | SHA1 | Date | |
---|---|---|---|
|
2b58876817 | ||
|
263cd4d1d9 | ||
|
9ae94b2f64 | ||
|
6094516a63 |
@ -15,6 +15,7 @@ pub fn finalize(
|
|||||||
LayoutedPage {
|
LayoutedPage {
|
||||||
inner,
|
inner,
|
||||||
mut margin,
|
mut margin,
|
||||||
|
bleed,
|
||||||
binding,
|
binding,
|
||||||
two_sided,
|
two_sided,
|
||||||
header,
|
header,
|
||||||
@ -34,33 +35,36 @@ pub fn finalize(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a frame for the full page.
|
// Create a frame for the full page.
|
||||||
let mut frame = Frame::hard(inner.size() + margin.sum_by_axis());
|
let mut frame =
|
||||||
|
Frame::hard(inner.size() + margin.sum_by_axis() + bleed.sum_by_axis());
|
||||||
|
|
||||||
// Add tags.
|
// Add tags.
|
||||||
for tag in tags.drain(..) {
|
for tag in tags.drain(..) {
|
||||||
frame.push(Point::zero(), FrameItem::Tag(tag));
|
frame.push(Point::zero(), FrameItem::Tag(tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let content_origin = Point::new(bleed.left, bleed.top);
|
||||||
|
|
||||||
// Add the "before" marginals. The order in which we push things here is
|
// Add the "before" marginals. The order in which we push things here is
|
||||||
// important as it affects the relative ordering of introspectable elements
|
// important as it affects the relative ordering of introspectable elements
|
||||||
// and thus how counters resolve.
|
// and thus how counters resolve.
|
||||||
if let Some(background) = background {
|
if let Some(background) = background {
|
||||||
frame.push_frame(Point::zero(), background);
|
frame.push_frame(content_origin, background);
|
||||||
}
|
}
|
||||||
if let Some(header) = header {
|
if let Some(header) = header {
|
||||||
frame.push_frame(Point::with_x(margin.left), header);
|
frame.push_frame(content_origin + Point::with_x(margin.left), header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the inner contents.
|
// Add the inner contents.
|
||||||
frame.push_frame(Point::new(margin.left, margin.top), inner);
|
frame.push_frame(content_origin + Point::new(margin.left, margin.top), inner);
|
||||||
|
|
||||||
// Add the "after" marginals.
|
// Add the "after" marginals.
|
||||||
if let Some(footer) = footer {
|
if let Some(footer) = footer {
|
||||||
let y = frame.height() - footer.height();
|
let y = frame.height() - footer.height() - bleed.bottom;
|
||||||
frame.push_frame(Point::new(margin.left, y), footer);
|
frame.push_frame(Point::new(margin.left + bleed.left, y), footer);
|
||||||
}
|
}
|
||||||
if let Some(foreground) = foreground {
|
if let Some(foreground) = foreground {
|
||||||
frame.push_frame(Point::zero(), foreground);
|
frame.push_frame(content_origin + Point::zero(), foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply counter updates from within the page to the manual page counter.
|
// Apply counter updates from within the page to the manual page counter.
|
||||||
@ -70,5 +74,5 @@ pub fn finalize(
|
|||||||
let number = counter.logical();
|
let number = counter.logical();
|
||||||
counter.step();
|
counter.step();
|
||||||
|
|
||||||
Ok(Page { frame, fill, numbering, supplement, number })
|
Ok(Page { frame, bleed, fill, numbering, supplement, number })
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ use crate::flow::{layout_flow, FlowMode};
|
|||||||
pub struct LayoutedPage {
|
pub struct LayoutedPage {
|
||||||
pub inner: Frame,
|
pub inner: Frame,
|
||||||
pub margin: Sides<Abs>,
|
pub margin: Sides<Abs>,
|
||||||
|
pub bleed: Sides<Abs>,
|
||||||
pub binding: Binding,
|
pub binding: Binding,
|
||||||
pub two_sided: bool,
|
pub two_sided: bool,
|
||||||
pub header: Option<Frame>,
|
pub header: Option<Frame>,
|
||||||
@ -123,6 +124,12 @@ fn layout_page_run_impl(
|
|||||||
.resolve(styles)
|
.resolve(styles)
|
||||||
.relative_to(size);
|
.relative_to(size);
|
||||||
|
|
||||||
|
let bleed = PageElem::bleed_in(styles)
|
||||||
|
.sides
|
||||||
|
.map(|side| side.and_then(Smart::custom).unwrap_or(Rel::zero()))
|
||||||
|
.resolve(styles)
|
||||||
|
.relative_to(size);
|
||||||
|
|
||||||
let fill = PageElem::fill_in(styles);
|
let fill = PageElem::fill_in(styles);
|
||||||
let foreground = PageElem::foreground_in(styles);
|
let foreground = PageElem::foreground_in(styles);
|
||||||
let background = PageElem::background_in(styles);
|
let background = PageElem::background_in(styles);
|
||||||
@ -215,6 +222,7 @@ fn layout_page_run_impl(
|
|||||||
background: layout_marginal(background, full_size, mid)?,
|
background: layout_marginal(background, full_size, mid)?,
|
||||||
foreground: layout_marginal(foreground, full_size, mid)?,
|
foreground: layout_marginal(foreground, full_size, mid)?,
|
||||||
margin,
|
margin,
|
||||||
|
bleed,
|
||||||
binding,
|
binding,
|
||||||
two_sided,
|
two_sided,
|
||||||
});
|
});
|
||||||
|
@ -148,6 +148,47 @@ pub struct PageElem {
|
|||||||
#[ghost]
|
#[ghost]
|
||||||
pub margin: Margin,
|
pub margin: Margin,
|
||||||
|
|
||||||
|
/// The page's bleed margin.
|
||||||
|
///
|
||||||
|
/// The bleed is the area of content that extends beyond the final trimmed
|
||||||
|
/// size of the page. It ensures that no unprinted edges appear in the final
|
||||||
|
/// product, even if minor trimming misalignments occur.
|
||||||
|
///
|
||||||
|
/// Accepted values:
|
||||||
|
///
|
||||||
|
/// - `{auto}`: Sets the bleed to `0mm` on all sides.
|
||||||
|
/// - A single length: Applies the same bleed to all sides.
|
||||||
|
/// - A dictionary: Allows setting bleed values individually. The dictionary
|
||||||
|
/// may include the following keys, listed in order of precedence:
|
||||||
|
/// - `top`: Bleed at the top of the page.
|
||||||
|
/// - `right`: Bleed at the right side.
|
||||||
|
/// - `bottom`: Bleed at the bottom.
|
||||||
|
/// - `left`: Bleed at the left side.
|
||||||
|
/// - `inside`: Bleed on the inner side of the page (next to
|
||||||
|
/// [binding]($page.binding)).
|
||||||
|
/// - `outside`: Bleed on the outer side of the page (opposite the
|
||||||
|
/// [binding]($page.binding)).
|
||||||
|
/// - `x`: Horizontal bleed (applies to both left/right or inside/outside).
|
||||||
|
/// - `y`: Vertical bleed (applies to both top and bottom).
|
||||||
|
/// - `rest`: Default bleed for any sides not explicitly set.
|
||||||
|
///
|
||||||
|
/// Note: The keys `left` and `right` are mutually exclusive with `inside` and
|
||||||
|
/// `outside`.
|
||||||
|
///
|
||||||
|
/// On PDF output, if the bleed is non-zero, a `TrimBox` and a `BleedBox` are
|
||||||
|
/// defined for the page.
|
||||||
|
///
|
||||||
|
/// ```example
|
||||||
|
/// #set page(
|
||||||
|
/// width: 3cm,
|
||||||
|
/// height: 4cm,
|
||||||
|
/// bleed: 5mm,
|
||||||
|
/// background: rect(width: 100%, height: 100%, fill: aqua),
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
#[ghost]
|
||||||
|
pub bleed: Margin,
|
||||||
|
|
||||||
/// On which side the pages will be bound.
|
/// On which side the pages will be bound.
|
||||||
///
|
///
|
||||||
/// - `{auto}`: Equivalent to `left` if the [text direction]($text.dir)
|
/// - `{auto}`: Equivalent to `left` if the [text direction]($text.dir)
|
||||||
@ -467,6 +508,8 @@ pub struct PagedDocument {
|
|||||||
pub struct Page {
|
pub struct Page {
|
||||||
/// The frame that defines the page.
|
/// The frame that defines the page.
|
||||||
pub frame: Frame,
|
pub frame: Frame,
|
||||||
|
/// The bleed amount to be added on each side of the page.
|
||||||
|
pub bleed: Sides<Abs>,
|
||||||
/// How the page is filled.
|
/// How the page is filled.
|
||||||
///
|
///
|
||||||
/// - When `None`, the background is transparent.
|
/// - When `None`, the background is transparent.
|
||||||
|
@ -7,7 +7,7 @@ use krilla::configure::{Configuration, ValidationError, Validator};
|
|||||||
use krilla::destination::{NamedDestination, XyzDestination};
|
use krilla::destination::{NamedDestination, XyzDestination};
|
||||||
use krilla::embed::EmbedError;
|
use krilla::embed::EmbedError;
|
||||||
use krilla::error::KrillaError;
|
use krilla::error::KrillaError;
|
||||||
use krilla::geom::PathBuilder;
|
use krilla::geom::{PathBuilder, Rect};
|
||||||
use krilla::page::{PageLabel, PageSettings};
|
use krilla::page::{PageLabel, PageSettings};
|
||||||
use krilla::surface::Surface;
|
use krilla::surface::Surface;
|
||||||
use krilla::{Document, SerializeSettings};
|
use krilla::{Document, SerializeSettings};
|
||||||
@ -16,7 +16,7 @@ use typst_library::diag::{bail, error, SourceDiagnostic, SourceResult};
|
|||||||
use typst_library::foundations::{NativeElement, Repr};
|
use typst_library::foundations::{NativeElement, Repr};
|
||||||
use typst_library::introspection::Location;
|
use typst_library::introspection::Location;
|
||||||
use typst_library::layout::{
|
use typst_library::layout::{
|
||||||
Abs, Frame, FrameItem, GroupItem, PagedDocument, Size, Transform,
|
Abs, Frame, FrameItem, GroupItem, PagedDocument, Sides, Size, Transform,
|
||||||
};
|
};
|
||||||
use typst_library::model::HeadingElem;
|
use typst_library::model::HeadingElem;
|
||||||
use typst_library::text::{Font, Lang};
|
use typst_library::text::{Font, Lang};
|
||||||
@ -81,6 +81,22 @@ fn convert_pages(gc: &mut GlobalContext, document: &mut Document) -> SourceResul
|
|||||||
typst_page.frame.height().to_f32(),
|
typst_page.frame.height().to_f32(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if typst_page.bleed != Sides::splat(Abs::zero()) {
|
||||||
|
settings = settings
|
||||||
|
.with_bleed_box(Rect::from_xywh(
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
typst_page.frame.width().to_f32(),
|
||||||
|
typst_page.frame.height().to_f32(),
|
||||||
|
))
|
||||||
|
.with_trim_box(Rect::from_ltrb(
|
||||||
|
typst_page.bleed.left.to_f32(),
|
||||||
|
typst_page.bleed.top.to_f32(),
|
||||||
|
(typst_page.frame.width() - typst_page.bleed.right).to_f32(),
|
||||||
|
(typst_page.frame.height() - typst_page.bleed.bottom).to_f32(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(label) = typst_page
|
if let Some(label) = typst_page
|
||||||
.numbering
|
.numbering
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
BIN
tests/ref/page-bleed-content-bleeding.png
Normal file
BIN
tests/ref/page-bleed-content-bleeding.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 B |
BIN
tests/ref/page-bleed.png
Normal file
BIN
tests/ref/page-bleed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 B |
@ -348,6 +348,26 @@ A
|
|||||||
A
|
A
|
||||||
]
|
]
|
||||||
|
|
||||||
|
--- page-bleed ---
|
||||||
|
#set page(
|
||||||
|
bleed: 20pt,
|
||||||
|
margin: 20pt,
|
||||||
|
height: 80pt,
|
||||||
|
width: 80pt,
|
||||||
|
background: rect(width: 100%, height: 100%, fill: gray),
|
||||||
|
)
|
||||||
|
#rect(width: 100%, height: 100%, fill: black)
|
||||||
|
|
||||||
|
--- page-bleed-content-bleeding ---
|
||||||
|
#set page(
|
||||||
|
bleed: 20pt,
|
||||||
|
margin: 20pt,
|
||||||
|
height: 80pt,
|
||||||
|
width: 80pt,
|
||||||
|
)
|
||||||
|
#set align(center + horizon)
|
||||||
|
#rect(width: 100pt, height: 100pt, fill: black)
|
||||||
|
|
||||||
--- issue-2631-page-header-ordering ---
|
--- issue-2631-page-header-ordering ---
|
||||||
#set text(6pt)
|
#set text(6pt)
|
||||||
#show heading: set text(6pt, weight: "regular")
|
#show heading: set text(6pt, weight: "regular")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user