pdf/object/
function.rs

1use crate as pdf;
2use crate::object::*;
3use crate::error::*;
4use itertools::izip;
5use datasize::DataSize;
6
7#[derive(Object, Debug, Clone, ObjectWrite)]
8struct RawFunction {
9    #[pdf(key="FunctionType")]
10    function_type: u32,
11
12    #[pdf(key="Domain")]
13    domain: Vec<f32>,
14
15    #[pdf(key="Range")]
16    range: Option<Vec<f32>>,
17
18    #[pdf(key="Size")]
19    size: Option<Vec<u32>>,
20
21    #[pdf(key="BitsPerSample")]
22    _bits_per_sample: Option<u32>,
23
24    #[pdf(key="Order", default="1")]
25    order: u32,
26
27    #[pdf(key="Encode")]
28    encode: Option<Vec<f32>>,
29
30    #[pdf(key="Decode")]
31    decode: Option<Vec<f32>>,
32
33    #[pdf(other)]
34    other: Dictionary
35}
36
37#[derive(Object, Debug, Clone)]
38struct Function2 {
39    #[pdf(key="C0")]
40    c0: Option<Vec<f32>>,
41
42    #[pdf(key="C1")]
43    c1: Option<Vec<f32>>,
44
45    #[pdf(key="N")]
46    exponent: f32,
47}
48
49#[derive(Debug, Clone, DataSize)]
50pub enum Function {
51    Sampled(SampledFunction),
52    Interpolated(Vec<InterpolatedFunctionDim>),
53    Stiching,
54    Calculator,
55    PostScript { func: PsFunc, domain: Vec<f32>, range: Vec<f32> },
56}
57impl Function {
58    pub fn apply(&self, x: &[f32], out: &mut [f32]) -> Result<()> {
59        match *self {
60            Function::Sampled(ref func) => {
61                func.apply(x, out)
62            }
63            Function::Interpolated(ref parts) => {
64                if parts.len() != out.len() {
65                    bail!("incorrect output length: expected {}, found {}.", parts.len(), out.len())
66                }
67                for (f, y) in parts.iter().zip(out) {
68                    *y = f.apply(x[0]);
69                }
70                Ok(())
71            }
72            Function::PostScript { ref func, .. } => func.exec(x, out),
73            _ => bail!("unimplemted function {:?}", self)
74        }
75    }
76    pub fn input_dim(&self) -> usize {
77        match *self {
78            Function::PostScript { ref domain, .. } => domain.len() / 2,
79            Function::Sampled(ref f) => f.input.len(),
80            _ => panic!()
81        }
82    }
83    pub fn output_dim(&self) -> usize {
84        match *self {
85            Function::PostScript { ref range, .. } => range.len() / 2,
86            Function::Sampled(ref f) => f.output.len(),
87            _ => panic!()
88        }
89    }
90}
91impl FromDict for Function {
92    fn from_dict(dict: Dictionary, resolve: &impl Resolve) -> Result<Self> {
93        use std::f32::INFINITY;
94        let raw = RawFunction::from_dict(dict, resolve)?;
95        match raw.function_type {
96            2 => {
97                let f2 = Function2::from_dict(raw.other, resolve)?;
98                
99                let n_dim = match (raw.range.as_ref(), f2.c0.as_ref(), f2.c1.as_ref()) {
100                    (Some(range), _, _) => range.len() / 2,
101                    (_, Some(c0), _) => c0.len(),
102                    (_, _, Some(c1)) => c1.len(),
103                    _ => bail!("unknown dimensions")
104                };
105                let mut parts = Vec::with_capacity(n_dim);
106                let input_range = (raw.domain[0], raw.domain[1]);
107                for dim in 0 .. n_dim {
108                    let output_range = (
109                        raw.range.as_ref().and_then(|r| r.get(2*dim).cloned()).unwrap_or(-INFINITY),
110                        raw.range.as_ref().and_then(|r| r.get(2*dim+1).cloned()).unwrap_or(INFINITY)
111                    );
112                    let c0 = f2.c0.as_ref().and_then(|c0| c0.get(dim).cloned()).unwrap_or(0.0);
113                    let c1 = f2.c1.as_ref().and_then(|c1| c1.get(dim).cloned()).unwrap_or(1.0);
114                    let exponent = f2.exponent;
115                    parts.push(InterpolatedFunctionDim {
116                        input_range, output_range, c0, c1, exponent
117                    });
118                }
119                Ok(Function::Interpolated(parts))
120            },
121            i => {
122                dbg!(raw);
123                bail!("unsupported function type {}", i)
124            }
125        }
126    }
127}
128impl Object for Function {
129    fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
130        match p {
131            Primitive::Dictionary(dict) => Self::from_dict(dict, resolve),
132            Primitive::Stream(s) => {
133                let stream = Stream::<RawFunction>::from_stream(s, resolve)?;
134                let data = stream.data(resolve)?;
135                match stream.info.function_type {
136                    4 => {
137                        let s = std::str::from_utf8(&data)?;
138                        let func = PsFunc::parse(s)?;
139                        let info = stream.info.info;
140                        Ok(Function::PostScript { func, domain: info.domain, range: info.range.unwrap() })
141                    },
142                    0 => {
143                        let info = stream.info.info;
144                        let order = match info.order {
145                            1 => Interpolation::Linear,
146                            3 => Interpolation::Cubic,
147                            n => bail!("Invalid interpolation order {}", n),
148                        };
149
150                        let size = try_opt!(info.size);
151                        let range = try_opt!(info.range);
152                        let encode = info.encode.unwrap_or_else(|| size.iter().flat_map(|&n| [0.0, (n-1) as f32]).collect());
153                        let decode = info.decode.unwrap_or_else(|| range.clone());
154
155                        Ok(Function::Sampled(SampledFunction {
156                            input: izip!(info.domain.chunks_exact(2), encode.chunks_exact(2), size.iter()).map(|(c, e, &s)| {
157                                SampledFunctionInput {
158                                    domain: (c[0], c[1]),
159                                    encode_offset: e[0],
160                                    encode_scale: e[1],
161                                    size: s as usize,
162                                }
163                            }).collect(),
164                            output: decode.chunks_exact(2).map(|c| SampledFunctionOutput { 
165                                offset: c[0],
166                                scale: (c[1] - c[0]) / 255.,
167                            }).collect(),
168                            data,
169                            order,
170                            range,
171                        }))
172                    }
173                    ref p => bail!("found a function stream with type {:?}", p)
174                }
175            },
176            Primitive::Reference(r) => Self::from_primitive(resolve.resolve(r)?, resolve),
177            _ => bail!("double indirection")
178        }
179    }
180}
181impl ObjectWrite for Function {
182    fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
183        unimplemented!()
184        /*
185        let dict = match self {
186            Function::Interpolated(parts) => {
187                let first: &InterpolatedFunctionDim = try_opt!(parts.get(0));
188                let f2 = Function2 {
189                    c0: parts.iter().map(|p| p.c0).collect(),
190                    c1: parts.iter().map(|p| p.c0).collect(),
191                    exponent: first.exponent
192                };
193                let f = RawFunction {
194                    function_type: 2,
195                    domain: vec![first.input_range.0, first.input_range.1],
196                    range: parts.iter().flat_map(|p| [p.output_range.0, p.output_range.1]).collect(),
197                    decode: None,
198                    encode: None,
199                    order
200                };
201
202            }
203        }
204        */
205    }
206}
207impl DeepClone for Function {
208    fn deep_clone(&self, cloner: &mut impl Cloner) -> Result<Self> {
209        Ok(self.clone())
210    }
211}
212
213#[derive(Debug, Clone, DataSize)]
214struct SampledFunctionInput {
215    domain: (f32, f32),
216    encode_offset: f32,
217    encode_scale: f32,
218    size: usize,
219}
220impl SampledFunctionInput {
221    fn map(&self, x: f32) -> (usize, usize, f32) {
222        let x = x.clamp(self.domain.0, self.domain.1);
223        let y = x.mul_add(self.encode_scale, self.encode_offset);
224        (y.floor() as usize, self.size, y.fract())
225    }
226}
227
228#[derive(Debug, Clone, DataSize)]
229struct SampledFunctionOutput {
230    offset: f32,
231    scale: f32
232}
233impl SampledFunctionOutput {
234    fn map(&self, x: f32) -> f32 {
235        x.mul_add(self.scale, self.offset)
236    }
237}
238
239#[derive(Debug, Clone, DataSize)]
240enum Interpolation {
241    Linear,
242    #[allow(dead_code)]  // TODO
243    Cubic,
244}
245
246#[derive(Debug, Clone, DataSize)]
247pub struct SampledFunction {
248    input: Vec<SampledFunctionInput>,
249    output: Vec<SampledFunctionOutput>,
250    data: Arc<[u8]>,
251    order: Interpolation,
252    range: Vec<f32>,
253}
254impl SampledFunction {
255    fn apply(&self, x: &[f32], out: &mut [f32]) -> Result<()> {
256        if x.len() != self.input.len() {
257            bail!("input dimension mismatch {} != {}", x.len(), self.input.len());
258        }
259        let n_out = out.len();
260        if out.len() * 2 != self.range.len() {
261            bail!("output dimension mismatch 2 * {} != {}", out.len(), self.range.len())
262        }
263        match x.len() {
264            1 => {
265                match self.order {
266                    Interpolation::Linear => {
267                        let (i, _, s) = self.input[0].map(x[0]);
268                        let idx = i * n_out;
269
270                        for (o, &a) in out.iter_mut().zip(&self.data[idx..]) {
271                            *o = a as f32 * (1. - s);
272                        }
273                        for (o, &b) in out.iter_mut().zip(&self.data[idx + n_out..]) {
274                            *o += b as f32 * s;
275                        }
276                    }
277                    _ => unimplemented!()
278                }
279            }
280            2 => match self.order {
281                Interpolation::Linear => {
282                    let (i0, s0, f0) = self.input[0].map(x[0]);
283                    let (i1,  _, f1) = self.input[1].map(x[1]);
284                    let (j0, j1) = (i0+1, i1+1);
285                    let (g0, g1) = (1. - f0, 1. - f1);
286                    
287                    out.fill(0.0);
288                    let mut add = |i0, i1, f| {
289                        let idx = (i0 + s0 * i1) * n_out;
290                        
291                        if let Some(part) = self.data.get(idx .. idx+n_out) {
292                            for (o, &b) in out.iter_mut().zip(part) {
293                                *o += f * b as f32;
294                            }
295                        }
296                    };
297
298                    add(i0, i1, g0 * g1);
299                    add(j0, i1, f0 * g1);
300                    add(i0, j1, g0 * f1);
301                    add(j0, j1, f0 * f1);
302                }
303                _ => unimplemented!()
304            }
305            3 => match self.order {
306                Interpolation::Linear => {
307                    let (i0, s0, f0) = self.input[0].map(x[0]);
308                    let (i1, s1, f1) = self.input[1].map(x[1]);
309                    let (i2,  _, f2) = self.input[2].map(x[2]);
310                    let (j0, j1, j2) = (i0+1, i1+1, i2+1);
311                    let (g0, g1, g2) = (1. - f0, 1. - f1, 1. - f2);
312                    
313                    out.fill(0.0);
314                    let mut add = |i0, i1, i2, f| {
315                        let idx = (i0 + s0 * (i1 + s1 * i2)) * n_out;
316                        
317                        if let Some(part) = self.data.get(idx .. idx+n_out) {
318                            for (o, &b) in out.iter_mut().zip(part) {
319                                *o += f * b as f32;
320                            }
321                        }
322                    };
323
324                    add(i0, i1, i2, g0 * g1 * g2);
325                    add(j0, i1, i2, f0 * g1 * g2);
326                    add(i0, j1, i2, g0 * f1 * g2);
327                    add(j0, j1, i2, f0 * f1 * g2);
328
329                    add(i0, i1, j2, g0 * g1 * f2);
330                    add(j0, i1, j2, f0 * g1 * f2);
331                    add(i0, j1, j2, g0 * f1 * f2);
332                    add(j0, j1, j2, f0 * f1 * f2);
333                }
334                _ => unimplemented!()
335            }
336            n => bail!("Order {}", n)
337        }
338        for (o, y) in self.output.iter().zip(out.iter_mut()) {
339            *y = o.map(*y);
340        }
341        Ok(())
342    }
343}
344
345
346#[derive(Debug, Clone, DataSize)]
347pub struct InterpolatedFunctionDim {
348    pub input_range: (f32, f32),
349    pub output_range: (f32, f32),
350    pub c0: f32,
351    pub c1: f32,
352    pub exponent: f32,
353}
354impl InterpolatedFunctionDim {
355    pub fn apply(&self, x: f32) -> f32 {
356        let y = self.c0 + x.powf(self.exponent) * (self.c1 - self.c0);
357        let (y0, y1) = self.output_range;
358        y.min(y1).max(y0)
359    }
360}
361
362#[derive(Debug)]
363pub enum PostScriptError {
364    StackUnderflow,
365    IncorrectStackSize
366}
367#[derive(Debug, Clone, DataSize)]
368pub struct PsFunc {
369    pub ops: Vec<PsOp>
370}
371
372macro_rules! op {
373    ($stack:ident; $($v:ident),* => $($e:expr),*) => ( {
374        $(let $v = $stack.pop().ok_or(PostScriptError::StackUnderflow)?;)*
375        $($stack.push($e);)*
376    } )
377}
378
379impl PsFunc {
380    fn exec_inner(&self, stack: &mut Vec<f32>) -> Result<(), PostScriptError> {
381        for &op in &self.ops {
382            match op {
383                PsOp::Int(i) => stack.push(i as f32),
384                PsOp::Value(v) => stack.push(v),
385                PsOp::Dup => op!(stack; v => v, v),
386                PsOp::Exch => op!(stack; b, a => b, a),
387                PsOp::Add => op!(stack; b, a => a + b),
388                PsOp::Sub => op!(stack; b, a => a - b),
389                PsOp::Mul => op!(stack; b, a => a * b),
390                PsOp::Abs => op!(stack; a => a.abs()),
391                PsOp::Roll => {
392                    let j = stack.pop().ok_or(PostScriptError::StackUnderflow)? as isize;
393                    let n = stack.pop().ok_or(PostScriptError::StackUnderflow)? as usize;
394                    let start = stack.len() - n;
395                    let slice = &mut stack[start..];
396                    if j > 0 {
397                        slice.rotate_right(j as usize);
398                    } else {
399                        slice.rotate_left(-j as usize);
400                    }
401                }
402                PsOp::Index => {
403                    let n = stack.pop().ok_or(PostScriptError::StackUnderflow)? as usize;
404                    if n >= stack.len() { return Err(PostScriptError::StackUnderflow); }
405                    let val = stack[stack.len() - n - 1];
406                    stack.push(val);
407                }
408                PsOp::Cvr => {}
409                PsOp::Pop => {
410                    stack.pop().ok_or(PostScriptError::StackUnderflow)?;
411                }
412            }
413        }
414        Ok(())
415    }
416    pub fn exec(&self, input: &[f32], output: &mut [f32]) -> Result<()> {
417        let mut stack = Vec::with_capacity(10);
418        stack.extend_from_slice(input);
419        match self.exec_inner(&mut stack) {
420            Ok(()) => {},
421            Err(_) => return Err(PdfError::PostScriptExec)
422        }
423        if output.len() != stack.len() {
424            bail!("incorrect output length: expected {}, found {}.", stack.len(), output.len())
425        }
426        output.copy_from_slice(&stack);
427        Ok(())
428    }
429    pub fn parse(s: &str) -> Result<Self, PdfError> {
430        let start = s.find('{').ok_or(PdfError::PostScriptParse)?;
431        let end = s.rfind('}').ok_or(PdfError::PostScriptParse)?;
432
433        let ops: Result<Vec<_>, _> = s[start + 1 .. end].split_ascii_whitespace().map(PsOp::parse).collect();
434        Ok(PsFunc { ops: ops? })
435    }
436}
437
438#[derive(Copy, Clone, Debug, DataSize)]
439pub enum PsOp {
440    Int(i32),
441    Value(f32),
442    Add,
443    Sub,
444    Abs,
445    Mul,
446    Dup,
447    Exch,
448    Roll,
449    Index,
450    Cvr,
451    Pop,
452}
453impl PsOp {
454    pub fn parse(s: &str) -> Result<Self> {
455        if let Ok(i) = s.parse::<i32>() {
456            Ok(PsOp::Int(i))
457        } else if let Ok(f) = s.parse::<f32>() {
458            Ok(PsOp::Value(f))
459        } else {
460            Ok(match s {
461                "add" => PsOp::Add,
462                "sub" => PsOp::Sub,
463                "abs" => PsOp::Abs,
464                "mul" => PsOp::Mul,
465                "dup" => PsOp::Dup,
466                "exch" => PsOp::Exch,
467                "roll" => PsOp::Roll,
468                "index" => PsOp::Index,
469                "cvr" => PsOp::Cvr,
470                "pop" => PsOp::Pop,
471                _ => {
472                    bail!("unimplemented op {}", s);
473                }
474            })
475        }
476    }
477}