///|
let pdf_page_trimbox_key_name : PdfName = pdf_page_name("/TrimBox")

///|
let pdf_page_artbox_key_name : PdfName = pdf_page_name("/ArtBox")

///|
let pdf_page_bleedbox_key_name : PdfName = pdf_page_name("/BleedBox")

///|
fn pdf_page_trimbox_key() -> PdfName {
  pdf_page_trimbox_key_name
}

///|
fn pdf_page_artbox_key() -> PdfName {
  pdf_page_artbox_key_name
}

///|
fn pdf_page_bleedbox_key() -> PdfName {
  pdf_page_bleedbox_key_name
}

///|
fn pdf_page_box_name_text(name : PdfName) -> String {
  @ascii.decode(name.bytes()) catch {
    _ => ""
  }
}

///|
fn pdf_page_box_name_of_string(text : String) -> PdfName {
  pdf_page_name(text)
}

///|
fn pdf_page_box_contains_page(
  page_numbers : ArrayView[Int],
  page_number : Int,
) -> Bool {
  for selected in page_numbers {
    if selected == page_number {
      break true
    }
  } nobreak {
    false
  }
}

///|
fn pdf_page_box_validate_page_numbers(
  page_numbers : ArrayView[Int],
  end_page : Int,
  context : String,
) -> Unit raise PdfError {
  for page_number in page_numbers {
    if page_number < 1 || page_number > end_page {
      raise BadPageSpecification(
        context + ": range contains pages not present in pdf",
      )
    }
  }
}

///|
fn PdfDocument::pdf_page_box_rewrite_pages(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  context : String,
  rewrite : (PdfDocument, Int, PdfPage) -> PdfPage raise PdfError,
) -> PdfDocument raise PdfError {
  let pages = self.pages_of_pagetree()
  pdf_page_box_validate_page_numbers(page_numbers, pages.length(), context)
  let selected_pages = @number_set.pdf_number_set(page_numbers)
  let rewritten : Array[PdfPage] = Array::new(capacity=pages.length())
  for index in 0.. Unit raise PdfError {
  if boxes.length() != end_page {
    raise BadPageSpecification(
      "set_mediaboxes: box count must match page count",
    )
  }
}

///|
fn pdf_page_box_validate_xywh_boxes_with_context(
  boxes : ArrayView[(Double, Double, Double, Double)],
  end_page : Int,
  context : String,
) -> Unit raise PdfError {
  if boxes.length() != end_page {
    raise BadPageSpecification(context + ": box count must match page count")
  }
}

///|
fn pdf_page_box_validate_offsets(
  offsets : ArrayView[(Double, Double)],
  end_page : Int,
) -> Unit raise PdfError {
  if offsets.length() != end_page {
    raise BadPageSpecification(
      "shift_boxes: offset count must match page count",
    )
  }
}

///|
fn pdf_page_box_xywh_object(
  box : (Double, Double, Double, Double),
) -> PdfObject {
  let (x, y, width, height) = box
  PdfArray([PdfReal(x), PdfReal(y), PdfReal(x + width), PdfReal(y + height)])
}

///|
fn pdf_page_box_bounds_object(
  bounds : (Double, Double, Double, Double),
) -> PdfObject {
  let (min_x, min_y, max_x, max_y) = bounds
  PdfArray([PdfReal(min_x), PdfReal(min_y), PdfReal(max_x), PdfReal(max_y)])
}

///|
fn PdfDocument::pdf_page_box_object(
  self : PdfDocument,
  page : PdfPage,
  box_name : PdfName,
  mediabox_if_missing : Bool,
) -> PdfObject raise PdfError {
  if box_name == pdf_page_mediabox_key() {
    page.mediabox
  } else {
    match self.lookup_direct(box_name, page.rest) {
      Some(value) => value
      None =>
        if mediabox_if_missing {
          page.mediabox
        } else {
          raise BadPageSpecification(
            "hard_box: box " + pdf_page_box_name_text(box_name) + " not found",
          )
        }
    }
  }
}

///|
fn PdfDocument::pdf_page_hard_box_page(
  self : PdfDocument,
  page : PdfPage,
  box_name : PdfName,
  mediabox_if_missing : Bool,
  fast : Bool,
) -> PdfPage raise PdfError {
  let bounds = self.parse_rectangle(
    self.pdf_page_box_object(page, box_name, mediabox_if_missing),
  )
  self.prepend_operators(
    page,
    [
      Op_re(
        bounds.min_x,
        bounds.min_y,
        bounds.max_x - bounds.min_x,
        bounds.max_y - bounds.min_y,
      ),
      Op_W,
      Op_n,
    ],
    fast~,
  )
}

///|
fn PdfDocument::pdf_page_remove_box_page(
  self : PdfDocument,
  page : PdfPage,
  box_name : PdfName,
) -> PdfPage raise PdfError {
  ignore(self)
  { ..page, rest: page.rest.remove_dict_entry(box_name) }
}

///|
fn PdfDocument::pdf_page_copy_box_source(
  self : PdfDocument,
  page : PdfPage,
  from_box : PdfName,
  mediabox_if_missing : Bool,
) -> PdfObject? {
  if from_box == pdf_page_mediabox_key() {
    Some(page.mediabox)
  } else {
    match self.lookup_direct(from_box, page.rest) {
      Some(value) => Some(value)
      None => if mediabox_if_missing { Some(page.mediabox) } else { None }
    }
  }
}

///|
fn PdfDocument::pdf_page_copy_box_page(
  self : PdfDocument,
  page : PdfPage,
  from_box : PdfName,
  to_box : PdfName,
  mediabox_if_missing : Bool,
) -> PdfPage raise PdfError {
  match self.pdf_page_copy_box_source(page, from_box, mediabox_if_missing) {
    Some(value) =>
      if to_box == pdf_page_mediabox_key() {
        { ..page, mediabox: value }
      } else {
        { ..page, rest: page.rest.add_dict_entry(to_box, value) }
      }
    None => page
  }
}

///|
fn PdfDocument::pdf_page_set_mediabox_page(
  self : PdfDocument,
  page_number : Int,
  page : PdfPage,
  boxes : ArrayView[(Double, Double, Double, Double)],
) -> PdfPage {
  ignore(self)
  { ..page, mediabox: pdf_page_box_xywh_object(boxes[page_number - 1]) }
}

///|
fn PdfDocument::pdf_page_crop_page(
  self : PdfDocument,
  page_number : Int,
  page : PdfPage,
  boxes : ArrayView[(Double, Double, Double, Double)],
  box_name : PdfName,
) -> PdfPage raise PdfError {
  ignore(self)
  {
    ..page,
    rest: page.rest.add_dict_entry(
      box_name,
      pdf_page_box_xywh_object(boxes[page_number - 1]),
    ),
  }
}

///|
fn PdfDocument::pdf_page_set_box_page(
  self : PdfDocument,
  page : PdfPage,
  box_name : PdfName,
  min_x : Double,
  max_x : Double,
  min_y : Double,
  max_y : Double,
) -> PdfPage raise PdfError {
  ignore(self)
  {
    ..page,
    rest: page.rest.add_dict_entry(
      box_name,
      pdf_page_box_bounds_object((min_x, min_y, max_x, max_y)),
    ),
  }
}

///|
fn PdfDocument::pdf_page_change_box_object(
  self : PdfDocument,
  object : PdfObject,
  transform : (Double, Double, Double, Double) -> (
    Double,
    Double,
    Double,
    Double,
  ),
) -> PdfObject raise PdfError {
  let bounds = self.parse_rectangle(object)
  pdf_page_box_bounds_object(
    transform(bounds.min_x, bounds.min_y, bounds.max_x, bounds.max_y),
  )
}

///|
/// Hard-clip selected pages to a page box by prepending a clipping rectangle.
///
/// `page_numbers` are 1-based. `box_name` is usually `/MediaBox`, `/CropBox`,
/// `/TrimBox`, `/ArtBox`, or `/BleedBox`. Missing non-media boxes raise unless
/// `mediabox_if_missing` is true. In `fast` mode the clip stream is prepended
/// without parsing existing content.
pub fn PdfDocument::hard_box(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : PdfName,
  mediabox_if_missing? : Bool = false,
  fast? : Bool = false,
) -> PdfDocument raise PdfError {
  self.pdf_page_box_rewrite_pages(page_numbers, "hard_box", (_, _, page) => {
    self.pdf_page_hard_box_page(page, box_name, mediabox_if_missing, fast)
  })
}

///|
/// Compatibility wrapper for `PdfDocument::hard_box`.
pub fn pdf_hard_box(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : PdfName,
  mediabox_if_missing? : Bool = false,
  fast? : Bool = false,
) -> PdfDocument raise PdfError {
  document.hard_box(page_numbers, box_name, mediabox_if_missing~, fast~)
}

///|
/// Compatibility wrapper using cpdfpage's string page-box names.
pub fn PdfDocument::hard_box_string(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : String,
  mediabox_if_missing? : Bool = false,
  fast? : Bool = false,
) -> PdfDocument raise PdfError {
  self.hard_box(
    page_numbers,
    pdf_page_box_name_of_string(box_name),
    mediabox_if_missing~,
    fast~,
  )
}

///|
/// Compatibility wrapper using cpdfpage's string page-box names.
pub fn pdf_hard_box_string(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : String,
  mediabox_if_missing? : Bool = false,
  fast? : Bool = false,
) -> PdfDocument raise PdfError {
  document.hard_box_string(page_numbers, box_name, mediabox_if_missing~, fast~)
}

///|
/// Return whether a 1-based page has a named non-media page box.
///
/// This mirrors cpdf's `hasbox`: invalid page numbers raise, and the check is
/// performed against the page's explicit dictionary entries rather than treating
/// `/MediaBox` as always present.
pub fn PdfDocument::has_page_box(
  self : PdfDocument,
  page_number : Int,
  box_name : PdfName,
) -> Bool raise PdfError {
  let pages = self.pages_of_pagetree()
  if page_number < 1 || page_number > pages.length() {
    raise BadPageSpecification("hasbox: bad page")
  }
  match self.lookup_direct(box_name, pages[page_number - 1].rest) {
    Some(_) => true
    None => false
  }
}

///|
/// Compatibility wrapper for `PdfDocument::has_page_box`.
pub fn pdf_hasbox(
  document : PdfDocument,
  page_number : Int,
  box_name : PdfName,
) -> Bool raise PdfError {
  document.has_page_box(page_number, box_name)
}

///|
/// Compatibility wrapper using cpdfpage's string page-box names.
pub fn PdfDocument::hasbox_string(
  self : PdfDocument,
  page_number : Int,
  box_name : String,
) -> Bool raise PdfError {
  self.has_page_box(page_number, pdf_page_box_name_of_string(box_name))
}

///|
/// Compatibility wrapper using cpdfpage's string page-box names.
pub fn pdf_hasbox_string(
  document : PdfDocument,
  page_number : Int,
  box_name : String,
) -> Bool raise PdfError {
  document.hasbox_string(page_number, box_name)
}

///|
/// Copy one page-box value to another on selected pages.
///
/// Missing source boxes leave the page unchanged unless `mediabox_if_missing`
/// is true, in which case the page `/MediaBox` is copied.
pub fn PdfDocument::copy_page_box(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  from_box : PdfName,
  to_box : PdfName,
  mediabox_if_missing? : Bool = false,
) -> PdfDocument raise PdfError {
  self.pdf_page_box_rewrite_pages(page_numbers, "copy_page_box", (_, _, page) => {
    self.pdf_page_copy_box_page(page, from_box, to_box, mediabox_if_missing)
  })
}

///|
/// Compatibility wrapper for `PdfDocument::copy_page_box`.
pub fn pdf_copy_page_box(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  from_box : PdfName,
  to_box : PdfName,
  mediabox_if_missing? : Bool = false,
) -> PdfDocument raise PdfError {
  document.copy_page_box(page_numbers, from_box, to_box, mediabox_if_missing~)
}

///|
/// Compatibility wrapper using cpdfpage's string page-box names.
pub fn PdfDocument::copy_box(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  from_box : String,
  to_box : String,
  mediabox_if_missing? : Bool = false,
) -> PdfDocument raise PdfError {
  self.copy_page_box(
    page_numbers,
    pdf_page_box_name_of_string(from_box),
    pdf_page_box_name_of_string(to_box),
    mediabox_if_missing~,
  )
}

///|
/// Compatibility wrapper matching cpdfpage's `copy_box` argument order.
pub fn pdf_copy_box(
  from_box : String,
  to_box : String,
  mediabox_if_missing : Bool,
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.copy_box(page_numbers, from_box, to_box, mediabox_if_missing~)
}

///|
/// Change `/MediaBox` and known page boxes with a coordinate transform.
///
/// The callback receives `(min_x, min_y, max_x, max_y)` and returns replacement
/// bounds. This ports cpdf's single-page `change_boxes` helper.
pub fn PdfDocument::change_boxes(
  self : PdfDocument,
  page : PdfPage,
  transform : (Double, Double, Double, Double) -> (
    Double,
    Double,
    Double,
    Double,
  ),
) -> PdfPage raise 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.pdf_page_change_box_object(value, transform),
        )
      None => ()
    }
  }
  {
    ..page,
    mediabox: self.pdf_page_change_box_object(page.mediabox, transform),
    rest,
  }
}

///|
/// Compatibility wrapper for `PdfDocument::change_boxes`.
pub fn pdf_change_boxes(
  document : PdfDocument,
  page : PdfPage,
  transform : (Double, Double, Double, Double) -> (
    Double,
    Double,
    Double,
    Double,
  ),
) -> PdfPage raise PdfError {
  document.change_boxes(page, transform)
}

///|
/// Compatibility wrapper matching cpdfpage's `change_boxes` argument order.
pub fn pdf_change_boxes_cpdf_order(
  transform : (Double, Double, Double, Double) -> (
    Double,
    Double,
    Double,
    Double,
  ),
  document : PdfDocument,
  page : PdfPage,
) -> PdfPage raise PdfError {
  document.change_boxes(page, transform)
}

///|
/// Set `/MediaBox` on selected pages from a page-indexed `(x, y, width, height)`
/// list.
///
/// `boxes` must contain one entry for every page in the document, matching
/// cpdf's rectangle parser. `page_numbers` selects which page entries are
/// applied, and each selected page uses `boxes[page_number - 1]`.
pub fn PdfDocument::set_mediaboxes(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  boxes : ArrayView[(Double, Double, Double, Double)],
) -> PdfDocument raise PdfError {
  let pages = self.pages_of_pagetree()
  pdf_page_box_validate_page_numbers(
    page_numbers,
    pages.length(),
    "set_mediaboxes",
  )
  pdf_page_box_validate_xywh_boxes(boxes, pages.length())
  let selected_pages = @number_set.pdf_number_set(page_numbers)
  let rewritten : Array[PdfPage] = Array::new(capacity=pages.length())
  for index in 0.. PdfDocument raise PdfError {
  self.set_mediaboxes(page_numbers, boxes)
}

///|
/// Compatibility wrapper for `PdfDocument::set_mediaboxes`.
pub fn pdf_set_mediaboxes(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  boxes : ArrayView[(Double, Double, Double, Double)],
) -> PdfDocument raise PdfError {
  document.set_mediaboxes(page_numbers, boxes)
}

///|
/// Compatibility wrapper matching cpdfpage's `set_mediabox` argument order.
pub fn pdf_set_mediabox(
  boxes : ArrayView[(Double, Double, Double, Double)],
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.set_mediaboxes(page_numbers, boxes)
}

///|
/// Set a named page box on selected pages from a page-indexed `(x, y, width,
/// height)` list.
///
/// This ports cpdf's `crop_pdf`. By default it writes `/CropBox`; `box_name`
/// can target another page-box dictionary entry. The selected pages use
/// `boxes[page_number - 1]`.
pub fn PdfDocument::crop_pages(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  boxes : ArrayView[(Double, Double, Double, Double)],
  box_name? : PdfName = pdf_page_cropbox_key(),
) -> PdfDocument raise PdfError {
  let pages = self.pages_of_pagetree()
  pdf_page_box_validate_page_numbers(page_numbers, pages.length(), "crop_pages")
  pdf_page_box_validate_xywh_boxes_with_context(
    boxes,
    pages.length(),
    "crop_pages",
  )
  let selected_pages = @number_set.pdf_number_set(page_numbers)
  let rewritten : Array[PdfPage] = Array::new(capacity=pages.length())
  for index in 0.. PdfDocument raise PdfError {
  document.crop_pages(page_numbers, boxes, box_name~)
}

///|
/// Compatibility wrapper using cpdfpage's string page-box names.
pub fn PdfDocument::crop_pdf_string(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  boxes : ArrayView[(Double, Double, Double, Double)],
  box_name? : String = "/CropBox",
) -> PdfDocument raise PdfError {
  self.crop_pages(
    page_numbers,
    boxes,
    box_name=pdf_page_box_name_of_string(box_name),
  )
}

///|
/// Compatibility wrapper matching cpdfpage's `crop_pdf` value argument order.
pub fn pdf_crop_pdf_string(
  boxes : ArrayView[(Double, Double, Double, Double)],
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name? : String = "/CropBox",
) -> PdfDocument raise PdfError {
  document.crop_pdf_string(page_numbers, boxes, box_name~)
}

///|
/// Set a fixed named page box on selected pages.
///
/// The scalar argument order mirrors cpdf's historical `setBox`:
/// `(min_x, max_x, min_y, max_y)`.
pub fn PdfDocument::set_page_box(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : PdfName,
  min_x : Double,
  max_x : Double,
  min_y : Double,
  max_y : Double,
) -> PdfDocument raise PdfError {
  self.pdf_page_box_rewrite_pages(page_numbers, "set_page_box", (_, _, page) => {
    self.pdf_page_set_box_page(page, box_name, min_x, max_x, min_y, max_y)
  })
}

///|
/// Compatibility wrapper for `PdfDocument::set_page_box`.
pub fn pdf_set_box(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : PdfName,
  min_x : Double,
  max_x : Double,
  min_y : Double,
  max_y : Double,
) -> PdfDocument raise PdfError {
  document.set_page_box(page_numbers, box_name, min_x, max_x, min_y, max_y)
}

///|
/// Compatibility wrapper using cpdfpage's string page-box names.
pub fn PdfDocument::set_box_string(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : String,
  min_x : Double,
  max_x : Double,
  min_y : Double,
  max_y : Double,
) -> PdfDocument raise PdfError {
  self.set_page_box(
    page_numbers,
    pdf_page_box_name_of_string(box_name),
    min_x,
    max_x,
    min_y,
    max_y,
  )
}

///|
/// Compatibility wrapper matching cpdfpage's `setBox` scalar argument order.
pub fn pdf_set_box_string(
  box_name : String,
  min_x : Double,
  max_x : Double,
  min_y : Double,
  max_y : Double,
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.set_box_string(page_numbers, box_name, min_x, max_x, min_y, max_y)
}

///|
/// Shift `/MediaBox` and known page boxes by page-indexed offsets.
///
/// This ports cpdf's `shift_boxes`: offsets are indexed by absolute page number
/// and content streams, annotations, and destination coordinates are not moved.
pub fn PdfDocument::shift_boxes(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  offsets : ArrayView[(Double, Double)],
) -> PdfDocument raise PdfError {
  let pages = self.pages_of_pagetree()
  pdf_page_box_validate_page_numbers(
    page_numbers,
    pages.length(),
    "shift_boxes",
  )
  pdf_page_box_validate_offsets(offsets, pages.length())
  let selected_pages = @number_set.pdf_number_set(page_numbers)
  let rewritten : Array[PdfPage] = Array::new(capacity=pages.length())
  for index in 0.. {
          (
            min_x + offset.0,
            min_y + offset.1,
            max_x + offset.0,
            max_y + offset.1,
          )
        }),
      )
    } else {
      rewritten.push(pages[index])
    }
  }
  self.change_pages(rewritten, change_references=true)
}

