///|
/// Return a float from a PDF number.
pub fn Pdf::getnum(self : Pdf, obj : PdfObject) -> Double raise {
match obj {
Real(a) => a
Integer(a) => Double::from_int(a)
Indirect(i) => self.getnum(self.lookup_obj(i))
_ => raise PdfError::Msg("getnum: not a number")
}
}
///|
/// Parse a PDF rectangle structure into min x, min y, max x, max y.
pub fn Pdf::parse_rectangle(
self : Pdf,
obj : PdfObject,
) -> (Double, Double, Double, Double) raise {
match obj {
Array(vals) =>
if vals.length() == 4 {
let x = self.getnum(vals[0])
let y = self.getnum(vals[1])
let x2 = self.getnum(vals[2])
let y2 = self.getnum(vals[3])
let min_x = if x < x2 { x } else { x2 }
let min_y = if y < y2 { y } else { y2 }
let max_x = if x > x2 { x } else { x2 }
let max_y = if y > y2 { y } else { y2 }
(min_x, min_y, max_x, max_y)
} else {
raise PdfError::Msg("parse_rectangle: expected 4 elements")
}
_ => raise PdfError::Msg("parse_rectangle: not an array")
}
}
///|
/// Parse a transform matrix, or return the identity if missing.
pub fn Pdf::parse_matrix(
self : Pdf,
key : String,
dict : PdfObject,
) -> @pdftransform.TransformMatrix raise {
match self.lookup_direct(key, dict) {
None | Some(Null) => @pdftransform.TransformMatrix::identity()
Some(Array(vals)) =>
if vals.length() != 6 {
raise PdfError::Msg("Malformed matrix")
} else {
let a = self.getnum(vals[0])
let b = self.getnum(vals[1])
let c = self.getnum(vals[2])
let d = self.getnum(vals[3])
let e = self.getnum(vals[4])
let f = self.getnum(vals[5])
{ a, b, c, d, e, f }
}
_ => raise PdfError::Msg("Malformed matrix")
}
}
///|
/// Build a matrix object.
pub fn make_matrix(tr : @pdftransform.TransformMatrix) -> PdfObject {
Array([Real(tr.a), Real(tr.b), Real(tr.c), Real(tr.d), Real(tr.e), Real(tr.f)])
}
///|
fn fmin(a : Double, b : Double) -> Double {
if a < b {
a
} else {
b
}
}
///|
fn fmax(a : Double, b : Double) -> Double {
if a > b {
a
} else {
b
}
}
///|
/// Transform a rectangle by a matrix, returning the bounding rectangle.
pub fn Pdf::transform_rect(
self : Pdf,
transform : @pdftransform.TransformMatrix,
rect : PdfObject,
) -> PdfObject raise {
let (minx, miny, maxx, maxy) = self.parse_rectangle(rect)
let (x0, y0) = transform.apply((minx, miny))
let (x1, y1) = transform.apply((maxx, maxy))
let (x2, y2) = transform.apply((minx, maxy))
let (x3, y3) = transform.apply((maxx, miny))
let minx = fmin(fmin(x0, x1), fmin(x2, x3))
let miny = fmin(fmin(y0, y1), fmin(y2, y3))
let maxx = fmax(fmax(x0, x1), fmax(x2, x3))
let maxy = fmax(fmax(y0, y1), fmax(y2, y3))
Array([Real(minx), Real(miny), Real(maxx), Real(maxy)])
}
///|
fn Pdf::transform_quadpoint_single(
self : Pdf,
transform : @pdftransform.TransformMatrix,
qp : Array[PdfObject],
) -> Array[PdfObject] raise {
if qp.length() != 8 {
@pdfe.log("Malformed /QuadPoints format: must be a multiple of 8 entries\n")
return qp
}
let x1 = self.getnum(qp[0])
let y1 = self.getnum(qp[1])
let x2 = self.getnum(qp[2])
let y2 = self.getnum(qp[3])
let x3 = self.getnum(qp[4])
let y3 = self.getnum(qp[5])
let x4 = self.getnum(qp[6])
let y4 = self.getnum(qp[7])
let (x1, y1) = transform.apply((x1, y1))
let (x2, y2) = transform.apply((x2, y2))
let (x3, y3) = transform.apply((x3, y3))
let (x4, y4) = transform.apply((x4, y4))
[
Real(x1),
Real(y1),
Real(x2),
Real(y2),
Real(x3),
Real(y3),
Real(x4),
Real(y4),
]
}
///|
fn[T] split_into(values : Array[T], size : Int) -> Array[Array[T]] {
let out = Array::new(capacity=(values.length() + size - 1) / size)
for i = 0; i < values.length(); i = i + size {
let part = Array::new(capacity=size)
for j in 0.. PdfObject raise {
match qp {
Array(qps) => {
let out = Array::new(capacity=qps.length())
for chunk in split_into(qps, 8) {
out.append(self.transform_quadpoint_single(transform, chunk))
}
Array(out)
}
_ => {
@pdfe.log("Unknown or malformed /QuadPoints format\n")
qp
}
}
}