mirror of
https://github.com/typst/typst
synced 2025-08-19 17:38:32 +08:00
Add bleed support to page layout
This commit is contained in:
parent
d3caedd813
commit
daa9399124
@ -15,6 +15,7 @@ pub fn finalize(
|
||||
LayoutedPage {
|
||||
inner,
|
||||
mut margin,
|
||||
bleed,
|
||||
binding,
|
||||
two_sided,
|
||||
header,
|
||||
@ -34,33 +35,36 @@ pub fn finalize(
|
||||
}
|
||||
|
||||
// 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.
|
||||
for tag in tags.drain(..) {
|
||||
frame.push(Point::zero(), FrameItem::Tag(tag));
|
||||
}
|
||||
|
||||
let bleed_start = Point::new(bleed.left, bleed.top);
|
||||
|
||||
// Add the "before" marginals. The order in which we push things here is
|
||||
// important as it affects the relative ordering of introspectable elements
|
||||
// and thus how counters resolve.
|
||||
if let Some(background) = background {
|
||||
frame.push_frame(Point::zero(), background);
|
||||
frame.push_frame(bleed_start, background);
|
||||
}
|
||||
if let Some(header) = header {
|
||||
frame.push_frame(Point::with_x(margin.left), header);
|
||||
frame.push_frame(bleed_start + Point::with_x(margin.left), header);
|
||||
}
|
||||
|
||||
// Add the inner contents.
|
||||
frame.push_frame(Point::new(margin.left, margin.top), inner);
|
||||
frame.push_frame(bleed_start + Point::new(margin.left, margin.top), inner);
|
||||
|
||||
// Add the "after" marginals.
|
||||
if let Some(footer) = footer {
|
||||
let y = frame.height() - footer.height();
|
||||
frame.push_frame(Point::new(margin.left, y), footer);
|
||||
let y = frame.height() - footer.height() - bleed.bottom;
|
||||
frame.push_frame(Point::new(margin.left + bleed.left, y), footer);
|
||||
}
|
||||
if let Some(foreground) = foreground {
|
||||
frame.push_frame(Point::zero(), foreground);
|
||||
frame.push_frame(bleed_start + Point::zero(), foreground);
|
||||
}
|
||||
|
||||
// Apply counter updates from within the page to the manual page counter.
|
||||
@ -70,5 +74,5 @@ pub fn finalize(
|
||||
let number = counter.logical();
|
||||
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 inner: Frame,
|
||||
pub margin: Sides<Abs>,
|
||||
pub bleed: Sides<Abs>,
|
||||
pub binding: Binding,
|
||||
pub two_sided: bool,
|
||||
pub header: Option<Frame>,
|
||||
@ -123,6 +124,12 @@ fn layout_page_run_impl(
|
||||
.resolve(styles)
|
||||
.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 foreground = PageElem::foreground_in(styles);
|
||||
let background = PageElem::background_in(styles);
|
||||
@ -215,6 +222,7 @@ fn layout_page_run_impl(
|
||||
background: layout_marginal(background, full_size, mid)?,
|
||||
foreground: layout_marginal(foreground, full_size, mid)?,
|
||||
margin,
|
||||
bleed,
|
||||
binding,
|
||||
two_sided,
|
||||
});
|
||||
|
@ -148,6 +148,46 @@ pub struct PageElem {
|
||||
#[ghost]
|
||||
pub margin: Margin,
|
||||
|
||||
/// The page's bleed margin.
|
||||
///
|
||||
/// The bleed is a part of the content that extends beyond the edge of the
|
||||
/// final trimmed page. It ensures that there are no unprinted edges in the
|
||||
/// final product, even if there's a slight misalignment during trimming.
|
||||
///
|
||||
/// - `{auto}`: The bleed is set to 0mm on each side.
|
||||
/// - A single length: The same bleed on all sides.
|
||||
/// - A dictionary: With a dictionary, the bleed can be set individually.
|
||||
/// The dictionary can contain the following keys in order of precedence:
|
||||
/// - `top`: The top bleed.
|
||||
/// - `right`: The right bleed.
|
||||
/// - `bottom`: The bottom bleed.
|
||||
/// - `left`: The left bleed.
|
||||
/// - `inside`: The bleed at the inner side of the page (where the
|
||||
/// [binding]($page.binding) is).
|
||||
/// - `outside`: The bleed at the outer side of the page (opposite to the
|
||||
/// [binding]($page.binding)).
|
||||
/// - `x`: The horizontal bleeds.
|
||||
/// - `y`: The vertical bleeds.
|
||||
/// - `rest`: The bleeds on all sides except those for which the
|
||||
/// dictionary explicitly sets a size.
|
||||
///
|
||||
/// The values for `left` and `right` are mutually exclusive with
|
||||
/// the values for `inside` and `outside`.
|
||||
///
|
||||
/// On PDF output, if bleed is different of zero, it sets a TrimBox and a
|
||||
/// BleedBox 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.
|
||||
///
|
||||
/// - `{auto}`: Equivalent to `left` if the [text direction]($text.dir)
|
||||
@ -467,6 +507,8 @@ pub struct PagedDocument {
|
||||
pub struct Page {
|
||||
/// The frame that defines the page.
|
||||
pub frame: Frame,
|
||||
/// The bleed amount to be added on each side of the page.
|
||||
pub bleed: Sides<Abs>,
|
||||
/// How the page is filled.
|
||||
///
|
||||
/// - When `None`, the background is transparent.
|
||||
|
@ -7,7 +7,7 @@ use krilla::configure::{Configuration, ValidationError, Validator};
|
||||
use krilla::destination::{NamedDestination, XyzDestination};
|
||||
use krilla::embed::EmbedError;
|
||||
use krilla::error::KrillaError;
|
||||
use krilla::geom::PathBuilder;
|
||||
use krilla::geom::{PathBuilder, Rect};
|
||||
use krilla::page::{PageLabel, PageSettings};
|
||||
use krilla::surface::Surface;
|
||||
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::introspection::Location;
|
||||
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::text::{Font, Lang};
|
||||
@ -81,6 +81,22 @@ fn convert_pages(gc: &mut GlobalContext, document: &mut Document) -> SourceResul
|
||||
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
|
||||
.numbering
|
||||
.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
|
||||
]
|
||||
|
||||
--- 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 ---
|
||||
#set text(6pt)
|
||||
#show heading: set text(6pt, weight: "regular")
|
||||
|
Loading…
x
Reference in New Issue
Block a user