DICOM viewer · iPadOS

See beyond the slice.

Open the studies you already have, on your own iPad. Scroll a stack, reformat it in any plane including oblique, lift a surface out of it in three dimensions, and measure what you find.

Nothing is uploaded. The app has no account, no analytics and no cloud. Images stay on the device they were opened on.

Title sequence · tracer dispersal

Multiplanar reformats

Slice in any plane, including oblique.

A stack of axial images is a volume, so it can be cut any way you like. Scanners are often tilted to clear the orbits or follow a disc space, and a tilted acquisition resliced as though it stood upright is subtly wrong everywhere. voXel reslices along the direction cosines the file actually carries.

Below is the sample study itself, at 64 × 64 × 60, resliced in your browser by the same arithmetic the app uses.

Axial · slice 31 of 60

firstthrough the volumelast
  • Volume64 × 64 × 60
  • In-plane spacing2.40 mm
  • Slice thickness1.50 mm
  • WindowL 40 · W 400
  • Sourcesynthetic phantom

Why the spacing matters. These voxels are 2.4 mm across and 1.5 mm deep, so a coronal cut of this volume is not square. Drawing it as though it were would stretch the patient. Each reformat here is scaled by the real spacing, which is the whole reason geometry is read from the file rather than assumed.

Three dimensions

A surface you can print.

Pick a tissue by threshold and the surface is extracted with marching tetrahedra, then exported as binary STL or Wavefront OBJ through the share sheet.

  1. 1Threshold. Four presets, in Hounsfield units: bone at 300, soft tissue at 50, skin at −300, lung at −700. Or set your own anywhere in the range.
  2. 2Trim. Tap a piece to drop it, lasso a region freehand, or crop to a box. The box is cut into the field rather than the mesh, so the surface closes itself.
  3. 3Export. STL or OBJ out through the share sheet, into whatever slicer or printer software you already use.
Detail

Three resolutions

Quarter, half and full. On a skull at bone threshold those take roughly 0.6 s, 2.8 s and 19.5 s, producing STL files of about 24 MB, 110 MB and 476 MB. Start at quarter.

Closed surfaces

Watertight, when it can be

Cropping keeps the model closed, because the box is applied to the field before the surface is found. A freehand lasso cuts an arbitrary curve and leaves an open edge, deliberately, and the app says so rather than pretending otherwise.

Verified

Checked against a twin

The extractor was written in Python first and proved there, then mirrored into Swift. Both are held to the same triangle counts, the same winding, and a closed surface's Euler characteristic.

On the processor

No GPU compute

Extraction is plain Swift on the CPU, not a Metal kernel. That is why full resolution takes twenty seconds rather than being instant, and why the timings above are worth printing instead of a claim about speed.

The first thing you do to a CT

Windowing, on a real volume.

A CT slice holds far more range than any screen can show, so you choose which part of it to look at. Take a preset, drag the controls, and probe the image for the attenuation underneath. This is the phantom the app ships to App Review, windowed here with the same linear transform the viewer uses on device.

voXel sample phantom
CT · slice 31 of 61
128 × 128 · synthetic
L 40 HU
W 400 HU
Soft tissue
Drag or arrow-key to probe

1.2 mm pixels · stored 12-bit · rescale 1.0 / −1024 · −1000 to 1200 HU · no patient data

−1000 air0 water+1000 bone
10 near-binary15003000 everything

Why it matters. A CT stores about 4,000 distinguishable values and a screen shows 256 grey levels, so roughly fifteen values collapse into every shade you can see. Choosing the window is choosing which fifteen you care about, which is why one image can never show lung and bone properly at the same time.

Everything it does

The whole feature list.

No asterisks and nothing marked coming soon. If it is on this page it is in the build, and every number here is the one the code actually uses.

Reading

Window and level

  • Drag to window, or take one of ten presets: soft tissue 40/400, lung −600/1500, bone 400/1800, brain 40/80, subdural 60/200, stroke 35/30, liver 60/150, mediastinum 50/350, angio 150/600, spine 50/250
  • Presets filter themselves to the modality in front of you
  • Type an exact centre and width when no preset will do
  • The window stored in the file is honoured, including its VOI LUT function
  • MONOCHROME1 studies invert, as they should
Navigation

Moving through a study

  • Scroll the stack by drag, trackpad or hardware keyboard
  • Cine playback at an adjustable frame rate
  • Zoom, pan, rotate in ninety-degree steps, and mirror
  • A magnifier that sits clear of your hand
  • One, two or four panels, scrolling together when the series share geometry
