///|
fn pdf_encode_png_encoded_length(data : BytesView, scanline_width : Int) -> Int {
data.length() / scanline_width * (scanline_width + 1)
}
///|
fn pdf_encode_png_sub_predictor(
colors : Int,
bits_per_component : Int,
columns : Int,
data : BytesView,
) -> @core.PdfBytes raise @core.PdfError {
let scanline_width = pdf_predictor_scanline_width(
colors, bits_per_component, columns,
)
let bytes_per_pixel = pdf_predictor_bytes_per_pixel(
colors, bits_per_component,
)
let output = Array::make(
pdf_encode_png_encoded_length(data, scanline_width),
b'\x00',
)
let mut position = 0
for row in 0..<(data.length() / scanline_width) {
position = pdf_encode_png_push_scanline(
output,
position,
1,
data,
row * scanline_width,
scanline_width,
bytes_per_pixel,
)
}
Bytes::from_array(output[:position])
}
///|
fn pdf_encode_png_up_predictor(
colors : Int,
bits_per_component : Int,
columns : Int,
data : BytesView,
) -> @core.PdfBytes raise @core.PdfError {
let scanline_width = pdf_predictor_scanline_width(
colors, bits_per_component, columns,
)
let bytes_per_pixel = pdf_predictor_bytes_per_pixel(
colors, bits_per_component,
)
let output = Array::make(
pdf_encode_png_encoded_length(data, scanline_width),
b'\x00',
)
let mut position = 0
for row in 0..<(data.length() / scanline_width) {
position = pdf_encode_png_push_scanline(
output,
position,
2,
data,
row * scanline_width,
scanline_width,
bytes_per_pixel,
)
}
Bytes::from_array(output[:position])
}
///|
fn pdf_encode_png_predictor_value(
predictor : Int,
data : BytesView,
row_start : Int,
index : Int,
scanline_width : Int,
bytes_per_pixel : Int,
) -> Int raise @core.PdfError {
let left = if index < bytes_per_pixel {
0
} else {
data[row_start + index - bytes_per_pixel].to_int()
}
let up = if row_start < scanline_width {
0
} else {
data[row_start - scanline_width + index].to_int()
}
let up_left = if row_start < scanline_width || index < bytes_per_pixel {
0
} else {
data[row_start - scanline_width + index - bytes_per_pixel].to_int()
}
match predictor {
0 => 0
1 => left
2 => up
3 => (left + up) / 2
4 => pdf_paeth_predictor(left, up, up_left)
_ => raise PredictorNotSupported(predictor)
}
}
///|
fn pdf_encode_png_push_scanline(
output : Array[Byte],
position : Int,
predictor : Int,
data : BytesView,
row_start : Int,
scanline_width : Int,
bytes_per_pixel : Int,
) -> Int raise @core.PdfError {
let mut current = position
output[current] = predictor.to_byte()
current += 1
for i in 0.. Int raise @core.PdfError {
let mut score = 0
for i in 0.. 127 { 256 - value } else { value }
}
score
}
///|
fn pdf_encode_png_tagged_predictor(
predictor : Int,
colors : Int,
bits_per_component : Int,
columns : Int,
data : BytesView,
) -> @core.PdfBytes raise @core.PdfError {
let scanline_width = pdf_predictor_scanline_width(
colors, bits_per_component, columns,
)
let bytes_per_pixel = pdf_predictor_bytes_per_pixel(
colors, bits_per_component,
)
let output = Array::make(
pdf_encode_png_encoded_length(data, scanline_width),
b'\x00',
)
let mut position = 0
for row in 0..<(data.length() / scanline_width) {
position = pdf_encode_png_push_scanline(
output,
position,
predictor,
data,
row * scanline_width,
scanline_width,
bytes_per_pixel,
)
}
Bytes::from_array(output[:position])
}
///|
fn pdf_encode_png_optimum_predictor(
colors : Int,
bits_per_component : Int,
columns : Int,
data : BytesView,
) -> @core.PdfBytes raise @core.PdfError {
let scanline_width = pdf_predictor_scanline_width(
colors, bits_per_component, columns,
)
let bytes_per_pixel = pdf_predictor_bytes_per_pixel(
colors, bits_per_component,
)
let output = Array::make(
pdf_encode_png_encoded_length(data, scanline_width),
b'\x00',
)
let mut position = 0
for row in 0..<(data.length() / scanline_width) {
let row_start = row * scanline_width
let mut best_predictor = 0
let mut best_score = pdf_encode_png_predictor_score(
0, data, row_start, scanline_width, bytes_per_pixel,
)
for predictor in 1..<=4 {
let score = pdf_encode_png_predictor_score(
predictor, data, row_start, scanline_width, bytes_per_pixel,
)
if score < best_score {
best_predictor = predictor
best_score = score
}
}
position = pdf_encode_png_push_scanline(
output, position, best_predictor, data, row_start, scanline_width, bytes_per_pixel,
)
}
Bytes::from_array(output[:position])
}