Skip to content

DPI / PPI Calculator — Rust source

Compute screen pixel density (PPI/DPI), dot pitch, physical dimensions, and aspect ratio from any resolution. Solve for PPI from a diagonal, or derive the diagonal from a known PPI - all in your browser.

This is the Rust implementation — the same logic the interactive tool runs, in a shareable, citable form.

//! Display pixel-density math (Rust port).
//!
//! Pure, deterministic, never panics. Non-positive inputs that would cause
//! division by zero produce `NaN` or infinity (IEEE-754 behavior — Rust's
//! `f64` division follows the standard and does not panic) rather than
//! returning a `Result`; callers should guard with `f64::is_finite` before
//! display.
//!
//! CosmoDev polyglot showcase port of `dpi-ppi`, ported from
//! `src/lib/dpi-ppi.ts`. Display source — part of CosmoDev's polyglot tool pages.

/// Fixed conversion factor between inches and millimeters.
const MM_PER_INCH: f64 = 25.4;

/// A resolution (width and height) in pixels, shared by the calculations
/// that consume a pixel grid.
#[derive(Clone, Copy, Debug)]
pub struct Resolution {
    pub w: f64,
    pub h: f64,
}

/// Pixels-per-inch result.
#[derive(Clone, Copy, Debug)]
pub struct Ppi {
    pub ppi: f64,
}

/// Physical dimensions of a display, in both inches and millimeters.
#[derive(Clone, Copy, Debug)]
pub struct PhysicalSize {
    pub width_in: f64,
    pub height_in: f64,
    pub diagonal_in: f64,
    pub width_mm: f64,
    pub height_mm: f64,
}

/// Diagonal length in pixels: √(w² + h²).
/// The sign of the inputs is irrelevant because both terms are squared.
pub fn diagonal_pixels(w: f64, h: f64) -> f64 {
    (w * w + h * h).sqrt()
}

/// Pixels per inch, given a resolution and a known physical diagonal in inches.
pub fn compute_ppi(r: Resolution, diagonal_inches: f64) -> Ppi {
    Ppi {
        ppi: diagonal_pixels(r.w, r.h) / diagonal_inches,
    }
}

/// Derive inches and millimeters from a resolution and a ppi. The diagonal is
/// recomputed from the derived inch dimensions so it stays consistent with
/// the width/height values.
pub fn physical_size(r: Resolution, ppi: f64) -> PhysicalSize {
    let width_in = r.w / ppi;
    let height_in = r.h / ppi;
    PhysicalSize {
        width_in,
        height_in,
        diagonal_in: diagonal_pixels(width_in, height_in),
        width_mm: width_in * MM_PER_INCH,
        height_mm: height_in * MM_PER_INCH,
    }
}

/// Dot pitch (pixel size) in millimeters per pixel: 25.4 / ppi.
pub fn dot_pitch(ppi: f64) -> f64 {
    MM_PER_INCH / ppi
}

/// Integer greatest-common-divisor via Euclid's algorithm, used to reduce
/// aspect ratios. Inputs are truncated toward zero and taken in absolute
/// value first, so the sign and fractional part of the inputs never matter.
fn gcd(a: f64, b: f64) -> i64 {
    let mut x = a.trunc().abs() as i64;
    let mut y = b.trunc().abs() as i64;
    while y != 0 {
        let t = y;
        y = x % y;
        x = t;
    }
    x
}

/// Reduced aspect ratio as "w:h" (e.g. "16:9").
/// Returns "-" when either side is not a positive number (this also covers
/// NaN, since every comparison with NaN is false).
pub fn aspect_ratio(w: f64, h: f64) -> String {
    if !(w > 0.0) || !(h > 0.0) {
        return String::from("-");
    }
    let g = gcd(w, h);
    if g == 0 {
        return String::from("-");
    }
    let wi = w.trunc() as i64;
    let hi = h.trunc() as i64;
    format!("{}:{}", wi / g, hi / g)
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →