Skip to content

DPI / PPI Calculator — Go 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 Go implementation — the same logic the interactive tool runs, in a shareable, citable form.

// Package dpippi is the Go twin of CosmoDev's src/lib/dpi-ppi.ts (dual source:
// the web lib is TypeScript, the CLI lib is Go — kept in lock-step). Pure +
// deterministic, never panics. The table-driven tests in dpi-ppi_test.go share
// vectors with src/lib/dpi-ppi.test.ts so the two implementations are held to
// the same contract.
//
// The logic mirrors the TS lib exactly. Non-positive inputs that cause a
// division by zero produce NaN or +Inf — documented IEEE 754 float64 behavior,
// identical to JS — rather than panicking. Callers should guard with
// math.IsFinite before display.
package dpippi

import (
	"fmt"
	"math"
)

// MmPerInch is the millimeters-per-inch conversion factor (25.4). Mirrors the
// private MM_PER_INCH constant in src/lib/dpi-ppi.ts.
const MmPerInch = 25.4

// DiagonalPixels returns the diagonal length in pixels: √(w² + h²). The sign of
// the inputs is irrelevant because they are squared. It mirrors
// diagonalPixels() in src/lib/dpi-ppi.ts.
func DiagonalPixels(w, h float64) float64 {
	return math.Sqrt(w*w + h*h)
}

// PpiInput is the input to ComputePpi: a resolution plus a known physical
// diagonal in inches. It mirrors the {w, h, diagonalInches} object in the TS
// lib.
type PpiInput struct {
	W              float64
	H              float64
	DiagonalInches float64
}

// PpiResult holds the pixels-per-inch value derived from a resolution and a
// known diagonal. It mirrors the {ppi} object returned by computePpi().
type PpiResult struct {
	Ppi float64
}

// ComputePpi derives pixels-per-inch from a resolution and a known diagonal
// (inches). A zero diagonal with a non-zero resolution yields +Inf; a fully
// zero input yields NaN — mirroring JS (never panics). It mirrors
// computePpi() in src/lib/dpi-ppi.ts.
func ComputePpi(in PpiInput) PpiResult {
	return PpiResult{Ppi: DiagonalPixels(in.W, in.H) / in.DiagonalInches}
}

// SizeInput is the input to PhysicalSize: a resolution plus a pixel density
// (ppi). It mirrors the {w, h, ppi} object in the TS lib.
type SizeInput struct {
	W   float64
	H   float64
	Ppi float64
}

// SizeResult holds the physical dimensions (inches and millimeters) of a
// display derived from its resolution and pixel density. It mirrors the object
// returned by physicalSize().
type SizeResult struct {
	WidthIn    float64
	HeightIn   float64
	DiagonalIn float64
	WidthMm    float64
	HeightMm   float64
}

// PhysicalSize computes the physical dimensions of a display from its
// resolution and ppi, returning inches and millimeters. A zero ppi yields +Inf
// (non-zero resolution) or NaN (fully-zero input) — mirroring JS (never
// panics). It mirrors physicalSize() in src/lib/dpi-ppi.ts.
func PhysicalSize(in SizeInput) SizeResult {
	widthIn := in.W / in.Ppi
	heightIn := in.H / in.Ppi
	return SizeResult{
		WidthIn:    widthIn,
		HeightIn:   heightIn,
		DiagonalIn: DiagonalPixels(widthIn, heightIn),
		WidthMm:    widthIn * MmPerInch,
		HeightMm:   heightIn * MmPerInch,
	}
}

// DotPitch returns the pixel size in millimeters per pixel (25.4 / ppi). A zero
// ppi yields +Inf — mirroring JS (never panics). It mirrors dotPitch() in
// src/lib/dpi-ppi.ts.
func DotPitch(ppi float64) float64 {
	return MmPerInch / ppi
}

// gcd is the integer gcd (Euclid's algorithm) computed over the truncated,
// absolute values of its inputs. It is used to reduce aspect ratios and mirrors
// the private gcd() helper in src/lib/dpi-ppi.ts.
func gcd(a, b float64) float64 {
	x := math.Abs(math.Trunc(a))
	y := math.Abs(math.Trunc(b))
	for y != 0 {
		x, y = y, math.Mod(x, y)
	}
	return x
}

// AspectRatio returns the reduced aspect ratio "w:h" (e.g. "16:9"), or "-" if
// either side is non-positive or the gcd collapses to zero. It mirrors
// aspectRatio() in src/lib/dpi-ppi.ts.
func AspectRatio(w, h float64) string {
	if !(w > 0) || !(h > 0) {
		return "-"
	}
	g := gcd(w, h)
	if g == 0 {
		return "-"
	}
	return fmt.Sprintf("%d:%d", int64(math.Trunc(w)/g), int64(math.Trunc(h)/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 →