///|
fn pdf_impose_validate_transform_inputs(
  x : Int,
  y : Int,
  count : Int,
) -> Unit raise PdfError {
  if x <= 0 || y <= 0 {
    raise BadNumberArgument("impose: x and y must be positive")
  }
  if count < 0 {
    raise BadNumberArgument("impose: page count must be non-negative")
  }
}

///|
fn pdf_impose_order(
  row : Int,
  col : Int,
  x : Int,
  y : Int,
  rtl : Bool,
  btt : Bool,
) -> (Int, Int) {
  (if btt { y - row - 1 } else { row }, if rtl { x - col - 1 } else { col })
}

///|
fn pdf_impose_adjusted_row(
  original_row : Int,
  y : Int,
  final_full_rows : Int,
  remaining : Int,
  center : Bool,
) -> Int {
  if center && remaining <= final_full_rows {
    let final_empty_rows = y - final_full_rows
    original_row + (y - 1 - 1 - final_empty_rows / 2)
  } else {
    original_row
  }
}

///|
fn pdf_impose_adjusted_col(
  original_col : Int,
  x : Int,
  final_full_cols : Int,
  remaining : Int,
  center : Bool,
) -> Int {
  if center && remaining <= final_full_cols {
    let final_empty_cols = x - final_full_cols
    original_col + (x - 1 - 1 - final_empty_cols / 2)
  } else {
    original_col
  }
}

///|
fn pdf_impose_translate(
  x : Int,
  rtl : Bool,
  btt : Bool,
  cent_extra_x : Double,
  cent_extra_y : Double,
  fit_extra_hspace : Double,
  fit_extra_vspace : Double,
  row : Int,
  col : Int,
  px : Double,
  py : Double,
) -> TransformMatrix {
  let cex = if rtl { -cent_extra_x } else { cent_extra_x }
  let cey = if btt { -cent_extra_y } else { cent_extra_y }
  let space_col = if rtl { x - col - 1 } else { col }
  let total_fit_extra_hspace = fit_extra_hspace * (space_col.to_double() + 1.0)
  let total_fit_extra_vspace = fit_extra_vspace * (row.to_double() + 1.0)
  transform_translate(
    px + cex + total_fit_extra_hspace,
    py + cey + total_fit_extra_vspace,
  )
}

///|
fn PdfDocument::pdf_impose_make_margin(
  self : PdfDocument,
  output_mediabox : PdfObject,
  margin : Double,
  matrix : TransformMatrix,
) -> TransformMatrix raise PdfError {
  if margin == 0.0 {
    matrix
  } else {
    let box = self.parse_rectangle(output_mediabox)
    let width = box.max_x - box.min_x
    let height = box.max_y - box.min_y
    if margin > width / 2.0 || margin > height / 2.0 {
      raise BadNumberArgument("impose: margin would fill whole page")
    }
    let hfactor = (width - margin - margin) / width
    let vfactor = (height - margin - margin) / height
    let factor = if hfactor < vfactor { hfactor } else { vfactor }
    let scale = transform_scale(point2(0.0, 0.0), factor, factor)
    let shift = transform_translate(
      (width - width * factor) / 2.0,
      (height - height * factor) / 2.0,
    )
    transform_matrix_compose(shift, transform_matrix_compose(scale, matrix))
  }
}

///|
fn PdfDocument::pdf_impose_transform_for_slot(
  self : PdfDocument,
  fit : Bool,
  x : Int,
  rtl : Bool,
  btt : Bool,
  margin : Double,
  output_mediabox : PdfObject,
  fit_extra_hspace : Double,
  fit_extra_vspace : Double,
  cent_extra_x : Double,
  cent_extra_y : Double,
  row : Int,
  col : Int,
  px : Double,
  py : Double,
) -> TransformMatrix raise PdfError {
  let matrix = pdf_impose_translate(
    x, rtl, btt, cent_extra_x, cent_extra_y, fit_extra_hspace, fit_extra_vspace,
    row, col, px, py,
  )
  if fit {
    self.pdf_impose_make_margin(output_mediabox, margin, matrix)
  } else {
    matrix
  }
}

