use super::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
enum FunctionType {
Sampled,
Exponential,
Stitching,
PostScript,
}
impl FunctionType {
pub(crate) fn to_int(self) -> i32 {
match self {
Self::Sampled => 0,
Self::Exponential => 2,
Self::Stitching => 3,
Self::PostScript => 4,
}
}
}
macro_rules! common_func_methods {
() => {
pub fn domain(&mut self, domain: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"Domain")).array().items(domain);
self
}
pub fn range(&mut self, range: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"Range")).array().items(range);
self
}
};
}
pub struct SampledFunction<'a> {
stream: Stream<'a>,
}
impl<'a> SampledFunction<'a> {
pub(crate) fn start(mut stream: Stream<'a>) -> Self {
stream.pair(Name(b"FunctionType"), FunctionType::Sampled.to_int());
Self { stream }
}
common_func_methods!();
pub fn size(&mut self, size: impl IntoIterator<Item = i32>) -> &mut Self {
self.insert(Name(b"Size")).array().items(size);
self
}
pub fn bits_per_sample(&mut self, bits: i32) -> &mut Self {
self.pair(Name(b"BitsPerSample"), bits);
self
}
pub fn order(&mut self, order: InterpolationOrder) -> &mut Self {
self.pair(Name(b"Order"), order.to_int());
self
}
pub fn encode(&mut self, encode: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"Encode")).array().items(encode);
self
}
pub fn decode(&mut self, decode: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"Decode")).array().items(decode);
self
}
}
deref!('a, SampledFunction<'a> => Stream<'a>, stream);
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
pub enum InterpolationOrder {
#[default]
Linear,
Cubic,
}
impl InterpolationOrder {
pub(crate) fn to_int(self) -> i32 {
match self {
Self::Linear => 1,
Self::Cubic => 3,
}
}
}
pub struct ExponentialFunction<'a> {
dict: Dict<'a>,
}
writer!(ExponentialFunction: |obj| {
let mut dict = obj.dict();
dict.pair(Name(b"FunctionType"), FunctionType::Exponential.to_int());
Self { dict }
});
impl ExponentialFunction<'_> {
common_func_methods!();
pub fn c0(&mut self, c0: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"C0")).array().items(c0);
self
}
pub fn c1(&mut self, c1: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"C1")).array().items(c1);
self
}
pub fn n(&mut self, n: f32) -> &mut Self {
self.pair(Name(b"N"), n);
self
}
}
deref!('a, ExponentialFunction<'a> => Dict<'a>, dict);
pub struct StitchingFunction<'a> {
dict: Dict<'a>,
}
writer!(StitchingFunction: |obj| {
let mut dict = obj.dict();
dict.pair(Name(b"FunctionType"), FunctionType::Stitching.to_int());
Self { dict }
});
impl StitchingFunction<'_> {
common_func_methods!();
pub fn functions(&mut self, functions: impl IntoIterator<Item = Ref>) -> &mut Self {
self.insert(Name(b"Functions")).array().items(functions);
self
}
pub fn bounds(&mut self, bounds: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"Bounds")).array().items(bounds);
self
}
pub fn encode(&mut self, encode: impl IntoIterator<Item = f32>) -> &mut Self {
self.insert(Name(b"Encode")).array().items(encode);
self
}
}
deref!('a, StitchingFunction<'a> => Dict<'a>, dict);
pub struct PostScriptFunction<'a> {
stream: Stream<'a>,
}
impl<'a> PostScriptFunction<'a> {
pub(crate) fn start(mut stream: Stream<'a>) -> Self {
stream.pair(Name(b"FunctionType"), FunctionType::PostScript.to_int());
Self { stream }
}
common_func_methods!();
}
deref!('a, PostScriptFunction<'a> => Stream<'a>, stream);
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PostScriptOp<'a> {
Real(f32),
Integer(i32),
Abs,
Add,
Atan,
Ceiling,
Cos,
Cvi,
Cvr,
Div,
Exp,
Floor,
Idiv,
Ln,
Log,
Mod,
Mul,
Neg,
Round,
Sin,
Sqrt,
Sub,
Truncate,
And,
Bitshift,
Eq,
False,
Ge,
Gt,
Le,
Lt,
Ne,
Not,
Or,
True,
Xor,
If(&'a [Self]),
IfElse(&'a [Self], &'a [Self]),
Copy,
Dup,
Exch,
Index,
Pop,
Roll,
}
impl PostScriptOp<'_> {
pub fn encode(ops: &[Self]) -> Buf {
let mut buf = Buf::new();
Self::write_slice(ops, &mut buf);
buf
}
fn write_slice(ops: &[Self], buf: &mut Buf) {
buf.push(b'{');
if ops.len() > 1 {
buf.push(b' ');
}
for op in ops {
op.write(buf);
buf.push(b' ');
}
if ops.len() == 1 {
buf.inner.pop();
}
buf.push(b'}');
}
fn write(&self, buf: &mut Buf) {
match *self {
Self::Real(r) => buf.push_decimal(r),
Self::Integer(i) => buf.push_val(i),
Self::If(ops) => {
Self::write_slice(ops, buf);
buf.push(b' ');
buf.extend(self.operator());
}
Self::IfElse(ops1, ops2) => {
Self::write_slice(ops1, buf);
buf.push(b' ');
Self::write_slice(ops2, buf);
buf.push(b' ');
buf.extend(self.operator());
}
_ => buf.extend(self.operator()),
}
}
fn operator(&self) -> &'static [u8] {
match self {
Self::Real(_) | Self::Integer(_) => b"",
Self::Abs => b"abs",
Self::Add => b"add",
Self::Atan => b"atan",
Self::Ceiling => b"ceiling",
Self::Cos => b"cos",
Self::Cvi => b"cvi",
Self::Cvr => b"cvr",
Self::Div => b"div",
Self::Exp => b"exp",
Self::Floor => b"floor",
Self::Idiv => b"idiv",
Self::Ln => b"ln",
Self::Log => b"log",
Self::Mod => b"mod",
Self::Mul => b"mul",
Self::Neg => b"neg",
Self::Round => b"round",
Self::Sin => b"sin",
Self::Sqrt => b"sqrt",
Self::Sub => b"sub",
Self::Truncate => b"truncate",
Self::And => b"and",
Self::Bitshift => b"bitshift",
Self::Eq => b"eq",
Self::False => b"false",
Self::Ge => b"ge",
Self::Gt => b"gt",
Self::Le => b"le",
Self::Lt => b"lt",
Self::Ne => b"ne",
Self::Not => b"not",
Self::Or => b"or",
Self::True => b"true",
Self::Xor => b"xor",
Self::If(_) => b"if",
Self::IfElse(_, _) => b"ifelse",
Self::Copy => b"copy",
Self::Dup => b"dup",
Self::Exch => b"exch",
Self::Index => b"index",
Self::Pop => b"pop",
Self::Roll => b"roll",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_post_script_encoding() {
use PostScriptOp::*;
let ops = [
Real(3.0),
Real(2.0),
Mul,
Exch,
Dup,
Real(0.0),
Ge,
IfElse(&[Real(1.0), Add], &[Neg]),
Add,
];
assert_eq!(
PostScriptOp::encode(&ops).as_slice(),
b"{ 3.0 2.0 mul exch dup 0.0 ge { 1.0 add } {neg} ifelse add }"
);
}
}