Browser-based colour characterisation data explorer and comparator
CharData is a browser-based tool for exploring and comparing colour characterisation datasets and ICC profiles. It runs entirely in your browser with no installation required — all data stays local to the browser, with no upload to any server — and works on both desktop and mobile. CharData pairs with profiletool, a companion in-browser ICC profile inspector and editor: when an ICC profile slot is open, the Launch editor button hands the loaded profile directly to profiletool in a new tab for header / tag inspection or full editing — same browser session, no upload.
A characterisation dataset typically associates device ink percentages (CYAN, MAGENTA, YELLOW, BLACK, and any additional colorants) with measured L*a*b* colorimetry and, optionally, spectral reflectance. CharData accepts these files in CGATS/IT8 and CSV formats. CharData also accepts ICC profiles (output, input, and display classes) and treats them as virtual datasets evaluated through their A2B (device-to-Lab) transform.
What you can do with CharData:
The suggested workflow is to load an entire directory of characterisation files via the File Select panel, then pick individual files to explore or compare.
CharData accepts CSV and CGATS/IT8 text files. CGATS is also published as ISO 28178 — these are the same format.
Every file must contain L*a*b* columns and at least one device colorant column:
| Column | Description |
|---|---|
LAB_L | CIE L* |
LAB_A | CIE a* |
LAB_B | CIE b* |
| (colorant) | At least one device colorant column (e.g. CYAN, 7CLR_1) |
Files with spectral data but no pre-computed LAB columns are also accepted — CharData computes L*a*b* from the spectral data automatically (see Settings — Spectral → LAB).
Any column that does not match a known non-colorant pattern is treated as a device colorant. The following are excluded from colorant detection:
| Pattern | Examples |
|---|---|
LAB_* | LAB_L, LAB_A, LAB_B |
| Spectral wavelength columns | NM380, 380_NM, SPECTRAL_NM380 |
SAMPLE* | SampleID, SAMPLE_NAME |
XYZ_* | XYZ_X, XYZ_Y, XYZ_Z |
D_* | D_RED, D_GREEN |
DENSITY* | DENSITY_V |
STATUS_* | STATUS_T |
COLOR_NAME, COLOR_INDEX |
Everything else — CYAN, MAGENTA, 7CLR_1, ORANGE, etc. — is classified as a device colorant.
If all colorant values in the file are in the range \[0, 1\], they are automatically scaled ×100 to the \[0, 100\] range on load.
The following column names are automatically remapped on load:
| File column | Treated as |
|---|---|
CMYK_C | CYAN |
CMYK_M | MAGENTA |
CMYK_Y | YELLOW |
CMYK_K | BLACK |
If the file contains spectral reflectance columns (named NMxxx, NM_xxx, or SPECTRAL_NMxxx, where xxx is the wavelength in nm), CharData can compute L*a*b* from the spectral data instead of using the file's pre-computed LAB values. See Settings — Spectral → LAB.
CharData also accepts ICC profiles (.icc, .icm). A file is recognised as an ICC profile by checking for the acsp signature at byte offset 36 of the binary header — files that don't carry that magic are rejected.
| Supported | Notes |
|---|---|
| Output / Input / Display class | Other classes (link, abstract, etc.) are rejected |
| CMYK, CMY, RGB, GRAY device color spaces | Other spaces are rejected |
| All four ICC rendering intents | Only those actually present in the profile are selectable; unsupported intents are greyed out |
When a profile loads, CharData treats it as a virtual dataset evaluated on demand through the profile's A2B (device-to-Lab) transform at the chosen rendering intent. CMYK profiles are pre-evaluated against the standard IT8.7/5 patch set so that 3D scatter clouds and ΔE comparisons against another dataset are immediate.
Files (datasets and profiles) load through the File Select panel on the left edge of the screen.
The panel is split into three collapsible sections:
| Section | Contains |
|---|---|
| Standard datasets | Built-in industry reference datasets (FOGRA, IFRA, APTEC, ISO 15339 / CRPC, EUROSB, JapanColor) shipped with the app. Click any entry to load it as if it were a local file, or drag an entry directly onto Dataset A or Dataset B. Once loaded it also appears in the Characterization data section below. Defaults to collapsed. |
| Characterization data | CSV and CGATS/IT8 files (your own or loaded from Standard datasets) |
| ICC Profiles | .icc / .icm binary profiles |
Click a section header (▾) to collapse or expand that section; the state persists between sessions. The button at the top loads files of either kind — CharData detects each file's type and routes it into the correct section automatically.
postMessage, no upload involved.Once a file loads, the slot panel shows:
| Type | Information shown |
|---|---|
| CSV | File name, type CSV, row count, validation, device colorants, spectral status |
| CGATS / ISO 28178 | File name, type Characterization dataset, row count, validation, device colorants, spectral status |
| ICC profile | File name, type ICC Profile, color space + colorants, Rendering intent dropdown |
Row counts, CGATS header warnings, and the "Colorimetric only" message are not shown for ICC profiles — they don't apply.
If a CSV/CGATS file is missing required columns (LAB or any device colorant), it is rejected with a specific error message. The G7 report additionally requires CMYK colorants. ICC profiles that fail header validation, or whose device class or color space is unsupported, are rejected with a matching message.
CGATS or ISO28178, a warning is shown but the file is still loaded and processed normally.
When a slot holds an ICC profile, the slot panel shows a Rendering intent dropdown directly below its colorants line. The default is Absolute Colorimetric (or the first intent the profile supports if Absolute is absent). Intents not encoded in the profile are greyed out.
Changing the intent immediately recomputes:
The Rendering intent control is only visible when the slot holds an ICC profile.
Open Settings by clicking the ⚙ button on the right edge of the screen (or the gear icon on mobile). The Settings panel slides over the content without resizing it. A ? help button sits directly below ⚙ and opens this help page in a new tab.
Selects the colour difference formula used throughout the app.
| Option | Description |
|---|---|
| ΔEab | CIE 1976 — simplest, less perceptually uniform |
| ΔE94 | CIE 1994 — weighted by chroma |
| ΔE00 | CIE 2000 — most perceptually uniform, industry standard |
The selection is remembered between sessions. Changing the method immediately updates the Compare table and the Estimate fit statistics (without refitting the model).
When Yes, rows with identical device colorant values are collapsed into a single row, with L*a*b* values averaged. Useful when a test chart contains repeated patches.
The row count shown in the dataset panel reflects the deduplicated count.
Controls how L*a*b* is derived when spectral columns are present. These settings have no effect on files without spectral data.
| Setting | Options |
|---|---|
| Illuminant | D50 (default), D65 |
| Standard Observer | 2° (default), 10° |
| M-Condition | M0 (default), M1 (forces D50), M2 (UV cut) |
Changing any of these settings immediately reprocesses all loaded spectral files.
Controls how the polynomial model in the Estimate section is fitted to the dataset.
| Option | Description |
|---|---|
| Weighted: Off | Ordinary least-squares — all patches contribute equally to the fit |
| Weighted: On | Iteratively reweighted least-squares — patches with large residuals are progressively down-weighted, making the model more robust to outlier patches |
Switches the app between Light, Dark, and System (follows OS preference) themes.
Overrides the interface language. System default detects the browser locale and selects the closest supported language automatically. Available languages: English, Français, Deutsch, Italiano, Español, Português (PT), Português (BR), 中文(简体), 中文(繁體), 日本語, 한국어.
Explore mode works with a single slot (A) holding either a characterization dataset or an ICC profile. Select it with the Explore button at the top.
When the slot holds an ICC profile, Explore shows a profile summary panel (color space, device class, available rendering intents, colorant list) and — for CMYK profiles — an optional table of the profile's IT8.7/5 patch evaluations at the current rendering intent.
Click Display File in the Dataset A panel to open a sortable table of all rows.
The G7 section (below Data Table) analyses the dataset against the IDEAlliance G7 System ADS target patch values (P2P chart, Appendix A). It requires CMYK colorants plus LAB.
The report shows measured vs target L*a*b* for key patches (paper white, K solids, CMY solids, and tonal ramps), plus ΔE for each.
Displays the dataset's colour gamut in CIE L*a*b* space.
The main control panel (above the plot) contains global settings. Each dataset also has its own gear icon (⚙) in the plot legend for per-slot overrides.
| Control | Description |
|---|---|
| Show gamut shell | Renders an alphahull mesh enclosing the gamut surface |
| Show data points | Shows individual scatter points |
| Color by hue angle | Colours points/shell vertices by hue angle |
| Color by value | Colours points/shell vertices by L* (lightness) |
| Shell opacity | Slider for shell transparency |
| Show spectral data when point selected | Enables spectral reflectance popup on click |
When both global and per-slot checkboxes are visible, the global checkbox shows an indeterminate state when the two slots differ. Clicking the global checkbox sets both slots to the same state.
Defaults differ by file type. When a characterization dataset loads, the slot defaults to gamut shell off, data points on. When an ICC profile loads, the slot defaults to gamut shell on, data points off — profiles encode a continuous transform rather than a sample cloud, so the shell is the more meaningful representation. You can override either default with the per-slot checkboxes.
If the dataset has spectral columns and Show spectral data when point selected is enabled, clicking a data point opens a popup showing the spectral reflectance curve for that patch.
Click any legend item to toggle that trace on/off. Hover for the tooltip.
Below the 3D plot, the Gamut Slice (2D) section shows a cross-section of the gamut.
| Control | Description |
|---|---|
| Axis | Which axis to slice along: L*, a*, or b* |
| Value | Position of the slice along the chosen axis (0–100) |
| Thickness | Half-width of the projection window along the chosen axis (0–128). Points whose axis value lies within ±Thickness of Value are orthogonally projected onto the slice plane |
| Fall-off | Hard — every projected point is drawn at full opacity. Soft — opacity falls linearly from 100 % at Value to 0 % at the window edge. Points within ±0.5 of Value are always at full opacity in either mode |
| Show data points | On by default. Draws each visible dataset's patch cloud (CSV measurements or, for ICC profiles, the sampled patch lattice) projected onto the slice. Points within ±0.5 of Value (in-plane) render as 7 px dots in a 30 %-brightened version of the dataset colour; points farther out render as 3 px dots in the dataset's solid colour |
The slice updates live as you adjust the controls.
The Estimate section maps device colorants → L*a*b* and lets you predict the L*a*b* for any combination of colorant values.
Click Generate model. A blue Computing badge appears in the top-left corner of the screen while the fit runs (it may take a moment for large datasets). The badge also appears during other computationally intensive operations such as rendering the 3D gamut shell. If the fit fails, an error message and Retry button appear.
| Statistic | Description |
|---|---|
| Mean ΔE | Average colour error across all data points |
| Min ΔE | Best-case colour error |
| Max ΔE | Worst-case colour error |
| Std Dev | Spread of the error distribution |
| Points fitted | Number of rows used for the fit |
The model degree is shown next to "Model fit" above the stats.
Below the stats, a table allows you to dial in colorant values:
Click Regenerate to refit the model (e.g. after loading a new dataset). Note: changing the ΔE method in Settings updates the displayed statistics immediately without refitting — only click Regenerate if you want to refit from scratch using the new method's stopping criterion.
The Tone Value section analyses the tonal response of each primary colorant — how the printed tone value relates to the input ink percentage. It appears between the Data Table and Estimate sections.
A collapsible bar below the chart (click ▲ to collapse, ▼ to expand) contains:
| Control | Description |
|---|---|
| Tone Method | Murray-Davies (spectral density) or Colour Tone Value (CTV, ISO 20654) |
| Filter | Status densitometer filter: T, E, I, or A (Murray-Davies only) |
| Graph Type | Transfer — TV (%) vs ink%; or Gain — TV minus ink% |
| Colorant checkboxes | Toggle individual colorant curves on/off |
Murray-Davies computes tone value from spectral reflectance using a simulated densitometer filter. The channel used depends on the colorant:
| Colorant | Filter channel |
|---|---|
| CYAN | Red (R) |
| MAGENTA | Green (G) |
| YELLOW | Blue (B) |
| BLACK and others | Visual (V) |
Paper (lowest ink%) and solid (highest ink%) patches in the primary tone ramp are used as reference points.
Colour Tone Value (CTV) follows ISO 20654 and computes tone value from CIE L* values only. No spectral data is required, but the dataset must contain a primary tone ramp for each colorant.
Transfer — plots tone value (%) on the Y-axis against ink% on the X-axis. Ideal linear response is a straight diagonal from (0,0) to (100,100). Curves above the diagonal indicate dot gain; below indicate dot loss.
Gain — plots TV − ink% (percentage points) on the Y-axis. Zero is ideal linear response; positive values = dot gain; negative = dot loss. By definition gain is always zero at 0% and 100% ink.
The Y-axis range is computed from the data for the current dataset, method, and filter combination, then fixed. In Gain mode the range is determined from interior tone steps only (excluding 0% and 100% endpoints), with padding for readability. The range is recalculated if the dataset, method, or filter changes.
Tone Value requires rows where only a single colorant is non-zero at a time (a primary tone ramp). Murray-Davies additionally requires spectral reflectance columns; if absent the chart prompts you to switch to CTV.
For ICC profile slots, CharData synthesises a primary ramp by evaluating the profile at fixed tint percentages (0, 5, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 95, 100) along each channel with all other channels at zero. Profiles have no spectral data, so only CTV works for ICC slots — Murray-Davies traces are skipped with a "no spectral" indicator. Changing the rendering intent re-samples the profile and re-fits the Y-axis range.
Compare mode loads two slots (A and B) and shows a row-by-row colour difference table. Select it with the Compare button at the top. Each slot can hold either a characterization dataset or an ICC profile; all four combinations are supported (data vs data, data vs ICC, ICC vs data, ICC vs ICC).
Matching depends on what's loaded:
The table shows, for each matched patch:
- ΔE (using the selected method) - ΔL* — lightness difference (L*B − L*A) - ΔC* — chroma difference (C*B − C*A) - ΔH* — geometric hue distance (chroma-weighted, computed via the selected ΔE method) - Δh*(deg) — hue-angle difference, signed shortest-path in (−180°, +180°]
Columns are sortable by clicking the header. The same column set and decimal alignment applies for every Compare combination, including ICC slots.
Above the table, a statistics box shows:
| Statistic | Description |
|---|---|
| Mean ΔE | Average colour difference across all matched patches |
| Min ΔE | Smallest colour difference |
| Max ΔE | Largest colour difference |
| Std Dev | Spread of colour differences |
The compare table includes filter controls to narrow down the rows shown:
The 3D plot in Compare mode shows both slots overlaid in L*a*b* space. Slot A is shown in blue, Slot B in red. All the same controls as Explore mode apply, with per-slot gear panels for independent control of each slot's shell / points / colour mode. Per-slot defaults still apply: ICC slots open with shell on / points off, characterization datasets with shell off / points on. Changing a slot's rendering intent rebuilds its 3D shell and patch cloud immediately.
The Tone Value section also appears in Compare mode, below the Comparison Table. Both slots are plotted on the same chart: Slot A uses solid lines, Slot B uses dashed lines in a slightly darker shade of the same colour.
The controls bar includes two additional checkboxes — Show Dataset A and Show Dataset B — to toggle all curves from either slot at once.
All other controls (Tone Method, Filter, Graph Type, colorant checkboxes) work identically to Explore mode. When either slot is an ICC profile, the chart auto-uses the CTV method for that slot; Murray-Davies traces from the ICC slot are skipped (no spectral data). The Y-axis range invalidates whenever a rendering intent changes so the curves stay correctly framed.
You can load an image and plot its gamut alongside any loaded datasets in either Explore or Compare mode. This is most useful for determining whether the colours used in a photograph or artwork fall inside or outside the gamut of a printing or display process represented by one of the loaded datasets — or, when the image carries an embedded ICC profile (or is a Lab TIFF), for viewing the image's gamut on its own with no dataset loaded at all.
The Image section sits above the 3D plot and is always visible. It works the same way in Explore and Compare; the only difference is that Compare mode adds Dataset B to the bind dropdown.
| Format | Colorimetry source |
|---|---|
| PNG | Embedded iCCP chunk (zlib-decompressed) if present, otherwise channel count (Gray or RGB) |
| JPEG | Embedded ICC profile (APP2 ICC_PROFILE segments) if present, otherwise channel count |
| TIFF | Embedded ICC profile (tag 34675) if present, otherwise channel count; TIFF PhotometricInterpretation 8 / 9 (CIELAB / ICCLab) is auto-detected and treated as Lab |
| BMP | Channel count — RGB (Canvas expands indexed and 16/24/32-bit BMPs to RGB on decode). BMP V5 embedded ICC profiles are not currently read |
| GIF | Channel count — RGB after palette expansion. GIF does not support embedded ICC profiles. Animated GIFs use the first frame only |
Photoshop-generated PDFs only. The first image XObject is extracted; its embedded /ICCBased profile (if any) drives colorimetry just like a JPEG/TIFF embedded ICC, otherwise channel count from /DeviceGray, /DeviceRGB, or /DeviceCMYK |
CMYK JPEGs (both standalone .jpg files and CMYK /DCTDecode streams inside Photoshop PDFs) are decoded via UTIF's bundled JPEG decoder, which handles Adobe APP14 YCCK and raw CMYK. Use TIFF for N-colorant (≥5 channel) images. BMP and GIF are palette/RGB-only formats and cannot represent CMYK or N-colorant data.
PDF support is intentionally narrow: only PDFs whose /Info dictionary's Producer or Creator string begins with Adobe Photoshop are accepted. Generic document PDFs (InDesign, Word, scanned PDFs, etc.) are rejected with a clear error so the gamut path never partially-decodes an unrelated document.
For Photoshop-generated PDFs, the supported pipeline is:
/DCTDecode) or ZIP / Maximum Quality (/FlateDecode with optional PNG-style Predictor in /DecodeParms). Acrobat-6+ JPEG2000 compression is not yet supported./DeviceGray, /DeviceRGB, /DeviceCMYK, and /ICCBased with Gray / RGB / CMYK channel counts./ICCBased colour space, is decoded and treated identically to embedded ICC profiles in JPEG (APP2) or TIFF (tag 34675), including the Embedded: dropdown entry above the 3D plot.The 100 MB file-size cap protects against accidentally loading uncompressed scanner output.
If the image carries an embedded ICC profile (JPEG APP2 / TIFF tag 34675), a first dropdown entry *Embedded: profile name** is added and selected by default. Picking this entry converts the image's device pixels straight through its own embedded profile (A2B, Absolute Colorimetric) to L*a*b* — no dataset binding is involved and no family check applies, since the embedded profile is* the image's colour space.
For non-Lab images, you can also bind to Dataset A (Explore or Compare) or Dataset B (Compare only) from the dropdown. The image's device colorant space must match the bound dataset's colorant family (for example, an RGB image binds only to an RGB dataset; a CMYK image to a CMYK dataset; a 5-colorant TIFF to a 5-colorant CMYKOGV-style dataset). When the binding is valid, the image's device pixels are run through the dataset's estimate model (for characterisation datasets) or the A2B with Absolute Colorimetric rendering intent (for ICC profiles) to derive L*a*b* coordinates.
For Lab images (TIFF with PhotometricInterpretation 8 or 9), the dataset dropdown is greyed out — the image plots in its native L*a*b* coordinates directly with no transformation.
The bind dropdown adapts to what's available:
- so the dropdown still shows the slot positions.When the image carries an embedded ICC profile (or is a Lab TIFF), no dataset is required — the 3D plot and 2D slice appear with the image trace alone. Removing the image (or unloading the dataset, if it was the only data source) hides both sections again.
The image trace is rendered as a point cloud (green by default) in:
It does not appear in the Comparison Table, Tone Value chart, or Explore views.
Before plotting, the loaded image is downsampled to a few hundred to a few thousand representative colour samples in two passes:
1. Spatial averaging to an aspect-preserved grid, so the result is broadly representative of the image's colour distribution rather than dominated by one region. 2. ΔE-radius deduplication to remove near-identical samples, scaled by colorant family.
This keeps the plot responsive on large images and matches the typical density of a characterisation dataset.
The Image detail dropdown (next to Bind image to dataset) selects how aggressively the loaded image is downsampled before plotting. Changing the setting rebins the cached pixels in place — no re-decode of the source file — so the trace updates immediately.
| Setting | Bin grid | Dedupe radius | Typical point cloud |
|---|---|---|---|
| Coarse | ≤30 × 30 cells | 2.0 device units | a few hundred points |
| Standard (default) | ≤45 × 45 cells | 1.0 device unit | up to ~2,000 points |
| Fine | ≤70 × 70 cells | 0.5 device units | up to ~5,000 points |
Coarse renders fastest and is sufficient for checking whether an image's gamut roughly fits a process. Fine surfaces more of the image's colour variety at the cost of a slower 3D plot and a denser cloud that may obscure the gamut shell. The choice is remembered across sessions.
On screens narrower than 700 px:
All features are available on mobile; the layout adapts to the smaller screen.