///|
fn pdf_squeeze_stream_dictionary(
dictionary : @syntax.PdfObject,
length : Int,
) -> @syntax.PdfObject raise @core.PdfError {
dictionary
.remove_dict_entry(pdf_filter_key())
.remove_dict_entry(pdf_short_filter_key())
.remove_dict_entry(pdf_decodeparms_key())
.remove_dict_entry(pdf_short_decodeparms_key())
.add_dict_entry(pdf_page_length_key_name, PdfInteger(length))
}
///|
fn PdfDocument::pdf_squeeze_content_stream_numbers(
self : PdfDocument,
page_number : Int,
) -> Array[Int] {
let page = self.lookup_object_or_null(page_number)
let contents = self.pdf_page_content_list(self.pdf_page_content_object(page))
let numbers : Array[Int] = Array(capacity=contents.length())
for content in contents {
match content {
PdfIndirect(number) => numbers.push(number)
_ => ()
}
}
numbers
}
///|
fn PdfDocument::pdf_squeeze_all_page_content_numbers(
self : PdfDocument,
page_numbers : ArrayView[Int],
) -> Array[Int] {
let numbers : Array[Int] = Array(capacity=page_numbers.length())
for page_number in page_numbers {
for number in self.pdf_squeeze_content_stream_numbers(page_number) {
numbers.push(number)
}
}
numbers
}
///|
fn pdf_squeeze_occurrences(values : ArrayView[Int], needle : Int) -> Int {
let mut count = 0
for value in values {
if value == needle {
count += 1
}
}
count
}
///|
fn pdf_squeeze_content_streams_are_unshared(
all_content_numbers : ArrayView[Int],
contents : ArrayView[@syntax.PdfObject],
) -> Bool {
for content in contents {
match content {
PdfIndirect(number) =>
if pdf_squeeze_occurrences(all_content_numbers, number) > 1 {
break false
}
_ => ()
}
} nobreak {
true
}
}
///|
fn PdfDocument::pdf_squeeze_replace_page_contents(
self : PdfDocument,
page_number : Int,
page_object : @syntax.PdfObject,
resources : @syntax.PdfObject,
contents : ArrayView[@syntax.PdfObject],
) -> Unit raise @core.PdfError {
if contents.length() > 0 {
let ops = self.parse_content_ops_with_resources(resources, contents)
let stream_number = self.add_object(pdf_content_stream_of_ops(ops))
self.add_object_given_number(
page_number,
page_object.add_dict_entry(
pdf_page_contents_key(),
PdfIndirect(stream_number),
),
)
}
}
///|
fn PdfDocument::pdf_squeeze_form_xobject(
self : PdfDocument,
object_number : Int,
done : @hashmap.HashMap[Int, Bool],
) -> Unit raise @core.PdfError {
if !done.contains(object_number) {
done[object_number] = true
let object = self.lookup_object_or_null(object_number)
let resources = match self.lookup_direct(pdf_page_resources_key(), object) {
Some(resources) => resources
None => PdfDictionary([])
}
self.pdf_squeeze_form_xobjects_in_resources(resources, done)
match self.lookup_direct(pdf_page_subtype_key(), object) {
Some(PdfNameObject(name)) if name == pdf_page_type_form() =>
match object {
PdfStreamObject(original_stream) => {
let ops = self.parse_content_ops_with_resources(resources, [object])
let rewritten = pdf_content_stream_of_ops(ops)
let data = rewritten.stream_bytes()
self.add_object_given_number(
object_number,
PdfStreamObject({
dictionary: pdf_squeeze_stream_dictionary(
original_stream.dictionary,
data.length(),
),
data: StreamGot(data),
}),
)
}
_ => raise ParseStreamExpected
}
_ => ()
}
}
}
///|
fn PdfDocument::pdf_squeeze_form_xobjects_in_resources(
self : PdfDocument,
resources : @syntax.PdfObject,
done : @hashmap.HashMap[Int, Bool],
) -> Unit raise @core.PdfError {
match self.lookup_direct(pdf_page_xobject_key(), resources) {
Some(PdfDictionary(entries)) =>
for entry in entries {
let (_, value) = entry
match value {
PdfIndirect(number) => self.pdf_squeeze_form_xobject(number, done)
_ => raise DictionaryExpected
}
}
_ => ()
}
}
///|
fn PdfDocument::pdf_squeeze_page_data(
self : PdfDocument,
) -> Unit raise @core.PdfError {
let page_reference_numbers = self.page_reference_numbers()
let all_content_numbers = self.pdf_squeeze_all_page_content_numbers(
page_reference_numbers,
)
let page_numbers = self.select_object_numbers(fn(object) {
match self.lookup_direct(pdf_page_type_key(), object) {
Some(PdfNameObject(name)) => name == pdf_page_type_page()
_ => false
}
})
let xobjects_done : @hashmap.HashMap[Int, Bool] = HashMap([])
for page_number in page_numbers {
let page = self.lookup_object_or_null(page_number)
let resources = match self.lookup_direct(pdf_page_resources_key(), page) {
Some(resources) => resources
None => PdfDictionary([])
}
let contents = self.pdf_page_content_list(
self.pdf_page_content_object(page),
)
if pdf_squeeze_content_streams_are_unshared(all_content_numbers, contents) {
self.pdf_squeeze_replace_page_contents(
page_number, page, resources, contents,
)
}
self.pdf_squeeze_form_xobjects_in_resources(resources, xobjects_done)
}
}