DPI / PPI Calculator — C# 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 C# implementation — the same logic the interactive tool runs, in a shareable, citable form.
// =============================================================================
// DpiPpi.cs — CosmoDev polyglot showcase port of the `dpi-ppi` tool
// -----------------------------------------------------------------------------
// Language : C# (C# 12, standard library only)
// Source: ported from src/lib/dpi-ppi.ts (the canonical, live TypeScript
// lib); mirrors src/tool-sources/dpi-ppi/{python.py,rust.rs}
// License : display source — part of CosmoDev's polyglot tool pages
// (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/
// Python ports and the other language ports.
// -----------------------------------------------------------------------------
// Display pixel-density math. Diagonal length in pixels, pixels-per-inch
// computed from a known physical diagonal, physical width/height/diagonal in
// both inches and millimeters, dot pitch in millimeters per pixel, and a
// reduced aspect ratio — all derived from a pixel resolution.
//
// Pure, deterministic, side-effect free. A zero divisor does not throw:
// double division follows IEEE-754, so x / 0.0 yields ±Infinity and
// 0.0 / 0.0 yields NaN — callers should guard with double.IsFinite before
// display. (The Python port routes every division through a SafeDiv wrapper
// only because Python raises ZeroDivisionError for float division.)
// =============================================================================
namespace CosmoDev.DpiPpi;
/// <summary>Display pixel-density math.</summary>
public static class DpiPpi
{
/// <summary>Fixed conversion factor between inches and millimeters.</summary>
public const double MmPerInch = 25.4;
/// <summary>Pixels-per-inch result.</summary>
public readonly record struct Ppi(double Ppi);
/// <summary>Physical dimensions of a display, in inches and millimeters.</summary>
public readonly record struct PhysicalSize(
double WidthIn,
double HeightIn,
double DiagonalIn,
double WidthMm,
double HeightMm);
/// <summary>
/// Diagonal length in pixels: √(w² + h²).
/// The sign of the inputs is irrelevant because both terms are squared.
/// </summary>
public static double DiagonalPixels(double w, double h) =>
Math.Sqrt(w * w + h * h);
/// <summary>Pixels per inch, given a resolution and a known physical diagonal in inches.</summary>
public static Ppi ComputePpi(double w, double h, double diagonalInches) =>
new(DiagonalPixels(w, h) / diagonalInches);
/// <summary>
/// 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.
/// </summary>
public static PhysicalSize PhysicalSizeFromPpi(double w, double h, double ppi)
{
double widthIn = w / ppi;
double heightIn = h / ppi;
return new PhysicalSize(
WidthIn: widthIn,
HeightIn: heightIn,
DiagonalIn: DiagonalPixels(widthIn, heightIn),
WidthMm: widthIn * MmPerInch,
HeightMm: heightIn * MmPerInch);
}
/// <summary>Dot pitch (pixel size) in millimeters per pixel: 25.4 / ppi.</summary>
public static double DotPitch(double ppi) => MmPerInch / ppi;
/// <summary>
/// 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. (The casts assume finite inputs — the w > 0 / h > 0
/// guard in <see cref="AspectRatio"/> has already rejected NaN and
/// negatives, and real resolutions are far below the i64 range.)
/// </summary>
private static long Gcd(double a, double b)
{
long x = Math.Abs((long)Math.Truncate(a));
long y = Math.Abs((long)Math.Truncate(b));
while (y != 0)
{
(x, y) = (y, x % y);
}
return x;
}
/// <summary>
/// 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).
/// </summary>
public static string AspectRatio(double w, double h)
{
if (!(w > 0) || !(h > 0))
{
return "-";
}
long g = Gcd(w, h);
if (g == 0)
{
return "-";
}
long wi = (long)Math.Truncate(w);
long hi = (long)Math.Truncate(h);
return $"{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 →