///|
#warnings("-unused_field")
priv struct PdfImposeLayout {
  pages_per_sheet : Int
  x_slots : Int
  y_slots : Int
  output_mediabox : PdfObject
  fit_extra_hspace : Double
  fit_extra_vspace : Double
}

///|
fn pdf_impose_output_box(width : Double, height : Double) -> PdfObject {
  PdfArray([PdfReal(0.0), PdfReal(0.0), PdfReal(width), PdfReal(height)])
}

///|
fn PdfDocument::pdf_impose_fit_layout(
  self : PdfDocument,
  x : Double,
  y : Double,
  page_width : Double,
  page_height : Double,
) -> PdfImposeLayout raise PdfError {
  ignore(self)
  let across = @math.floor(x / page_width + 0.001).to_int()
  let down = @math.floor(y / page_height + 0.001).to_int()
  if across < 1 || down < 1 {
    raise BadNumberArgument("impose: not even a single page would fit")
  }
  {
    pages_per_sheet: across * down,
    x_slots: across,
    y_slots: down,
    output_mediabox: pdf_impose_output_box(x, y),
    fit_extra_hspace: (x - across.to_double() * page_width) /
    (across.to_double() + 1.0),
    fit_extra_vspace: (y - down.to_double() * page_height) /
    (down.to_double() + 1.0),
  }
}

///|
fn PdfDocument::pdf_impose_xy_layout(
  self : PdfDocument,
  x : Double,
  y : Double,
  margin : Double,
  page_count : Int,
  page_width : Double,
  page_height : Double,
) -> PdfImposeLayout raise PdfError {
  ignore(self)
  let ix = x.to_int()
  let iy = y.to_int()
  if ix == 0 && iy == 0 {
    raise BadNumberArgument("impose-xy: both dimensions cannot be zero")
  }
  let (pages_per_sheet, x_slots, y_slots) = if ix == 0 {
    (page_count, page_count, 1)
  } else if iy == 0 {
    (page_count, 1, page_count)
  } else {
    (ix * iy, ix, iy)
  }
  let margin2 = margin * 2.0
  let output_mediabox = if x == 0.0 {
    pdf_impose_output_box(
      page_width * page_count.to_double() + margin2,
      page_height + margin2,
    )
  } else if y == 0.0 {
    pdf_impose_output_box(
      page_width + margin2,
      page_height * page_count.to_double() + margin2,
    )
  } else {
    pdf_impose_output_box(page_width * x + margin2, page_height * y + margin2)
  }
  {
    pages_per_sheet,
    x_slots,
    y_slots,
    output_mediabox,
    fit_extra_hspace: 0.0,
    fit_extra_vspace: 0.0,
  }
}

///|
#warnings("-unused_value")
fn PdfDocument::pdf_impose_layout(
  self : PdfDocument,
  fit : Bool,
  x : Double,
  y : Double,
  margin : Double,
  page_count : Int,
  mediabox : PdfObject,
) -> PdfImposeLayout raise PdfError {
  let bounds = self.parse_rectangle(mediabox)
  let page_width = bounds.max_x - bounds.min_x
  let page_height = bounds.max_y - bounds.min_y
  if fit {
    self.pdf_impose_fit_layout(x, y, page_width, page_height)
  } else {
    self.pdf_impose_xy_layout(x, y, margin, page_count, page_width, page_height)
  }
}

