pdf_writer/
functions.rs

1use super::*;
2
3/// Way the function is defined in.
4#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
5enum FunctionType {
6    /// A function that is derived from a set of sampled data.
7    Sampled,
8    /// A exponential function.
9    Exponential,
10    /// A composite function made up of multiple other functions.
11    Stitching,
12    /// A postscript function.
13    PostScript,
14}
15
16impl FunctionType {
17    pub(crate) fn to_int(self) -> i32 {
18        match self {
19            Self::Sampled => 0,
20            Self::Exponential => 2,
21            Self::Stitching => 3,
22            Self::PostScript => 4,
23        }
24    }
25}
26
27macro_rules! common_func_methods {
28    () => {
29        /// Write the `/Domain` attribute to set where the function is defined.
30        /// Required.
31        pub fn domain(&mut self, domain: impl IntoIterator<Item = f32>) -> &mut Self {
32            self.insert(Name(b"Domain")).array().items(domain);
33            self
34        }
35
36        /// Write the `/Range` attribute.
37        ///
38        /// Required for sampled and PostScript functions.
39        pub fn range(&mut self, range: impl IntoIterator<Item = f32>) -> &mut Self {
40            self.insert(Name(b"Range")).array().items(range);
41            self
42        }
43    };
44}
45
46/// Writer for a _sampled function stream_. PDF 1.2+.
47///
48/// This struct is created by [`Chunk::sampled_function`].
49pub struct SampledFunction<'a> {
50    stream: Stream<'a>,
51}
52
53impl<'a> SampledFunction<'a> {
54    /// Create a new sampled function writer.
55    pub(crate) fn start(mut stream: Stream<'a>) -> Self {
56        stream.pair(Name(b"FunctionType"), FunctionType::Sampled.to_int());
57        Self { stream }
58    }
59
60    common_func_methods!();
61
62    /// Write the `/Size` attribute.
63    ///
64    /// Sets the number of input samples per dimension. Required.
65    pub fn size(&mut self, size: impl IntoIterator<Item = i32>) -> &mut Self {
66        self.insert(Name(b"Size")).array().items(size);
67        self
68    }
69
70    /// Write the `/BitsPerSample` attribute.
71    ///
72    /// Sets the number of bits per input sample. Required.
73    pub fn bits_per_sample(&mut self, bits: i32) -> &mut Self {
74        self.pair(Name(b"BitsPerSample"), bits);
75        self
76    }
77
78    /// Write the `/Order` attribute.
79    ///
80    /// Choose the implementation kind.
81    pub fn order(&mut self, order: InterpolationOrder) -> &mut Self {
82        self.pair(Name(b"Order"), order.to_int());
83        self
84    }
85
86    /// Write the `/Encode` attribute.
87    ///
88    /// For each sample, define how the input is mapped to the domain range.
89    pub fn encode(&mut self, encode: impl IntoIterator<Item = f32>) -> &mut Self {
90        self.insert(Name(b"Encode")).array().items(encode);
91        self
92    }
93
94    /// Write the `/Decode` attribute.
95    ///
96    /// For each sample, define how the output is mapped to the output range.
97    pub fn decode(&mut self, decode: impl IntoIterator<Item = f32>) -> &mut Self {
98        self.insert(Name(b"Decode")).array().items(decode);
99        self
100    }
101}
102
103deref!('a, SampledFunction<'a> => Stream<'a>, stream);
104
105/// How to interpolate between the samples in a function of the
106/// sampled type.
107#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
108pub enum InterpolationOrder {
109    /// Linear spline interpolation.
110    #[default]
111    Linear,
112    /// Cubic spline interpolation.
113    Cubic,
114}
115
116impl InterpolationOrder {
117    pub(crate) fn to_int(self) -> i32 {
118        match self {
119            Self::Linear => 1,
120            Self::Cubic => 3,
121        }
122    }
123}
124
125/// Writer for an _exponential function dictionary_. PDF 1.3+.
126///
127/// The function result is `y_i = C0_i + x^N * (C1_i - C0_i)` where `i` is the
128/// current dimension.
129///
130/// This struct is created by [`Chunk::exponential_function`] and
131/// [`writers::Separation::tint_exponential`].
132pub struct ExponentialFunction<'a> {
133    dict: Dict<'a>,
134}
135
136writer!(ExponentialFunction: |obj| {
137    let mut dict = obj.dict();
138    dict.pair(Name(b"FunctionType"), FunctionType::Exponential.to_int());
139    Self { dict }
140});
141
142impl ExponentialFunction<'_> {
143    common_func_methods!();
144
145    /// Write the `/C0` array.
146    ///
147    /// Function result when input is zero. Default is `0.0`.
148    pub fn c0(&mut self, c0: impl IntoIterator<Item = f32>) -> &mut Self {
149        self.insert(Name(b"C0")).array().items(c0);
150        self
151    }
152
153    /// Write the `/C1` array.
154    ///
155    /// Function result when input is one. Default is `1.0`.
156    pub fn c1(&mut self, c1: impl IntoIterator<Item = f32>) -> &mut Self {
157        self.insert(Name(b"C1")).array().items(c1);
158        self
159    }
160
161    /// Write the `/N` attribute.
162    ///
163    /// The interpolation exponent. Required.
164    pub fn n(&mut self, n: f32) -> &mut Self {
165        self.pair(Name(b"N"), n);
166        self
167    }
168}
169
170deref!('a, ExponentialFunction<'a> => Dict<'a>, dict);
171
172/// Writer for a _stitching function dictionary_. PDF 1.3+.
173///
174/// The function result is `y_i = C0_i + x^N * (C1_i - C0_i)` where `i` is the
175/// current dimension.
176///
177/// This struct is created by [`Chunk::stitching_function`] and
178/// [`writers::Separation::tint_stitching`].
179pub struct StitchingFunction<'a> {
180    dict: Dict<'a>,
181}
182
183writer!(StitchingFunction: |obj| {
184    let mut dict = obj.dict();
185    dict.pair(Name(b"FunctionType"), FunctionType::Stitching.to_int());
186    Self { dict }
187});
188
189impl StitchingFunction<'_> {
190    common_func_methods!();
191
192    /// Write the `/Functions` array.
193    ///
194    /// The functions to be stitched. Required.
195    pub fn functions(&mut self, functions: impl IntoIterator<Item = Ref>) -> &mut Self {
196        self.insert(Name(b"Functions")).array().items(functions);
197        self
198    }
199
200    /// Write the `/Bounds` array.
201    ///
202    /// The boundaries of the intervals that each function is called in. The
203    /// array has one less entry than there are stiched functions. Required.
204    pub fn bounds(&mut self, bounds: impl IntoIterator<Item = f32>) -> &mut Self {
205        self.insert(Name(b"Bounds")).array().items(bounds);
206        self
207    }
208
209    /// Write the `/Encode` array.
210    ///
211    /// Pair of values for each function that maps the stitching domain subsets
212    /// to the function domain. Required.
213    pub fn encode(&mut self, encode: impl IntoIterator<Item = f32>) -> &mut Self {
214        self.insert(Name(b"Encode")).array().items(encode);
215        self
216    }
217}
218
219deref!('a, StitchingFunction<'a> => Dict<'a>, dict);
220
221/// Writer for a _PostScript function stream_. PDF 1.3+.
222///
223/// This struct is created by [`Chunk::post_script_function`].
224pub struct PostScriptFunction<'a> {
225    stream: Stream<'a>,
226}
227
228impl<'a> PostScriptFunction<'a> {
229    /// Create a new postscript function writer.
230    pub(crate) fn start(mut stream: Stream<'a>) -> Self {
231        stream.pair(Name(b"FunctionType"), FunctionType::PostScript.to_int());
232        Self { stream }
233    }
234
235    common_func_methods!();
236}
237
238deref!('a, PostScriptFunction<'a> => Stream<'a>, stream);
239
240/// PostScript operators for use in Type 4 functions.
241#[derive(Debug, Copy, Clone, PartialEq)]
242pub enum PostScriptOp<'a> {
243    /// Push a real number.
244    Real(f32),
245    /// Push an integer number.
246    Integer(i32),
247
248    /// Absolute value. One number argument.
249    Abs,
250    /// Addition. Two number arguments.
251    Add,
252    /// Arc tangent. One number argument.
253    Atan,
254    /// Round up to the nearest integer. One number argument.
255    Ceiling,
256    /// Cosine. One number argument.
257    Cos,
258    /// Convert to integer. One real number argument.
259    Cvi,
260    /// Convert to real. One integer argument.
261    Cvr,
262    /// Divide. Two number arguments.
263    Div,
264    /// Raise the base to the exponent. Two number arguments.
265    Exp,
266    /// Round down to the nearest integer. One number argument.
267    Floor,
268    /// Integer division. Two integer arguments.
269    Idiv,
270    /// Natural logarithm. One number argument.
271    Ln,
272    /// Logarithm base 10. One number argument.
273    Log,
274    /// Modulo. Two integer arguments.
275    Mod,
276    /// Multiply. Two number arguments.
277    Mul,
278    /// Negate. One number argument.
279    Neg,
280    /// Round to the nearest integer. One number argument.
281    Round,
282    /// Sine. One number argument.
283    Sin,
284    /// Square root. One number argument.
285    Sqrt,
286    /// Subtract. Two number arguments.
287    Sub,
288    /// Remove fractional part. One number argument.
289    Truncate,
290
291    /// Logical bitwise And. Two integer or boolean arguments.
292    And,
293    /// Bitwise shift left. Negative shifts possible. Two integer arguments.
294    Bitshift,
295    /// Equals. Any two arguments of the same type.
296    Eq,
297    /// Constant false.
298    False,
299    /// Greater than or equal. Two number arguments.
300    Ge,
301    /// Greater than. Two number arguments.
302    Gt,
303    /// Less than or equal. Two number arguments.
304    Le,
305    /// Less than. Two number arguments.
306    Lt,
307    /// Not equals. Any two arguments of the same type.
308    Ne,
309    /// Bitwise logical not. One integer or boolean argument.
310    Not,
311    /// Bitwise logical or. Two integer or boolean arguments.
312    Or,
313    /// Constant true.
314    True,
315    /// Bitwise logical exclusive or. Two integer or boolean arguments.
316    Xor,
317
318    /// Conditional. Runs if boolean argument is true.
319    If(&'a [Self]),
320    /// Conditional. Decides which branch to run depending on boolean argument.
321    IfElse(&'a [Self], &'a [Self]),
322
323    /// Copy the top elements. One integer argument.
324    Copy,
325    /// Duplicate the top element.
326    Dup,
327    /// Exchange the two top elements.
328    Exch,
329    /// Duplicate any element. One integer argument.
330    Index,
331    /// Discard the top element.
332    Pop,
333    /// Roll `n` elements up `j` times. Two integer arguments.
334    Roll,
335}
336
337impl PostScriptOp<'_> {
338    /// Encode a slice of operations into a byte stream.
339    pub fn encode(ops: &[Self]) -> Buf {
340        let mut buf = Buf::new();
341        Self::write_slice(ops, &mut buf);
342        buf
343    }
344
345    fn write_slice(ops: &[Self], buf: &mut Buf) {
346        buf.push(b'{');
347        if ops.len() > 1 {
348            buf.push(b' ');
349        }
350        for op in ops {
351            op.write(buf);
352            buf.push(b' ');
353        }
354        if ops.len() == 1 {
355            buf.inner.pop();
356        }
357        buf.push(b'}');
358    }
359
360    fn write(&self, buf: &mut Buf) {
361        match *self {
362            Self::Real(r) => buf.push_decimal(r),
363            Self::Integer(i) => buf.push_val(i),
364            Self::If(ops) => {
365                Self::write_slice(ops, buf);
366                buf.push(b' ');
367                buf.extend(self.operator());
368            }
369            Self::IfElse(ops1, ops2) => {
370                Self::write_slice(ops1, buf);
371                buf.push(b' ');
372                Self::write_slice(ops2, buf);
373                buf.push(b' ');
374                buf.extend(self.operator());
375            }
376            _ => buf.extend(self.operator()),
377        }
378    }
379
380    fn operator(&self) -> &'static [u8] {
381        match self {
382            Self::Real(_) | Self::Integer(_) => b"",
383            Self::Abs => b"abs",
384            Self::Add => b"add",
385            Self::Atan => b"atan",
386            Self::Ceiling => b"ceiling",
387            Self::Cos => b"cos",
388            Self::Cvi => b"cvi",
389            Self::Cvr => b"cvr",
390            Self::Div => b"div",
391            Self::Exp => b"exp",
392            Self::Floor => b"floor",
393            Self::Idiv => b"idiv",
394            Self::Ln => b"ln",
395            Self::Log => b"log",
396            Self::Mod => b"mod",
397            Self::Mul => b"mul",
398            Self::Neg => b"neg",
399            Self::Round => b"round",
400            Self::Sin => b"sin",
401            Self::Sqrt => b"sqrt",
402            Self::Sub => b"sub",
403            Self::Truncate => b"truncate",
404            Self::And => b"and",
405            Self::Bitshift => b"bitshift",
406            Self::Eq => b"eq",
407            Self::False => b"false",
408            Self::Ge => b"ge",
409            Self::Gt => b"gt",
410            Self::Le => b"le",
411            Self::Lt => b"lt",
412            Self::Ne => b"ne",
413            Self::Not => b"not",
414            Self::Or => b"or",
415            Self::True => b"true",
416            Self::Xor => b"xor",
417            Self::If(_) => b"if",
418            Self::IfElse(_, _) => b"ifelse",
419            Self::Copy => b"copy",
420            Self::Dup => b"dup",
421            Self::Exch => b"exch",
422            Self::Index => b"index",
423            Self::Pop => b"pop",
424            Self::Roll => b"roll",
425        }
426    }
427}
428
429#[cfg(test)]
430mod tests {
431    use super::*;
432
433    #[test]
434    fn test_post_script_encoding() {
435        use PostScriptOp::*;
436
437        let ops = [
438            Real(3.0),
439            Real(2.0),
440            Mul,
441            Exch,
442            Dup,
443            Real(0.0),
444            Ge,
445            IfElse(&[Real(1.0), Add], &[Neg]),
446            Add,
447        ];
448
449        assert_eq!(
450            PostScriptOp::encode(&ops).as_slice(),
451            b"{ 3.0 2.0 mul exch dup 0.0 ge { 1.0 add } {neg} ifelse add }"
452        );
453    }
454}