///|
/// Rectify a page so its media-box origin is `(0, 0)`.
///
/// Known page boxes are shifted by the same amount, and page content,
/// annotations, and pattern matrices receive the compensating translation.
pub fn PdfDocument::rectify_boxes(
  self : PdfDocument,
  page : PdfPage,
  fast? : Bool = false,
) -> PdfPage raise PdfError {
  let bounds = self.parse_rectangle(page.mediabox)
  let page = self.change_boxes(page, (min_x, min_y, max_x, max_y) => {
    (
      min_x - bounds.min_x,
      min_y - bounds.min_y,
      max_x - bounds.min_x,
      max_y - bounds.min_y,
    )
  })
  if bounds.min_x != 0.0 || bounds.min_y != 0.0 {
    self.pdf_page_shift_page(
      page,
      transform_translate(-bounds.min_x, -bounds.min_y),
      fast,
    )
  } else {
    page
  }
}

///|
/// Compatibility wrapper for `PdfDocument::rectify_boxes`.
pub fn pdf_rectify_boxes(
  document : PdfDocument,
  page : PdfPage,
  fast? : Bool = false,
) -> PdfPage raise PdfError {
  document.rectify_boxes(page, fast~)
}

///|
/// Compatibility wrapper for `PdfDocument::shift_boxes`.
pub fn pdf_shift_boxes(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  offsets : ArrayView[(Double, Double)],
) -> PdfDocument raise PdfError {
  document.shift_boxes(page_numbers, offsets)
}

