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