///|
fn pdf_impose_split_pages(
  pages : ArrayView[PdfPage],
  chunk_size : Int,
) -> Array[Array[PdfPage]] {
  let chunks : Array[Array[PdfPage]] = []
  let mut index = 0
  while index < pages.length() {
    let chunk : Array[PdfPage] = []
    let stop = if index + chunk_size < pages.length() {
      index + chunk_size
    } else {
      pages.length()
    }
    for page_index in index.. Array[(Int, Int)] {
  let changes : Array[(Int, Int)] = []
  for page_number in 1..<=page_count {
    changes.push(
      (page_number, (page_number + pages_per_sheet - 1) / pages_per_sheet),
    )
  }
  changes
}

///|
fn PdfDocument::pdf_impose_preprocess(
  self : PdfDocument,
  fit : Bool,
  spacing : Double,
  line_width : Double,
  fast : Bool,
) -> PdfDocument raise PdfError {
  let end_page = self.endpage()
  let all_pages = pdf_impose_all_pages(end_page)
  self
  .copy_page_box(
    all_pages,
    pdf_page_cropbox_key(),
    pdf_page_mediabox_key(),
    mediabox_if_missing=true,
  )
  .remove_cropping(all_pages)
  .upright_pages(all_pages, fast~)
  .pdf_impose_add_border(line_width, fast)
  .pdf_impose_make_space(fit, spacing, fast)
}

///|
/// Impose pages into cpdf-style sheets.
///
/// In non-fit mode, `x` and `y` are grid dimensions; one of them may be zero to
/// stack all pages in the other direction. In fit mode, `x` and `y` are the
/// output page width and height, and the grid is calculated from the current
/// page size.
pub fn PdfDocument::impose(
  self : PdfDocument,
  x : Double,
  y : Double,
  fit? : Bool = false,
  columns? : Bool = false,
  rtl? : Bool = false,
  btt? : Bool = false,
  center? : Bool = false,
  margin? : Double = 0.0,
  spacing? : Double = 0.0,
  line_width? : Double = 0.0,
  fast? : Bool = false,
  process_struct_tree? : Bool = false,
) -> PdfDocument raise PdfError {
  let source = if process_struct_tree {
    self.mark_all_as_artifact()
  } else {
    self
  }
  let original_page_count = source.endpage()
  if original_page_count == 0 {
    raise BadNumberArgument("impose: pages must not be empty")
  }
  let prepared = source.pdf_impose_preprocess(fit, spacing, line_width, fast)
  let prepared_pages = prepared.pages_of_pagetree()
  let layout = prepared.pdf_impose_layout(
    fit,
    x,
    y,
    margin,
    original_page_count,
    prepared_pages[0].mediabox,
  )
  let imposed_pages : Array[PdfPage] = []
  for page_set in pdf_impose_split_pages(prepared_pages, layout.pages_per_sheet) {
    imposed_pages.push(
      prepared.pdf_impose_pages_core(
        prepared.renumber_pages(page_set),
        fit,
        layout.x_slots,
        layout.y_slots,
        columns,
        rtl,
        btt,
        center,
        margin,
        layout.output_mediabox,
        fast,
        layout.fit_extra_hspace,
        layout.fit_extra_vspace,
      ),
    )
  }
  let imposed = prepared.change_pages(
    imposed_pages,
    change_references=true,
    changes=pdf_impose_page_reference_changes(
      original_page_count,
      layout.pages_per_sheet,
    ),
  )
  if fit {
    imposed
  } else {
    let output_count = imposed.endpage()
    imposed.shift_pages(
      pdf_impose_all_pages(output_count),
      pdf_impose_repeated_offsets(output_count, (margin, margin)),
      fast~,
    )
  }
}

///|
/// Compatibility wrapper for `PdfDocument::impose`.
pub fn pdf_impose(
  document : PdfDocument,
  x : Double,
  y : Double,
  fit? : Bool = false,
  columns? : Bool = false,
  rtl? : Bool = false,
  btt? : Bool = false,
  center? : Bool = false,
  margin? : Double = 0.0,
  spacing? : Double = 0.0,
  line_width? : Double = 0.0,
  fast? : Bool = false,
  process_struct_tree? : Bool = false,
) -> PdfDocument raise PdfError {
  document.impose(
    x,
    y,
    fit~,
    columns~,
    rtl~,
    btt~,
    center~,
    margin~,
    spacing~,
    line_width~,
    fast~,
    process_struct_tree~,
  )
}

///|
/// Legacy cpdf two-up stack operation.
///
/// This first imposes source pages in a 2x1 non-fit grid, then rotates the
/// imposed sheets by -90 degrees and uprights them into ordinary page geometry.
pub fn PdfDocument::twoup_stack(
  self : PdfDocument,
  fast? : Bool = false,
  process_struct_tree? : Bool = false,
) -> PdfDocument raise PdfError {
  let imposed = self.impose(2.0, 1.0, fast~, process_struct_tree~)
  let all_pages = pdf_impose_all_pages(imposed.endpage())
  imposed.rotate_pages(-90, all_pages).upright_pages(all_pages, fast~)
}

///|
/// Compatibility wrapper for `PdfDocument::twoup_stack`.
pub fn pdf_twoup_stack(
  document : PdfDocument,
  fast? : Bool = false,
  process_struct_tree? : Bool = false,
) -> PdfDocument raise PdfError {
  document.twoup_stack(fast~, process_struct_tree~)
}

///|
/// Legacy cpdf two-up operation.
///
/// This scales source pages down, imposes them 2x1, rotates/uprights the
/// imposed sheets, then scales each sheet back to the first page's original
/// size.
pub fn PdfDocument::twoup(
  self : PdfDocument,
  fast? : Bool = false,
  process_struct_tree? : Bool = false,
) -> PdfDocument raise PdfError {
  let pages = self.pages_of_pagetree()
  if pages.length() == 0 {
    raise BadNumberArgument("twoup: pages must not be empty")
  }
  let bounds = self.parse_rectangle(pages[0].mediabox)
  let width = bounds.max_x - bounds.min_x
  let height = bounds.max_y - bounds.min_y
  let scale = if width > height {
    let page_ratio = height / width
    let sheet_ratio = width / 2.0 / height
    if page_ratio < sheet_ratio {
      page_ratio
    } else {
      sheet_ratio
    }
  } else {
    let page_ratio = width / height
    let sheet_ratio = height / 2.0 / width
    if page_ratio < sheet_ratio {
      page_ratio
    } else {
      sheet_ratio
    }
  }
  let source_count = self.endpage()
  let source_pages = pdf_impose_all_pages(source_count)
  let scaled = self.scale_pages(
    source_pages,
    pdf_impose_repeated_scales(source_count, (scale, scale)),
    fast~,
  )
  let imposed = scaled.impose(
    2.0,
    1.0,
    center=true,
    fast~,
    process_struct_tree~,
  )
  let output_count = imposed.endpage()
  let output_pages = pdf_impose_all_pages(output_count)
  let upright = imposed
    .rotate_pages(-90, output_pages)
    .upright_pages(output_pages, fast~)
  upright.scale_to_fit_pages(
    output_pages,
    pdf_impose_repeated_scales(output_count, (width, height)),
    position=PdfPositionDiagonal,
    fast~,
  )
}

///|
/// Compatibility wrapper for `PdfDocument::twoup`.
pub fn pdf_twoup(
  document : PdfDocument,
  fast? : Bool = false,
  process_struct_tree? : Bool = false,
) -> PdfDocument raise PdfError {
  document.twoup(fast~, process_struct_tree~)
}

///|
fn pdf_impose_concat_ops(
  first : ArrayView[PdfContentOp],
  second : ArrayView[PdfContentOp],
) -> Array[PdfContentOp] {
  let output : Array[PdfContentOp] = []
  for op in first {
    output.push(op)
  }
  for op in second {
    output.push(op)
  }
  output
}

///|
fn pdf_impose_push_objects(
  output : Array[PdfObject],
  objects : ArrayView[PdfObject],
) -> Unit {
  for object in objects {
    output.push(object)
  }
}

///|
fn pdf_impose_all_pages(end_page : Int) -> Array[Int] {
  let pages : Array[Int] = []
  for page_number in 1..<=end_page {
    pages.push(page_number)
  }
  pages
}

///|
fn pdf_impose_repeated_offsets(
  count : Int,
  offset : (Double, Double),
) -> Array[(Double, Double)] {
  let offsets : Array[(Double, Double)] = []
  for _ in 0.. Array[(Double, Double)] {
  let scales : Array[(Double, Double)] = []
  for _ in 0.. Array[(Double, Double, Double, Double)] {
  let boxes : Array[(Double, Double, Double, Double)] = []
  for _ in 0.. PdfDocument raise PdfError {
  let end_page = self.endpage()
  let all_pages = pdf_impose_all_pages(end_page)
  let boxed = self.hard_box(all_pages, pdf_page_mediabox_key(), fast~)
  if spacing == 0.0 || end_page == 0 {
    boxed
  } else {
    let margin = spacing / 2.0
    let pages = boxed.pages_of_pagetree()
    let first_bounds = boxed.parse_rectangle(pages[0].mediabox)
    let width = first_bounds.max_x - first_bounds.min_x
    let height = first_bounds.max_y - first_bounds.min_y
    let offsets = pdf_impose_repeated_offsets(end_page, (margin, margin))
    if fit {
      boxed
      .scale_contents(
        all_pages,
        PdfPositionBottomLeft(0.0, 0.0),
        (width - spacing) / width,
        fast~,
      )
      .shift_pages(all_pages, offsets, fast~)
    } else {
      boxed
      .shift_pages(all_pages, offsets, fast~)
      .set_mediaboxes(
        all_pages,
        pdf_impose_repeated_boxes(
          end_page,
          (0.0, 0.0, width + spacing, height + spacing),
        ),
      )
    }
  }
}

///|
let pdf_impose_cpdf_stamp_name : PdfName = pdf_page_name("/CPDFSTAMP")

///|
fn pdf_impose_border_ops(
  x : Double,
  y : Double,
  width : Double,
  height : Double,
  line_width : Double,
) -> Array[PdfContentOp] {
  [
    pdf_content_begin_artifact(),
    Op_q,
    Op_BMC(pdf_impose_cpdf_stamp_name),
    Op_rg(0.0, 0.0, 0.0),
    Op_RG(0.0, 0.0, 0.0),
    Op_w(line_width),
    Op_re(x, y, width, height),
    Op_s,
    Op_EMC,
    Op_Q,
    pdf_content_end_artifact(),
  ]
}

///|
#warnings("-unused_value")
fn PdfDocument::pdf_impose_add_border(
  self : PdfDocument,
  line_width : Double,
  fast : Bool,
) -> PdfDocument raise PdfError {
  let end_page = self.endpage()
  if line_width == 0.0 || end_page == 0 {
    self
  } else {
    let pages = self.pages_of_pagetree()
    let first_bounds = self.parse_rectangle(pages[0].mediabox)
    let inset = line_width / 2.0
    self.append_page_content_ops(
      pdf_impose_all_pages(end_page),
      pdf_impose_border_ops(
        first_bounds.min_x + inset,
        first_bounds.min_y + inset,
        first_bounds.max_x - line_width,
        first_bounds.max_y - line_width,
        line_width,
      ),
      fast~,
    )
  }
}

///|
let pdf_impose_matrix_key_name : PdfName = pdf_page_name("/Matrix")

///|
fn pdf_impose_pattern_name_used(
  used_names : ArrayView[PdfName],
  name : PdfName,
) -> Bool {
  for used_name in used_names {
    if used_name == name {
      break true
    }
  } nobreak {
    false
  }
}

///|
fn pdf_impose_pattern_add_used(
  used_names : Array[PdfName],
  name : PdfName,
) -> Unit {
  if !pdf_impose_pattern_name_used(used_names, name) {
    used_names.push(name)
  }
}

///|
fn PdfDocument::pdf_impose_patterns_used_with_scn(
  self : PdfDocument,
  content : ArrayView[PdfObject],
  resources : PdfObject,
) -> Array[PdfName] raise PdfError {
  let used_names : Array[PdfName] = []
  match self.lookup_direct(pdf_page_pattern_resource_name, resources) {
    Some(_) => {
      let ops = self.parse_content_ops_with_resources(resources, content)
      for op in ops {
        match op {
          Op_scnName(name, []) | Op_SCNName(name, []) =>
            pdf_impose_pattern_add_used(used_names, name)
          _ => ()
        }
      }
    }
    None => ()
  }
  used_names
}

///|
fn pdf_impose_xobject_done(done : ArrayView[Int], number : Int) -> Bool {
  for item in done {
    if item == number {
      break true
    }
  } nobreak {
    false
  }
}

///|
fn PdfDocument::pdf_impose_change_pattern_object(
  self : PdfDocument,
  matrix : TransformMatrix,
  pattern : PdfObject,
) -> PdfObject raise PdfError {
  let old_pattern = self.direct(pattern)
  let existing = self.parse_matrix(pdf_impose_matrix_key_name, old_pattern)
  let new_matrix = transform_matrix_compose(matrix, existing)
  PdfIndirect(
    self.add_object(
      old_pattern.add_dict_entry(
        pdf_impose_matrix_key_name,
        pdf_object_of_matrix(new_matrix),
      ),
    ),
  )
}

///|
fn PdfDocument::pdf_impose_change_pattern_matrices_resources(
  self : PdfDocument,
  matrix : TransformMatrix,
  resources : PdfObject,
  names_used_with_scn : ArrayView[PdfName],
  xobjects_done : Array[Int],
) -> PdfObject raise PdfError {
  match self.lookup_direct(pdf_page_xobject_key(), resources) {
    Some(PdfDictionary(entries)) =>
      for entry in entries {
        match entry.1 {
          PdfIndirect(number) =>
            self.pdf_impose_change_pattern_matrices_xobject(
              matrix,
              entry.1,
              number,
              xobjects_done,
            )
          _ => raise DictionaryExpected
        }
      }
    _ => ()
  }
  match self.lookup_direct(pdf_page_pattern_resource_name, resources) {
    Some(PdfDictionary(patterns)) => {
      let entries : Array[(PdfName, PdfObject)] = []
      for entry in patterns {
        let (name, pattern) = entry
        if pdf_impose_pattern_name_used(names_used_with_scn, name) {
          entries.push(
            (name, self.pdf_impose_change_pattern_object(matrix, pattern)),
          )
        } else {
          entries.push(entry)
        }
      }
      resources.add_dict_entry(
        pdf_page_pattern_resource_name,
        PdfDictionary(entries),
      )
    }
    _ => resources
  }
}

///|
fn PdfDocument::pdf_impose_change_pattern_matrices_xobject(
  self : PdfDocument,
  matrix : TransformMatrix,
  xobject : PdfObject,
  xobject_number : Int,
  xobjects_done : Array[Int],
) -> Unit raise PdfError {
  if pdf_impose_xobject_done(xobjects_done, xobject_number) {
    ()
  } else {
    xobjects_done.push(xobject_number)
    let direct_xobject = self.direct(xobject)
    match self.lookup_direct(pdf_page_subtype_key(), direct_xobject) {
      Some(PdfNameObject(name)) if name == pdf_page_type_form() => {
        let resources = match
          self.lookup_direct(pdf_page_resources_key(), direct_xobject) {
          Some(value) => value
          None => PdfDictionary([])
        }
        let used = self.pdf_impose_patterns_used_with_scn(
          [direct_xobject],
          resources,
        )
        match self.lookup_direct(pdf_page_resources_key(), direct_xobject) {
          Some(_) => {
            let updated_resources = self.pdf_impose_change_pattern_matrices_resources(
              matrix, resources, used, xobjects_done,
            )
            self.add_object_given_number(
              xobject_number,
              direct_xobject.add_dict_entry(
                pdf_page_resources_key(),
                updated_resources,
              ),
            )
          }
          None => ()
        }
      }
      _ => ()
    }
  }
}

///|
fn PdfDocument::pdf_impose_change_pattern_matrices_page(
  self : PdfDocument,
  matrix : TransformMatrix,
  page : PdfPage,
) -> PdfPage raise PdfError {
  let used = self.pdf_impose_patterns_used_with_scn(
    page.content,
    page.resources,
  )
  let xobjects_done : Array[Int] = []
  {
    ..page,
    resources: self.pdf_impose_change_pattern_matrices_resources(
      matrix,
      page.resources,
      used,
      xobjects_done,
    ),
  }
}

///|
/// Rewrite pattern matrices used by a page after applying a page transform.
pub fn PdfDocument::change_pattern_matrices_page(
  self : PdfDocument,
  matrix : TransformMatrix,
  page : PdfPage,
) -> PdfPage raise PdfError {
  self.pdf_impose_change_pattern_matrices_page(matrix, page)
}

///|
/// Compatibility wrapper matching cpdfpage's `change_pattern_matrices_page`.
pub fn pdf_change_pattern_matrices_page(
  document : PdfDocument,
  matrix : TransformMatrix,
  page : PdfPage,
) -> PdfPage raise PdfError {
  document.change_pattern_matrices_page(matrix, page)
}

///|
#warnings("-unused_value")
fn PdfDocument::pdf_impose_transform_content(
  self : PdfDocument,
  resources : PdfObject,
  matrix : TransformMatrix,
  content : ArrayView[PdfObject],
  fast : Bool,
) -> Array[PdfObject] raise PdfError {
  if fast {
    let output : Array[PdfObject] = [
      pdf_content_stream_of_ops([Op_q, Op_cm(matrix)]),
    ]
    pdf_impose_push_objects(output, content)
    output.push(pdf_content_stream_of_ops([Op_Q]))
    output
  } else {
    let old_ops = self.parse_content_ops_with_resources(resources, content)
    let protected_ops = pdf_impose_concat_ops(
      pdf_page_protect(old_ops),
      old_ops,
    )
    [
      pdf_content_stream_of_ops(
        pdf_impose_concat_ops(
          [Op_q, Op_cm(matrix)],
          pdf_impose_concat_ops(protected_ops, [Op_Q]),
        ),
      ),
    ]
  }
}

///|
fn PdfDocument::pdf_impose_combine_page_resources(
  self : PdfDocument,
  pages : ArrayView[PdfPage],
) -> PdfObject {
  let mut resources = pages[0].resources
  for index in 1.. PdfObject {
  let mut rest = pages[0].rest
  for index in 1.. PdfPage raise PdfError {
  if pages.length() == 0 {
    raise BadNumberArgument("impose: pages must not be empty")
  }
  let first_page = pages[0]
  let transforms = self.pdf_impose_transforms(
    fit,
    x,
    y,
    columns,
    rtl,
    btt,
    center,
    margin,
    first_page.mediabox,
    output_mediabox,
    fit_extra_hspace,
    fit_extra_vspace,
    pages.length(),
  )
  for index in 0.. Array[TransformMatrix] raise PdfError {
  pdf_impose_validate_transform_inputs(x, y, count)
  let page_box = self.parse_rectangle(mediabox)
  let width = page_box.max_x - page_box.min_x
  let height = page_box.max_y - page_box.min_y
  let final_full_cols = count % x
  let final_full_rows = count % y
  let output : Array[TransformMatrix] = []
  let mut remaining = count
  let mut cent_extra_x = 0.0
  let mut cent_extra_y = 0.0
  if columns {
    for col in 0.. 0 {
          output.push(
            self.pdf_impose_transform_for_slot(
              fit,
              x,
              rtl,
              btt,
              margin,
              output_mediabox,
              fit_extra_hspace,
              fit_extra_vspace,
              cent_extra_x,
              cent_extra_y,
              adjusted_row,
              ordered_col,
              width * ordered_col.to_double(),
              height * ordered_row.to_double(),
            ),
          )
        }
        remaining -= 1
      }
    }
  } else {
    for row_offset in 0.. 0 {
          output.push(
            self.pdf_impose_transform_for_slot(
              fit,
              x,
              rtl,
              btt,
              margin,
              output_mediabox,
              fit_extra_hspace,
              fit_extra_vspace,
              cent_extra_x,
              cent_extra_y,
              ordered_row,
              adjusted_col,
              width * ordered_col.to_double(),
              height * ordered_row.to_double(),
            ),
          )
        }
        remaining -= 1
      }
    }
  }
  output
}