///|
fn pdf_page_upright_degrees(rotation : @page.PdfPageRotation) -> Double {
@page.pdf_page_int_of_rotation(rotation).to_double()
}
///|
fn pdf_page_upright_near_zero(value : Double) -> Bool {
value < 0.001 && value > -0.001
}
///|
fn PdfDocument::pdf_page_upright_is_upright(
self : PdfDocument,
page : @page.PdfPage,
) -> Bool raise @core.PdfError {
let bounds = self.parse_rectangle(page.mediabox)
page.rotate == Rotate0 &&
pdf_page_upright_near_zero(bounds.min_x) &&
pdf_page_upright_near_zero(bounds.min_y)
}
///|
fn PdfDocument::pdf_page_upright_all_upright(
self : PdfDocument,
page_numbers : ArrayView[Int],
pages : ArrayView[@page.PdfPage],
) -> Bool raise @core.PdfError {
for page_number in page_numbers {
if !self.pdf_page_upright_is_upright(pages[page_number - 1]) {
break false
}
} nobreak {
true
}
}
///|
/// Return whether selected pages are rotation-free and have a near-zero origin.
///
/// This ports cpdf's `allupright` predicate. Like the source, page numbers
/// outside the document are ignored rather than treated as a range error.
pub fn PdfDocument::all_pages_upright(
self : PdfDocument,
page_numbers : ArrayView[Int],
) -> Bool raise @core.PdfError {
let pages = self.pages_of_pagetree()
for page_number in page_numbers {
if page_number >= 1 && page_number <= pages.length() {
if !self.pdf_page_upright_is_upright(pages[page_number - 1]) {
break false
}
}
} nobreak {
true
}
}
///|
/// Compatibility wrapper for `PdfDocument::all_pages_upright`.
pub fn pdf_allupright(
document : PdfDocument,
page_numbers : ArrayView[Int],
) -> Bool raise @core.PdfError {
document.all_pages_upright(page_numbers)
}
///|
/// Compatibility wrapper matching cpdfpage's `allupright` argument order.
pub fn pdf_allupright_cpdf_order(
page_numbers : ArrayView[Int],
document : PdfDocument,
) -> Bool raise @core.PdfError {
document.all_pages_upright(page_numbers)
}
///|
/// Return whether selected pages have no page dictionary rotation.
///
/// This ports cpdf's `alluprightonly`, which intentionally does not require a
/// `(0, 0)` media-box origin and ignores out-of-range page numbers.
pub fn PdfDocument::all_pages_upright_only(
self : PdfDocument,
page_numbers : ArrayView[Int],
) -> Bool raise @core.PdfError {
let pages = self.pages_of_pagetree()
for page_number in page_numbers {
if page_number >= 1 && page_number <= pages.length() {
if pages[page_number - 1].rotate != Rotate0 {
break false
}
}
} nobreak {
true
}
}
///|
/// Compatibility wrapper for `PdfDocument::all_pages_upright_only`.
pub fn pdf_alluprightonly(
document : PdfDocument,
page_numbers : ArrayView[Int],
) -> Bool raise @core.PdfError {
document.all_pages_upright_only(page_numbers)
}
///|
/// Compatibility wrapper matching cpdfpage's `alluprightonly` argument order.
pub fn pdf_alluprightonly_cpdf_order(
page_numbers : ArrayView[Int],
document : PdfDocument,
) -> Bool raise @core.PdfError {
document.all_pages_upright_only(page_numbers)
}
///|
fn PdfDocument::pdf_page_upright_rotation_matrix(
self : PdfDocument,
page : @page.PdfPage,
) -> @geometry.TransformMatrix raise @core.PdfError {
let bounds = self.parse_rectangle(page.mediabox)
let center = @geometry.point2(
(bounds.min_x + bounds.max_x) / 2.0,
(bounds.min_y + bounds.max_y) / 2.0,
)
@geometry.transform_rotate(
center,
-pdf_page_upright_degrees(page.rotate) * @math.PI / 180.0,
)
}
///|
fn pdf_page_upright_box_names() -> Array[@core.PdfName] {
[
pdf_page_trimbox_key(),
pdf_page_artbox_key(),
pdf_page_cropbox_key(),
pdf_page_bleedbox_key(),
]
}
///|
fn PdfDocument::pdf_page_upright_transform_boxes(
self : PdfDocument,
page : @page.PdfPage,
matrix : @geometry.TransformMatrix,
) -> @page.PdfPage raise @core.PdfError {
let mut rest = page.rest
for name in pdf_page_upright_box_names() {
match self.lookup_direct(name, page.rest) {
Some(value) =>
rest = rest.add_dict_entry(name, self.transform_rect(matrix, value))
None => ()
}
}
{ ..page, mediabox: self.transform_rect(matrix, page.mediabox), rest, }
}
///|
fn PdfDocument::pdf_page_upright_transform_content(
self : PdfDocument,
page : @page.PdfPage,
matrix : @geometry.TransformMatrix,
fast : Bool,
) -> @page.PdfPage raise @core.PdfError {
if matrix == @geometry.transform_identity_matrix {
page
} else {
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~)
}
}
///|
fn PdfDocument::pdf_page_upright_rectify(
self : PdfDocument,
page : @page.PdfPage,
fast : Bool,
) -> (@page.PdfPage, @geometry.TransformMatrix) raise @core.PdfError {
let bounds = self.parse_rectangle(page.mediabox)
if pdf_page_upright_near_zero(bounds.min_x) &&
pdf_page_upright_near_zero(bounds.min_y) {
(page, @geometry.transform_identity_matrix)
} else {
let matrix = @geometry.transform_translate(-bounds.min_x, -bounds.min_y)
let page = self.pdf_page_upright_transform_boxes(page, matrix)
let page = self.pdf_page_shift_page(page, matrix, fast)
(page, matrix)
}
}
///|
fn PdfDocument::pdf_page_upright_page(
self : PdfDocument,
page : @page.PdfPage,
fast : Bool,
) -> (@page.PdfPage, @geometry.TransformMatrix) raise @core.PdfError {
if self.pdf_page_upright_is_upright(page) {
(page, @geometry.transform_identity_matrix)
} else {
let rotation_matrix = self.pdf_page_upright_rotation_matrix(page)
let page = self.pdf_page_upright_transform_boxes(page, rotation_matrix)
let page = self.pdf_page_upright_transform_content(
{ ..page, rotate: Rotate0, },
rotation_matrix,
fast,
)
let (page, rectification_matrix) = self.pdf_page_upright_rectify(page, fast)
(
page,
@geometry.transform_matrix_compose(rectification_matrix, rotation_matrix),
)
}
}
///|
/// Remove page dictionary rotation from selected pages by transforming page data.
///
/// Page content, annotations, known page boxes, and destinations are transformed
/// into an upright coordinate system. Non-zero `/MediaBox` origins are shifted
/// back to `(0, 0)` after rotation.
pub fn PdfDocument::upright_pages(
self : PdfDocument,
page_numbers : ArrayView[Int],
fast? : Bool = false,
) -> PdfDocument raise @core.PdfError {
pdf_page_box_validate_page_numbers(
page_numbers,
self.endpage(),
"upright_pages",
)
let pages = self.pages_of_pagetree()
if self.pdf_page_upright_all_upright(page_numbers, pages) {
self
} else {
let selected_pages = @core.pdf_number_set(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.. PdfDocument raise @core.PdfError {
document.upright_pages(page_numbers, fast~)
}
///|
/// Compatibility alias for `PdfDocument::upright_pages`.
pub fn PdfDocument::upright(
self : PdfDocument,
page_numbers : ArrayView[Int],
fast? : Bool = false,
) -> PdfDocument raise @core.PdfError {
self.upright_pages(page_numbers, fast~)
}
///|
/// Compatibility wrapper matching cpdfpage's `upright` argument order.
pub fn pdf_upright(
page_numbers : ArrayView[Int],
document : PdfDocument,
fast? : Bool = false,
) -> PdfDocument raise @core.PdfError {
document.upright_pages(page_numbers, fast~)
}