///|
fn pdf_remove_text_name(text : String) -> @core.PdfName {
@core.pdf_name_of_bytes(@ascii.encode(text))
}
///|
let pdf_remove_text_stamp_name : @core.PdfName = pdf_remove_text_name(
"/CPDFSTAMP",
)
///|
fn pdf_remove_text_stamp() -> @core.PdfName {
pdf_remove_text_stamp_name
}
///|
fn pdf_remove_text_is_stamp_bmc(op : @content.PdfContentOp) -> Bool {
match op {
Op_BMC(tag) => tag == pdf_remove_text_stamp()
_ => false
}
}
///|
fn pdf_remove_text_after_stamp(
ops : ArrayView[@content.PdfContentOp],
start : Int,
) -> Int {
let mut index = start
let mut level = 1
while index < ops.length() {
let op = ops[index]
if pdf_remove_text_is_stamp_bmc(op) {
level += 1
index += 1
} else {
match op {
Op_EMC => {
level -= 1
index += 1
if level == 0 {
break index
}
}
_ => index += 1
}
}
} nobreak {
ops.length()
}
}
///|
/// Remove content marked as `/CPDFSTAMP`, matching cpdf's add-text cleanup.
///
/// Nested `/CPDFSTAMP ... EMC` sections are skipped as a unit. If a stamp block
/// is unterminated, all following operators are dropped, matching the OCaml
/// recursive removal behavior.
pub fn pdf_remove_added_text_ops(
ops : ArrayView[@content.PdfContentOp],
) -> Array[@content.PdfContentOp] {
let output : Array[@content.PdfContentOp] = []
let mut index = 0
while index < ops.length() {
let op = ops[index]
if pdf_remove_text_is_stamp_bmc(op) {
index = pdf_remove_text_after_stamp(ops, index + 1)
} else {
output.push(op)
index += 1
}
}
output
}
///|
fn pdf_remove_text_is_text_showing_op(op : @content.PdfContentOp) -> Bool {
match op {
Op_Tj(_) | Op_TJ(_) | Op_quote(_) | Op_double_quote(_, _, _) => true
_ => false
}
}
///|
/// Remove text-showing operators while preserving text positioning/state ops.
pub fn pdf_remove_all_text_ops(
ops : ArrayView[@content.PdfContentOp],
) -> Array[@content.PdfContentOp] {
let output : Array[@content.PdfContentOp] = []
for op in ops {
if !pdf_remove_text_is_text_showing_op(op) {
output.push(op)
}
}
output
}
///|
fn PdfDocument::pdf_remove_text_page(
self : PdfDocument,
page : @page.PdfPage,
transform : (ArrayView[@content.PdfContentOp]) -> Array[@content.PdfContentOp],
) -> @page.PdfPage raise @core.PdfError {
let ops = self.pdf_page_parse_content_ops(page.resources, page.content)
{ ..page, content: [pdf_content_stream_of_ops(transform(ops))], }
}
///|
fn pdf_remove_text_all_text_xobject(
document : PdfDocument,
resources : @syntax.PdfObject,
streams : ArrayView[@syntax.PdfObject],
) -> Array[@syntax.PdfObject] raise @core.PdfError {
let ops = document.pdf_page_parse_content_ops(resources, streams)
[pdf_content_stream_of_ops(pdf_remove_all_text_ops(ops))]
}
///|
/// Remove text added by cpdf add-text stamping from selected one-based pages.
pub fn PdfDocument::remove_added_text(
self : PdfDocument,
page_numbers : ArrayView[Int],
) -> PdfDocument raise @core.PdfError {
let pages = self.pages_of_pagetree()
let selected_pages = @core.pdf_number_set(page_numbers)
let rewritten : Array[@page.PdfPage] = Array(capacity=pages.length())
for index in 0.. PdfDocument raise @core.PdfError {
document.remove_added_text(page_numbers)
}
///|
/// Compatibility wrapper matching cpdfremovetext's source-spelled `removetext`.
pub fn pdf_removetext(
page_numbers : ArrayView[Int],
document : PdfDocument,
) -> PdfDocument raise @core.PdfError {
document.remove_added_text(page_numbers)
}
///|
/// Remove all text-showing operators from selected one-based pages and their
/// referenced Form XObjects.
pub fn PdfDocument::remove_all_text(
self : PdfDocument,
page_numbers : ArrayView[Int],
) -> PdfDocument raise @core.PdfError {
let document = self.copy()
let pages = document.pages_of_pagetree()
let selected_pages = @core.pdf_number_set(page_numbers)
let rewritten : Array[@page.PdfPage] = Array(capacity=pages.length())
for index in 0.. PdfDocument raise @core.PdfError {
document.remove_all_text(page_numbers)
}
///|
/// Compatibility wrapper matching cpdfremovetext's page-list-first order.
pub fn pdf_remove_all_text_cpdf_order(
page_numbers : ArrayView[Int],
document : PdfDocument,
) -> PdfDocument raise @core.PdfError {
document.remove_all_text(page_numbers)
}