Reformats

Multiplanar

  • Axial, coronal and sagittal from any stack
  • Oblique planes, rotated freely
  • Thick slab as mean, MaxIP or MinIP
  • A linked crosshair: tap on one plane and the other two follow
  • Gantry tilt taken from the direction cosines rather than assumed away
Three dimensions

Surfaces

  • Isosurface by marching tetrahedra
  • Four thresholds: bone 300, soft tissue 50, skin −300, lung −700, or one of your own
  • Quarter, half and full detail
  • Trim by tapping a piece, lassoing freehand, or cropping to a box
  • Rotate, zoom and pan the result
Measurement

Eight kinds of mark

  • Distance, angle and Cobb angle
  • Area by ellipse, with the statistics inside it
  • Probe for the value at a single point
  • Arrow, label and freehand for pointing things out
  • Kept in the patient's own frame of reference, so a mark drawn on one reformat stays where it belongs when the plane changes
  • A list of every mark on the study, saying which series each came from
In and out

Getting studies across

  • Open a folder, ZIP, RAR or DICOMDIR from Files
  • Send from a desktop browser over your own network, with nothing installed at the other end
  • Export an image as PNG, JPEG or PDF
  • Export a stack as an animated GIF
  • Export a surface as binary STL or Wavefront OBJ
Encodings

What it can read

  • Explicit and implicit VR little endian, uncompressed
  • Lossless JPEG and RLE, both written from scratch in Swift
  • PALETTE COLOR resolved through its lookup tables
  • YBR_FULL and YBR_FULL_422 converted to RGB
  • Multi-frame studies, and frames split across fragments
  • Anything else is refused by name, never approximated
Inspection

Looking underneath

  • A DICOM tag inspector for the file in front of you
  • A diagnostics screen that runs the whole suite on the device and shares the report
  • A performance readout timing each stage of a slice
  • Problem reports that scrub patient names out of file paths before anything is written
Privacy

What leaves

  • No account, no sign-in, no analytics in the app
  • A privacy manifest declaring zero collection, because there is none to declare
  • Patient details hidden from the overlay with one toggle
  • The only networking is inbound, on your own network, behind a pairing code, and only while the import sheet is open

Scope

The limits, before the feature list.

A viewer is only worth trusting if it is honest about what it is not, so that comes first rather than in a footnote.

What it is for

  • Reference and review of studies you already have access to
  • Teaching — handing an iPad to a trainee with no login and no portal
  • Showing someone their own scan, in planes they can follow
  • Measurement of distance, angle and Cobb angle, kept in the patient's own frame of reference
  • Models lifted out of a volume and exported for printing

What it is not for

  • Primary diagnostic interpretation. An iPad panel is not calibrated to the DICOM Part 14 grayscale standard, and no software can make it so
  • Reporting. It writes no report and signs nothing
  • Being a PACS. It does not query or retrieve, and stores nothing centrally
  • Any decision that turns on a grey. If the call depends on the display, make it at a workstation

On the network, precisely. The voXel app has no account, no analytics and no cloud service behind it. It does contain one piece of networking, and it is worth naming rather than hiding: a small web server that runs only while the import sheet is open, listens on a port the system picks, answers nothing without the pairing code shown on screen, and exists so a study can be sent from a desktop browser with no cable and nothing installed at the other end. It receives. There is no path that sends an image anywhere.

Engineering method

Written on the device it runs on.

voXel is built in Swift Playgrounds, on an iPad, with no compiler on the machine the code is written on. That constraint shaped everything: each non-trivial algorithm is written twice, once in Python as a reference and once in Swift, and the two are held to the same numbers. The suite runs on the device, because that is the only place the code has ever been compiled.

Checks on device
1190
all passing, every release
Public corpus read
91.7%
of 1,840 real objects
Releases
80
each one written down
Servers involved
0
nothing to talk to
The corpus decides

What to build next is measured, not guessed

A harness runs the reference parser over thousands of real studies and reports exactly what would fail and why, naming no file and no patient. One run found a fifth of a public archive failing on a single wrong assumption about sequence lengths. Another turned fourteen apparent decoder crashes into one reassembly bug.

Nothing silent

A wrong image is worse than no image

A palette read as intensity still looks like a plausible study. A colour space converted wrongly still fills the screen. Those are the failures worth testing hardest, so the checks pin actual colours and exact pixel values rather than shapes. An encoding it cannot read is refused by name.