///|
/// Compatibility wrapper matching cpdfpage's `shift_boxes` argument order.
pub fn pdf_shift_boxes_cpdf_order(
  offsets : ArrayView[(Double, Double)],
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.shift_boxes(page_numbers, offsets)
}

///|
/// Remove one page-box dictionary entry from selected pages.
pub fn PdfDocument::remove_page_box(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : PdfName,
) -> PdfDocument raise PdfError {
  self.pdf_page_box_rewrite_pages(page_numbers, "remove_page_box", (_, _, page) => {
    self.pdf_page_remove_box_page(page, box_name)
  })
}

///|
/// Compatibility wrapper for `PdfDocument::remove_page_box`.
pub fn pdf_remove_page_box(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
  box_name : PdfName,
) -> PdfDocument raise PdfError {
  document.remove_page_box(page_numbers, box_name)
}

///|
/// Remove `/CropBox` entries from selected pages.
pub fn PdfDocument::remove_cropping(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  self.remove_page_box(page_numbers, pdf_page_cropbox_key())
}

///|
/// Compatibility wrapper for `PdfDocument::remove_cropping`.
pub fn pdf_remove_cropping_pdf(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.remove_cropping(page_numbers)
}

///|
/// Remove `/TrimBox` entries from selected pages.
pub fn PdfDocument::remove_trim(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  self.remove_page_box(page_numbers, pdf_page_trimbox_key())
}

///|
/// Compatibility wrapper for `PdfDocument::remove_trim`.
pub fn pdf_remove_trim_pdf(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.remove_trim(page_numbers)
}

///|
/// Remove `/ArtBox` entries from selected pages.
pub fn PdfDocument::remove_art(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  self.remove_page_box(page_numbers, pdf_page_artbox_key())
}

///|
/// Compatibility wrapper for `PdfDocument::remove_art`.
pub fn pdf_remove_art_pdf(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.remove_art(page_numbers)
}

///|
/// Remove `/BleedBox` entries from selected pages.
pub fn PdfDocument::remove_bleed(
  self : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  self.remove_page_box(page_numbers, pdf_page_bleedbox_key())
}

///|
/// Compatibility wrapper for `PdfDocument::remove_bleed`.
pub fn pdf_remove_bleed_pdf(
  document : PdfDocument,
  page_numbers : ArrayView[Int],
) -> PdfDocument raise PdfError {
  document.remove_bleed(page_numbers)
}