pdfium_render/pdf/
points.rs

1//! Defines the [PdfPoints] struct, the basic unit of measurement within the internal
2//! coordinate system inside a [PdfDocument].
3
4use std::cmp::Ordering;
5use std::fmt::{Display, Formatter};
6use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
7
8#[cfg(doc)]
9use {
10    crate::pdf::bitmap::PdfBitmap, crate::pdf::document::page::PdfPage,
11    crate::pdf::document::PdfDocument,
12};
13
14/// The internal coordinate system inside a [PdfDocument] is measured in Points, a
15/// device-independent unit equal to 1/72 inches, roughly 0.358 mm. Points are converted to pixels
16/// when a [PdfPage] is rendered into a [PdfBitmap].
17#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
18pub struct PdfPoints {
19    pub value: f32,
20}
21
22impl PdfPoints {
23    /// A [PdfPoints] object with identity value 0.0.
24    pub const ZERO: PdfPoints = PdfPoints::zero();
25
26    /// A [PdfPoints] object with the largest addressable finite positive value.
27    pub const MAX: PdfPoints = PdfPoints::max();
28
29    /// A [PdfPoints] object with the smallest addressable finite negative value.
30    pub const MIN: PdfPoints = PdfPoints::min();
31
32    /// Creates a new [PdfPoints] object with the given value.
33    #[inline]
34    pub const fn new(value: f32) -> Self {
35        Self { value }
36    }
37
38    /// Creates a new [PdfPoints] object with the value 0.0.
39    ///
40    /// Consider using the compile-time constant value [PdfPoints::ZERO]
41    /// rather than calling this function directly.
42    #[inline]
43    pub const fn zero() -> Self {
44        Self::new(0.0)
45    }
46
47    /// A [PdfPoints] object with the largest addressable finite positive value.
48    ///
49    /// In theory, this should be [f32::MAX]; in practice, values approaching [f32::MAX]
50    /// are handled inconsistently by Pdfium, so this value is set to an arbitrarily large
51    /// positive value that does not approach [f32::MAX] but should more than suffice
52    /// for every use case.
53    #[inline]
54    pub const fn max() -> Self {
55        Self::new(2_000_000_000.0)
56    }
57
58    /// A [PdfPoints] object with the smallest addressable finite negative value.
59    ///
60    /// In theory, this should be [f32::MIN]; in practice, values approaching [f32::MIN]
61    /// are handled inconsistently by Pdfium, so this value is set to an arbitrarily large
62    /// negative value that does not approach [f32::MIN] but should more than suffice
63    /// for every use case.
64    #[inline]
65    pub const fn min() -> Self {
66        Self::new(-2_000_000_000.0)
67    }
68
69    /// Creates a new [PdfPoints] object from the given measurement in inches.
70    #[inline]
71    pub fn from_inches(inches: f32) -> Self {
72        Self::new(inches * 72.0)
73    }
74
75    /// Creates a new [PdfPoints] object from the given measurement in centimeters.
76    #[inline]
77    pub fn from_cm(cm: f32) -> Self {
78        Self::from_inches(cm / 2.54)
79    }
80
81    /// Creates a new [PdfPoints] object from the given measurement in millimeters.
82    #[inline]
83    pub fn from_mm(mm: f32) -> Self {
84        Self::from_cm(mm / 10.0)
85    }
86
87    /// Converts the value of this [PdfPoints] object to inches.
88    #[inline]
89    pub fn to_inches(&self) -> f32 {
90        self.value / 72.0
91    }
92
93    /// Converts the value of this [PdfPoints] object to centimeters.
94    #[inline]
95    pub fn to_cm(&self) -> f32 {
96        self.to_inches() * 2.54
97    }
98
99    /// Converts the value of this [PdfPoints] object to millimeters.
100    #[inline]
101    pub fn to_mm(&self) -> f32 {
102        self.to_cm() * 10.0
103    }
104
105    /// Creates a new [PdfPoints] object with the absolute value of this [PdfPoints] object.
106    #[inline]
107    pub fn abs(&self) -> PdfPoints {
108        PdfPoints::new(self.value.abs())
109    }
110}
111
112impl Add<PdfPoints> for PdfPoints {
113    type Output = PdfPoints;
114
115    #[inline]
116    fn add(self, rhs: Self) -> Self::Output {
117        PdfPoints::new(self.value + rhs.value)
118    }
119}
120
121impl AddAssign<PdfPoints> for PdfPoints {
122    #[inline]
123    fn add_assign(&mut self, rhs: PdfPoints) {
124        self.value += rhs.value;
125    }
126}
127
128impl Sub<PdfPoints> for PdfPoints {
129    type Output = PdfPoints;
130
131    #[inline]
132    fn sub(self, rhs: Self) -> Self::Output {
133        PdfPoints::new(self.value - rhs.value)
134    }
135}
136
137impl SubAssign<PdfPoints> for PdfPoints {
138    #[inline]
139    fn sub_assign(&mut self, rhs: PdfPoints) {
140        self.value -= rhs.value;
141    }
142}
143
144impl Mul<f32> for PdfPoints {
145    type Output = PdfPoints;
146
147    #[inline]
148    fn mul(self, rhs: f32) -> Self::Output {
149        PdfPoints::new(self.value * rhs)
150    }
151}
152
153impl Div<f32> for PdfPoints {
154    type Output = PdfPoints;
155
156    #[inline]
157    fn div(self, rhs: f32) -> Self::Output {
158        PdfPoints::new(self.value / rhs)
159    }
160}
161
162impl Neg for PdfPoints {
163    type Output = PdfPoints;
164
165    #[inline]
166    fn neg(self) -> Self::Output {
167        PdfPoints::new(-self.value)
168    }
169}
170
171impl Eq for PdfPoints {}
172
173#[allow(clippy::derive_ord_xor_partial_ord)]
174// We would ideally use f32::total_cmp() here, but it was not stabilized until 1.62.0.
175// Providing our own (simple) implementation allows for better backwards compatibility.
176// Strictly speaking, our implementation is not _true_ total ordering because it treats
177// +0 and -0 to be equal; but for the purposes of this library and this specific data type,
178// this minor deviation from true total ordering is acceptable.
179//
180// For a deeper dive on the precise considerations of total ordering as applied to
181// floating point values, see: https://github.com/rust-lang/rust/pull/72568
182impl Ord for PdfPoints {
183    #[inline]
184    fn cmp(&self, other: &Self) -> Ordering {
185        self.value
186            .partial_cmp(&other.value)
187            .unwrap_or(Ordering::Equal)
188    }
189}
190
191impl Display for PdfPoints {
192    #[inline]
193    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
194        f.write_fmt(format_args!("PdfPoints({})", self.value))
195    }
196}
197
198#[cfg(test)]
199mod tests {
200    use crate::prelude::*;
201
202    #[test]
203    fn test_points_ordering() {
204        assert!(PdfPoints::new(1.0) > PdfPoints::ZERO);
205        assert_eq!(PdfPoints::ZERO, -PdfPoints::ZERO);
206        assert!(PdfPoints::ZERO > PdfPoints::new(-1.0));
207    }
208}