///|
fn pdf_page_scale_to_fit_position_offset(
position : @geometry.PdfPosition,
target_width : Double,
target_height : Double,
source_width : Double,
source_height : Double,
scale : Double,
) -> (Double, Double) {
let dx = (target_width - source_width * scale) / 2.0
let dy = (target_height - source_height * scale) / 2.0
let x = match position {
PdfPositionLeft(_) => -dx
PdfPositionRight(_) => dx
_ => 0.0
}
let y = match position {
PdfPositionTop(_) => dy
PdfPositionBottom(_) => -dy
_ => 0.0
}
(x, y)
}
///|
fn pdf_page_scale_to_fit_matrix_from_bounds(
bounds : @geometry.PdfRectangle,
target_width : Double,
target_height : Double,
position : @geometry.PdfPosition,
input_scale : Double,
) -> @geometry.TransformMatrix raise @core.PdfError {
let source_width = bounds.max_x - bounds.min_x
let source_height = bounds.max_y - bounds.min_y
if source_width <= 0.0 || source_height <= 0.0 {
raise BadNumberArgument("scale_to_fit_pages: zero-sized pages are invalid")
}
let fx = target_width / source_width
let fy = target_height / source_height
let fit = if fx < fy { fx } else { fy }
let fit_scale = fit * input_scale
let trans_x = (target_width - bounds.max_x * fit_scale) / 2.0
let trans_y = (target_height - bounds.max_y * fit_scale) / 2.0
let fixup_trans_x = -(bounds.min_x * fit_scale) / 2.0
let fixup_trans_y = -(bounds.min_y * fit_scale) / 2.0
let position_offset = pdf_page_scale_to_fit_position_offset(
position, target_width, target_height, source_width, source_height, fit_scale,
)
@geometry.transform_matrix_compose(
@geometry.transform_translate(fixup_trans_x, fixup_trans_y),
@geometry.transform_matrix_compose(
@geometry.transform_translate(position_offset.0, position_offset.1),
@geometry.transform_matrix_compose(
@geometry.transform_translate(trans_x, trans_y),
@geometry.transform_scale(
@geometry.point2(0.0, 0.0),
fit_scale,
fit_scale,
),
),
),
)
}
///|
fn PdfDocument::pdf_page_scale_to_fit_matrix(
self : PdfDocument,
page : @page.PdfPage,
target_width : Double,
target_height : Double,
position : @geometry.PdfPosition,
input_scale : Double,
) -> @geometry.TransformMatrix raise @core.PdfError {
pdf_page_scale_to_fit_matrix_from_bounds(
self.pdf_page_scale_bounds(page),
target_width,
target_height,
position,
input_scale,
)
}
///|
fn pdf_page_scale_target_box(
width : Double,
height : Double,
) -> @syntax.PdfObject {
PdfArray([PdfReal(0.0), PdfReal(0.0), PdfReal(width), PdfReal(height)])
}
///|
fn PdfDocument::pdf_page_scale_to_fit_boxes(
self : PdfDocument,
page : @page.PdfPage,
target_width : Double,
target_height : Double,
) -> @page.PdfPage raise @core.PdfError {
let target = pdf_page_scale_target_box(target_width, target_height)
let mut rest = page.rest
for name in pdf_page_upright_box_names() {
match self.lookup_direct(name, page.rest) {
Some(_) => rest = rest.add_dict_entry(name, target)
None => ()
}
}
{ ..page, mediabox: target, rest, }
}
///|
fn PdfDocument::pdf_page_scale_to_fit_page(
self : PdfDocument,
page : @page.PdfPage,
target_width : Double,
target_height : Double,
matrix : @geometry.TransformMatrix,
fast : Bool,
) -> @page.PdfPage raise @core.PdfError {
let page = self.pdf_page_scale_to_fit_boxes(page, target_width, target_height)
let page = self.pdf_impose_change_pattern_matrices_page(matrix, page)
self.transform_annotations(matrix, page.rest)
self.prepend_operators(page, [Op_cm(matrix)], fast~)
}
///|
/// Scale selected pages to fit target page sizes while preserving aspect ratio.
pub fn PdfDocument::scale_to_fit_pages(
self : PdfDocument,
page_numbers : ArrayView[Int],
sizes : ArrayView[(Double, Double)],
position? : @geometry.PdfPosition = PdfPositionCentre,
input_scale? : Double = 1.0,
fast? : Bool = false,
) -> PdfDocument raise @core.PdfError {
pdf_page_box_validate_page_numbers(
page_numbers,
self.endpage(),
"scale_to_fit_pages",
)
if page_numbers.length() != sizes.length() {
raise BadPageSpecification(
"scale_to_fit_pages: size count must match page count",
)
}
let pages = self.pages_of_pagetree()
let page_indexes = pdf_page_scale_pair_index_map(page_numbers)
let rewritten : Array[@page.PdfPage] = Array(capacity=pages.length())
let matrices : Array[(Int, @geometry.TransformMatrix)] = Array(
capacity=page_numbers.length(),
)
for index in 0.. {
let size = sizes[size_index]
let matrix = self.pdf_page_scale_to_fit_matrix(
pages[index],
size.0,
size.1,
position,
input_scale,
)
rewritten.push(
self.pdf_page_scale_to_fit_page(
pages[index],
size.0,
size.1,
matrix,
fast,
),
)
matrices.push((page_number, matrix))
}
None => rewritten.push(pages[index])
}
}
self.change_pages(rewritten, change_references=true, matrices~)
}
///|
/// Compatibility wrapper for `PdfDocument::scale_to_fit_pages`.
pub fn pdf_scale_to_fit_pages(
document : PdfDocument,
page_numbers : ArrayView[Int],
sizes : ArrayView[(Double, Double)],
position? : @geometry.PdfPosition = PdfPositionCentre,
input_scale? : Double = 1.0,
fast? : Bool = false,
) -> PdfDocument raise @core.PdfError {
document.scale_to_fit_pages(
page_numbers,
sizes,
position~,
input_scale~,
fast~,
)
}
///|
/// Scale selected pages to fit using cpdf's absolute page-indexed size list.
pub fn PdfDocument::scale_to_fit_pdf(
self : PdfDocument,
page_numbers : ArrayView[Int],
sizes : ArrayView[(Double, Double)],
position? : @geometry.PdfPosition = PdfPositionCentre,
input_scale? : Double = 1.0,
fast? : Bool = false,
) -> PdfDocument raise @core.PdfError {
let pages = self.pages_of_pagetree()
pdf_page_box_validate_page_numbers(
page_numbers,
pages.length(),
"scale_to_fit_pdf",
)
pdf_page_scale_validate_page_indexed_pairs(
"scale_to_fit_pdf",
"size",
pages.length(),
sizes,
)
self.scale_to_fit_pages(
page_numbers,
pdf_page_scale_select_page_indexed_pairs(page_numbers, sizes),
position~,
input_scale~,
fast~,
)
}
///|
/// Compatibility wrapper matching cpdfpage's `scale_to_fit_pdf` argument order.
pub fn[T] pdf_scale_to_fit_pdf(
position : @geometry.PdfPosition,
input_scale : Double,
sizes : ArrayView[(Double, Double)],
_op : T,
document : PdfDocument,
page_numbers : ArrayView[Int],
fast? : Bool = false,
) -> PdfDocument raise @core.PdfError {
document.scale_to_fit_pdf(page_numbers, sizes, position~, input_scale~, fast~)
}