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}