Skip to main content

pdfium_render/pdf/
transform.rs

1#[doc(hidden)]
2#[macro_export]
3macro_rules! create_transform_setters {
4
5    (
6        $self_:ty,
7        $ret_:ty,
8        $doc_ref_:literal,
9        $doc_ref_period_:literal,
10        $doc_ref_comma_:literal,
11        $custom_doc_:literal,
12        $reset_matrix_visibility_:vis
13    ) => {
14        /// Applies the given transformation, expressed as six values representing the six configurable
15        /// elements of a nine-element 3x3 PDF transformation matrix, to
16        #[doc = $doc_ref_period_ ]
17        ///
18        #[doc = $custom_doc_ ]
19        ///
20        /// To move, scale, rotate, or skew
21        #[doc = $doc_ref_comma_ ]
22        /// consider using one or more of
23        /// the following functions. Internally they all use [Self::transform], but are
24        /// probably easier to use (and certainly clearer in their intent) in most situations.
25        ///
26        /// * [Self::translate]: changes the position of
27        #[doc = $doc_ref_period_ ]
28        /// * [Self::scale]: changes the size of
29        #[doc = $doc_ref_period_ ]
30        /// * [Self::flip_horizontally]: flips
31        #[doc = $doc_ref_ ]
32        /// horizontally around its origin.
33        /// * [Self::flip_vertically]: flips
34        #[doc = $doc_ref_ ]
35        /// vertically around its origin.
36        /// * [Self::rotate_clockwise_degrees], [Self::rotate_counter_clockwise_degrees],
37        /// [Self::rotate_clockwise_radians], [Self::rotate_counter_clockwise_radians]: rotates
38        #[doc = $doc_ref_ ]
39        /// around its origin.
40        /// * [Self::skew_degrees], [Self::skew_radians]: skews
41        #[doc = $doc_ref_ ]
42        /// relative to its axes.
43        ///
44        /// **The order in which transformations are applied is significant.**
45        /// For example, the result of rotating _then_ translating an object may be vastly different
46        /// from translating _then_ rotating the same object.
47        ///
48        /// An overview of PDF transformation matrices can be found in the PDF Reference Manual
49        /// version 1.7 on page 204; a detailed description can be found in section 4.2.3 on page 207.
50        #[inline]
51        pub fn transform(
52            self: $self_,
53            a: PdfMatrixValue,
54            b: PdfMatrixValue,
55            c: PdfMatrixValue,
56            d: PdfMatrixValue,
57            e: PdfMatrixValue,
58            f: PdfMatrixValue,
59        ) -> $ret_ {
60            self.transform_impl(a, b, c, d, e, f)
61        }
62
63        /// Applies the given transformation, expressed as a [PdfMatrix], to
64        #[doc = $doc_ref_period_ ]
65        ///
66        #[doc = $custom_doc_ ]
67        #[inline]
68        pub fn apply_matrix(self: $self_, matrix: PdfMatrix) -> $ret_ {
69            self.transform_impl(
70                matrix.a(),
71                matrix.b(),
72                matrix.c(),
73                matrix.d(),
74                matrix.e(),
75                matrix.f(),
76            )
77        }
78
79        #[deprecated(
80            since = "0.8.15",
81            note = "This function has been renamed to better reflect its behaviour. Use the apply_matrix() function instead."
82        )]
83        #[doc(hidden)]
84        #[inline]
85        pub fn set_matrix(self: $self_, matrix: PdfMatrix) -> $ret_ {
86            self.apply_matrix(matrix)
87        }
88
89        /// Resets the transform matrix for
90        #[doc = $doc_ref_ ]
91        /// to the the given [PdfMatrix], overriding any previously applied transformations.
92        ///
93        #[doc = $custom_doc_ ]
94        #[inline]
95        #[allow(dead_code)]
96        $reset_matrix_visibility_ fn reset_matrix(self: $self_, matrix: PdfMatrix) -> $ret_ {
97            self.reset_matrix_impl(matrix)
98        }
99
100        /// Resets the transformation matrix for
101        #[doc = $doc_ref_ ]
102        /// to the identity matrix, undoing any previously applied transformations.
103        ///
104        #[doc = $custom_doc_ ]
105        #[inline]
106        #[allow(dead_code)]
107        $reset_matrix_visibility_ fn reset_matrix_to_identity(self: $self_) -> $ret_ {
108            self.reset_matrix(PdfMatrix::IDENTITY)
109        }
110
111        /// Moves the origin of
112        #[doc = $doc_ref_ ]
113        /// by the given horizontal and vertical delta distances.
114        ///
115        #[doc = $custom_doc_ ]
116        #[inline]
117        pub fn translate(self: $self_, delta_x: PdfPoints, delta_y: PdfPoints) -> $ret_ {
118            self.transform(1.0, 0.0, 0.0, 1.0, delta_x.value, delta_y.value)
119        }
120
121        /// Changes the size of
122        #[doc = $doc_ref_comma_ ]
123        /// scaling it by the given horizontal and vertical scale factors.
124        ///
125        #[doc = $custom_doc_ ]
126        #[inline]
127        pub fn scale(
128            self: $self_,
129            horizontal_scale_factor: PdfMatrixValue,
130            vertical_scale_factor: PdfMatrixValue,
131        ) -> $ret_ {
132            self.transform(
133                horizontal_scale_factor,
134                0.0,
135                0.0,
136                vertical_scale_factor,
137                0.0,
138                0.0,
139            )
140        }
141
142        /// Flips
143        #[doc = $doc_ref_ ]
144        /// horizontally around its origin by applying a horizontal scale factor of -1.
145        ///
146        #[doc = $custom_doc_ ]
147        #[inline]
148        pub fn flip_horizontally(self: $self_) -> $ret_ {
149            self.scale(-1.0, 1.0)
150        }
151
152        /// Flips
153        #[doc = $doc_ref_ ]
154        /// vertically around its origin by applying a vertical scale factor of -1.
155        ///
156        #[doc = $custom_doc_ ]
157        #[inline]
158        pub fn flip_vertically(self: $self_) -> $ret_ {
159            self.scale(1.0, -1.0)
160        }
161
162        /// Reflects
163        #[doc = $doc_ref_ ]
164        /// by flipping it both horizontally and vertically around its origin.
165        ///
166        #[doc = $custom_doc_ ]
167        #[inline]
168        pub fn reflect(self: $self_) -> $ret_ {
169            self.scale(-1.0, -1.0)
170        }
171
172        /// Rotates
173        #[doc = $doc_ref_ ]
174        /// counter-clockwise by the given number of degrees.
175        ///
176        #[doc = $custom_doc_ ]
177        #[inline]
178        pub fn rotate_counter_clockwise_degrees(self: $self_, degrees: PdfMatrixValue) -> $ret_ {
179            self.rotate_counter_clockwise_radians(degrees.to_radians())
180        }
181
182        /// Rotates
183        #[doc = $doc_ref_ ]
184        /// clockwise by the given number of degrees.
185        ///
186        #[doc = $custom_doc_ ]
187        #[inline]
188        pub fn rotate_clockwise_degrees(self: $self_, degrees: PdfMatrixValue) -> $ret_ {
189            self.rotate_counter_clockwise_degrees(-degrees)
190        }
191
192        /// Rotates
193        #[doc = $doc_ref_ ]
194        /// counter-clockwise by the given number of radians.
195        ///
196        #[doc = $custom_doc_ ]
197        #[inline]
198        pub fn rotate_counter_clockwise_radians(self: $self_, radians: PdfMatrixValue) -> $ret_ {
199            let cos_theta = radians.cos();
200
201            let sin_theta = radians.sin();
202
203            self.transform(cos_theta, sin_theta, -sin_theta, cos_theta, 0.0, 0.0)
204        }
205
206        /// Rotates
207        #[doc = $doc_ref_ ]
208        /// clockwise by the given number of radians.
209        ///
210        #[doc = $custom_doc_ ]
211        #[inline]
212        pub fn rotate_clockwise_radians(self: $self_, radians: PdfMatrixValue) -> $ret_ {
213            self.rotate_counter_clockwise_radians(-radians)
214        }
215
216        /// Skews the axes of
217        #[doc = $doc_ref_ ]
218        /// by the given angles in degrees.
219        ///
220        #[doc = $custom_doc_ ]
221        #[inline]
222        pub fn skew_degrees(
223            self: $self_,
224            x_axis_skew: PdfMatrixValue,
225            y_axis_skew: PdfMatrixValue,
226        ) -> $ret_ {
227            self.skew_radians(x_axis_skew.to_radians(), y_axis_skew.to_radians())
228        }
229
230        /// Skews the axes of
231        #[doc = $doc_ref_ ]
232        /// by the given angles in radians.
233        ///
234        #[doc = $custom_doc_ ]
235        #[inline]
236        pub fn skew_radians(
237            self: $self_,
238            x_axis_skew: PdfMatrixValue,
239            y_axis_skew: PdfMatrixValue,
240        ) -> $ret_ {
241            self.transform(1.0, x_axis_skew.tan(), y_axis_skew.tan(), 1.0, 0.0, 0.0)
242        }
243    };
244    ($self_:ty, $ret_:ty, $doc_ref_:literal, $doc_ref_period_:literal, $doc_ref_comma_:literal, $custom_doc_:literal) => {
245        create_transform_setters!(
246            $self_,
247            $ret_,
248            $doc_ref_,
249            $doc_ref_period_,
250            $doc_ref_comma_,
251            $custom_doc_,
252            pub
253        );
254    };
255    ($self_:ty, $ret_:ty, $doc_ref_:literal, $doc_ref_period_:literal, $doc_ref_comma_:literal) => {
256        create_transform_setters!(
257            $self_,
258            $ret_,
259            $doc_ref_,
260            $doc_ref_period_,
261            $doc_ref_comma_,
262            "",
263            pub
264        );
265    };
266}
267
268#[doc(hidden)]
269#[macro_export]
270macro_rules! create_transform_getters {
271    ($doc_ref_:literal, $doc_ref_period_:literal, $doc_ref_comma_:literal) => {
272        /// Returns the transformation matrix currently applied to
273        #[doc = $doc_ref_period_ ]
274        #[inline]
275        pub fn matrix(&self) -> Result<PdfMatrix, PdfiumError> {
276            self.get_matrix_impl()
277        }
278
279        /// Returns the current horizontal and vertical translation of the origin of
280        #[doc = $doc_ref_period_ ]
281        #[inline]
282        pub fn get_translation(&self) -> (PdfPoints, PdfPoints) {
283            (self.get_horizontal_translation(), self.get_vertical_translation())
284        }
285
286        /// Returns the current horizontal translation of the origin of
287        #[doc = $doc_ref_period_ ]
288        #[inline]
289        pub fn get_horizontal_translation(&self) -> PdfPoints {
290            self.matrix()
291                .map(|matrix| PdfPoints::new(matrix.e()))
292                .unwrap_or(PdfPoints::ZERO)
293        }
294
295        /// Returns the current vertical translation of the origin of
296        #[doc = $doc_ref_period_ ]
297        #[inline]
298        pub fn get_vertical_translation(&self) -> PdfPoints {
299            self.matrix()
300                .map(|matrix| PdfPoints::new(matrix.f()))
301                .unwrap_or(PdfPoints::ZERO)
302        }
303
304        /// Returns the current horizontal and vertical scale factors applied to
305        #[doc = $doc_ref_period_ ]
306        #[inline]
307        pub fn get_scale(&self) -> (PdfMatrixValue, PdfMatrixValue) {
308            (self.get_horizontal_scale(), self.get_vertical_scale())
309        }
310
311        /// Returns the current horizontal scale factor applied to
312        #[doc = $doc_ref_period_ ]
313        #[inline]
314        pub fn get_horizontal_scale(&self) -> PdfMatrixValue {
315            self.matrix().map(|matrix| matrix.a()).unwrap_or(0.0)
316        }
317
318        /// Returns the current vertical scale factor applied to
319        #[doc = $doc_ref_period_ ]
320        #[inline]
321        pub fn get_vertical_scale(&self) -> PdfMatrixValue {
322            self.matrix().map(|matrix| matrix.d()).unwrap_or(0.0)
323        }
324
325        /// Returns the counter-clockwise rotation applied to
326        #[doc = $doc_ref_comma_ ]
327        /// in degrees.
328        ///
329        /// If the object is both rotated and skewed, the return value of this function will reflect
330        /// the combined operation.
331        #[inline]
332        pub fn get_rotation_counter_clockwise_degrees(&self) -> PdfMatrixValue {
333            self.get_rotation_counter_clockwise_radians().to_degrees()
334        }
335
336        /// Returns the clockwise rotation applied to
337        #[doc = $doc_ref_comma_ ]
338        /// in degrees.
339        ///
340        /// If the object is both rotated and skewed, the return value of this function will reflect
341        /// the combined operation.
342        #[inline]
343        pub fn get_rotation_clockwise_degrees(&self) -> PdfMatrixValue {
344            -self.get_rotation_counter_clockwise_degrees()
345        }
346
347        /// Returns the counter-clockwise rotation applied to
348        #[doc = $doc_ref_comma_ ]
349        /// in radians.
350        ///
351        /// If the object is both rotated and skewed, the return value of this function will reflect
352        /// the combined operation.
353        #[inline]
354        pub fn get_rotation_counter_clockwise_radians(&self) -> PdfMatrixValue {
355            self.matrix()
356                .map(|matrix| matrix.b().atan2(matrix.a()))
357                .unwrap_or(0.0)
358        }
359
360        /// Returns the clockwise rotation applied to
361        #[doc = $doc_ref_comma_ ]
362        /// in radians.
363        ///
364        /// If the object is both rotated and skewed, the return value of this function will reflect
365        /// the combined operation.
366        #[inline]
367        pub fn get_rotation_clockwise_radians(&self) -> PdfMatrixValue {
368            -self.get_rotation_counter_clockwise_radians()
369        }
370
371        /// Returns the current x axis and y axis skew angles applied to
372        #[doc = $doc_ref_comma_ ]
373        /// in degrees.
374        ///
375        /// If the object is both rotated and skewed, the return value of this function will reflect
376        /// the combined operation.
377        #[inline]
378        pub fn get_skew_degrees(&self) -> (PdfMatrixValue, PdfMatrixValue) {
379            (self.get_x_axis_skew_degrees(), self.get_y_axis_skew_degrees())
380        }
381
382        /// Returns the current x axis skew angle applied to
383        #[doc = $doc_ref_comma_ ]
384        /// in degrees.
385        ///
386        /// If the object is both rotated and skewed, the return value of this function will reflect
387        /// the combined operation.
388        #[inline]
389        pub fn get_x_axis_skew_degrees(&self) -> PdfMatrixValue {
390            self.get_x_axis_skew_radians().to_degrees()
391        }
392
393        /// Returns the current y axis skew applied to
394        #[doc = $doc_ref_comma_ ]
395        /// in degrees.
396        ///
397        /// If the object is both rotated and skewed, the return value of this function will reflect
398        /// the combined operation.
399        #[inline]
400        pub fn get_y_axis_skew_degrees(&self) -> PdfMatrixValue {
401            self.get_y_axis_skew_radians().to_degrees()
402        }
403
404        /// Returns the current x axis and y axis skew angles applied to
405        #[doc = $doc_ref_comma_ ]
406        /// in radians.
407        ///
408        /// If the object is both rotated and skewed, the return value of this function will reflect
409        /// the combined operation.
410        #[inline]
411        pub fn get_skew_radians(&self) -> (PdfMatrixValue, PdfMatrixValue) {
412            (self.get_x_axis_skew_radians(), self.get_y_axis_skew_radians())
413        }
414
415        /// Returns the current x axis skew applied to
416        #[doc = $doc_ref_comma_ ]
417        /// in radians.
418        ///
419        /// If the object is both rotated and skewed, the return value of this function will reflect
420        /// the combined operation.
421        #[inline]
422        pub fn get_x_axis_skew_radians(&self) -> PdfMatrixValue {
423            self.matrix().map(|matrix| matrix.b().atan()).unwrap_or(0.0)
424        }
425
426        /// Returns the current y axis skew applied to
427        #[doc = $doc_ref_comma_ ]
428        /// in radians.
429        ///
430        /// If the object is both rotated and skewed, the return value of this function will reflect
431        /// the combined operation.
432        #[inline]
433        pub fn get_y_axis_skew_radians(&self) -> PdfMatrixValue {
434            self.matrix().map(|matrix| matrix.c().atan()).unwrap_or(0.0)
435        }
436    };
437    () => {
438        create_transform_getters!("this object", "this object.", "this object,");
439    };
440}