Skip to main content
Auric Artisan · Documentation

Image Color Picker Developer Reference

Technical map for Image Color Picker: the page shell, canvas sampling runtime, K-means++ palette extraction, color metric helpers, chart renderers, export surfaces, state API and Library integration.

Published: May 25, 2026 Updated: May 25, 2026 Category: Reference Author: Chirag Bansal
Back to Documentation Auric Artisan Home

Overview

Technical map for Image Color Picker: the page shell, canvas sampling runtime, K-means++ palette extraction, color metric helpers, chart renderers, export surfaces, state API and Library integration.

Table of contents

  1. 1. Code map
  2. 2. Page shell and UI contract
  3. 3. Runtime state
  4. 4. Image loading and canvas sampling
  5. 5. Color math helpers
  6. 6. Palette extraction pipeline
  7. 7. Rendering and charts
  8. 8. Exports, batch analysis and shortcuts
  9. 9. Public API and restore contract
  10. 10. Library binding
  11. 11. Testing checklist

1. Code map

+
File Role
tool/general/tools/image-picker/index.html SEO shell, route markup, hero, tabs, upload controls, result panels, action panels, canvases and fullscreen chart overlay.
js/tool/image-picker.js Self-contained runtime for image loading, canvas sampling, palette extraction, rendering, exports, batch analysis, keyboard shortcuts and state API.
js/common/tool-gates.js Has no gate for /tool/general/tools/image-picker/: its note lists Image Color Picker among the tools that open and run free on every tier.
js/library/tool-bindings.js Registers Image Color Picker as a Library palette tool and connects shared state capture through window.AAImagePicker.
js/generated-inline/644c56b21472624ee959.js Generated helper for fullscreen chart behavior used by the canvas chart wrappers.
js/generated-inline/771583026d107068e662.js Shared generated bootstrap used across documentation and tool pages.

The runtime is an IIFE. It does not import modules and does not send image data to a server. Any remote image URL is loaded by the browser image element and then sampled only if canvas security allows getImageData.

2. Page shell and UI contract

+

The route exposes ipl-app as the application root and uses three tab panels: p-ipl-lab (Workbench), p-ipl-analysis (Analysis) and p-ipl-actions (Actions). There is no quick-start guide; until an image loads, the right rail (ipl-readout-empty) shows the keyboard map.

Area Primary IDs
Source loading ipl-drop-zone, ipl-file-input, ipl-url-input, ipl-url-btn, ipl-file-name, ipl-img-meta
Extraction controls ipl-clusters-slider, ipl-quality-slider, ipl-merge-slider, ipl-ignore-dark, ipl-ignore-light, ipl-btn-extract, ipl-btn-reset
Eyedropper ipl-picker-swatch, ipl-picker-text, ipl-picker-meta, ipl-picker-add, ipl-picked-count, ipl-picked-strip
Palette output ipl-empty-state, ipl-lab-content, ipl-canvas, ipl-palette-swatches, ipl-tone-shadows, ipl-tone-midtones, ipl-tone-highlights, ipl-wcag-pairs, ipl-harmony-host
Charts ipl-hist-canvas, ipl-dist-canvas, ipl-hsl-canvas, ipl-lum-canvas, ipl-chart-fs-overlay, ipl-chart-fs-title, ipl-chart-fs-close, ipl-chart-fs-canvas
Actions ipl-btn-copy-hex, ipl-btn-copy-css, ipl-btn-copy-json, ipl-btn-copy-link, ipl-btn-download-json, ipl-btn-download-svg, ipl-btn-download-csv, ipl-batch-input, ipl-btn-batch, ipl-batch-results

The runtime also maps ipl-btn-compare and ipl-compare-results if a comparison surface is present. The current shell tracks history but does not render those two comparison IDs in the visible Actions markup.

3. Runtime state

+

The central STATE object stores image, palette, eyedropper and settings data:

{
  imageLoaded: false,
  imageInfo: null,
  imageData: null,
  palette: [],
  picks: [],
  liveColor: null,
  sampleCount: 0,
  clusterCount: 6,
  quality: 3,
  mergeThreshold: 25,
  ignoreDark: false,
  ignoreLight: false,
  history: []
}
  • imageInfo stores original width, original height, canvas width, canvas height and source label.
  • imageData stores the sampled canvas pixels returned by getImageData.
  • palette entries contain r, g, b, hex, count and fraction.
  • picks entries contain exact pinned RGB and HEX values.
  • history stores extraction snapshots with label, palette and timestamp for comparison workflows.

4. Image loading and canvas sampling

+

loadFile(file) validates file.type.startsWith("image/"), creates an object URL, decodes an Image and revokes the object URL after drawImageToCanvas. loadUrl(url) creates an image with crossOrigin = "anonymous" and asks the browser to load the URL directly.

drawImageToCanvas(img, label) scales the image to a maximum working canvas of 800 by 500 pixels, draws the decoded image and then calls getImageData. If the canvas is tainted by CORS, sampling fails and the user sees the local-upload fallback message.

Pointer sampling uses getBoundingClientRect() to map viewport coordinates to canvas pixels. The sampled byte index is (y * canvasWidth + x) * 4. Pinned colors ignore pixels with alpha below 16.

5. Color math helpers

+

The file implements the color conversions required for extraction, analysis and export:

  • rgbToHex and hexToRgb for palette and batch I/O.
  • rgbToHsl and hslToRgb for hue, saturation and lightness output.
  • srgbToLin, linToSrgb and rgbToXyz for linearized sRGB to XYZ conversion.
  • xyzToLab and rgbToLab with a D65 white point.
  • labToLch for cylindrical Lab output.
  • deltaE00 for CIEDE2000 palette comparison.
  • relLum, contrastRatio, bestTextColor and wcagLevel for accessibility summaries.

Lab and LCH values are practical browser-side metrics for comparing palette colors. They should be treated as computed analysis values from sRGB source pixels, not as device-profile-aware color-managed measurements.

6. Palette extraction pipeline

+

computePalette() is the main extraction pipeline. It reads STATE.imageData, chooses a sampling step from QUALITY_STEP, spreads samples across the full image and caps the estimated grid through MAX_SAMPLES = 50000.

  1. Loop through canvas pixels on the calculated sample grid.
  2. Skip nearly transparent pixels.
  3. Optionally skip near-black or near-white pixels using WCAG relative luminance.
  4. Record sampled RGB values in a flat Float32Array and exact HEX counts.
  5. If exact unique sampled colors are no more than the requested clusters, use exact colors.
  6. Otherwise run kmeanspp(samples, n, clusterCount, 20).
  7. Apply mergeClusters(clusters, mergeThreshold).
  8. Sort clusters by population count and compute fraction.
  9. Push a snapshot into STATE.history and render results.

This exact-color fallback matters for logos, icons, UI screenshots and flat illustrations. It prevents K-means from inventing averaged colors when the image already has a small set of real discrete colors.

7. Rendering and charts

+

renderPalette() coordinates the result UI. It toggles empty/content states, writes palette and sample counts, renders swatches, builds tone bands, computes WCAG pairs, renders harmony rows and draws the four charts once the Analysis tab is visible.

  • drawHistogram renders cluster population bars.
  • drawDistribution renders the color distribution donut.
  • drawHslScatter plots hue against saturation.
  • drawLuminanceBars renders sorted WCAG relative luminance values.

prepCanvas(id) handles device pixel ratio scaling and canvas setup. The chartColors() helper returns fixed grid, label and stroke colors for the workbench, which is dark in both themes. Resize handling redraws charts after a short debounce.

Tone bands are created by classifyTone(L). Harmony rows come from analyseHarmony(palette), which looks for approximate hue relationships such as complementary, analogous, triadic, split-complementary and tetradic matches.

8. Exports, batch analysis and shortcuts

+

Export helpers build data from the current runtime state and use a shared downloadBlob(data, name, mime) helper for file downloads.

  • getPaletteHexes() returns extracted palette HEX values.
  • getCSSVars() writes a :root block using --palette-01 style variables.
  • getJSON() includes image info, settings, sample count, RGB, HSL, Lab, LCH, luminance, population, count, pins and export timestamp.
  • getSVGPalette() creates a simple labeled SVG palette strip.
  • exportCSV() writes rows with index, HEX, RGB, HSL, luminance, population and count.

runBatchAnalysis() reads ipl-batch-input, tokenizes hex colors by newline, comma, semicolon or whitespace and renders a table with RGB, HSL, Lab, LCH, luminance and tone classification.

Keyboard shortcuts are registered globally but ignored when focus is inside inputs, textareas or selects. Supported keys are J for JSON, H for HEX, R for reset and E for re-extract.

9. Public API and restore contract

+

The tool exposes window.AAImagePicker for Library and integration workflows:

window.AAImagePicker = {
  getState: function () {
    return {
      imageInfo: STATE.imageInfo,
      palette: STATE.palette.slice(),
      picks: STATE.picks.slice(),
      sampleCount: STATE.sampleCount,
      settings: {
        clusterCount: STATE.clusterCount,
        quality: STATE.quality,
        mergeThreshold: STATE.mergeThreshold,
        ignoreDark: STATE.ignoreDark,
        ignoreLight: STATE.ignoreLight
      },
      history: STATE.history.slice(-8)
    };
  },
  restoreState: function (saved) { ... }
};

restoreState(saved) restores settings, image info, palette, picks, sample count and recent history, updates slider and checkbox controls, updates visible setting labels, rerenders palette and pins, and clears the live eyedropper preview. It does not restore raw ImageData; source images must be reloaded before canvas sampling can continue.

10. Library binding

+

The Library binding registers the route as a palette-producing creative tool:

{
  id: "image-picker",
  name: "Image Color Picker",
  href: "/tool/general/tools/image-picker/",
  category: "Creative",
  asset_type: "palette"
}
  • Shared state: the global capture map stores imagePicker: window.AAImagePicker?.getState.
  • Shared restore: the restore hook maps imagePicker payloads to window.AAImagePicker?.restoreState.
  • Palette asset: capture reads window.AAImagePicker.getState() and stores the unique HEX values of the palette and the pins under asset_data.colors, with the image's file name as source_label. With nothing extracted yet it saves an Image Color Picker settings preset instead.
  • Restore: a save made in the picker comes back through the runtime-state pass. A palette or color saved elsewhere (the binding accepts palette and color assets) is passed to AAImagePicker.restoreState() as the palette, each color an equal share because there is no image behind it; 3- and 8-digit HEX values are normalized to 6.
  • Source images: large image pixels are not stored. If the payload includes a source image reference, restore messaging asks the user to reload it for further picking.

Implementation note: capture reads AAImagePicker.getState() rather than DOM IDs, so changes to the ipl- markup do not affect it. Keep the shape of getState() stable instead.

11. Testing checklist

+
  • Open /tool/general/tools/image-picker/ and verify it opens with no plan gate.
  • Load PNG, JPEG, WebP and at least one transparent image through file upload.
  • Load a remote image URL that permits CORS and one that blocks CORS, then verify messaging.
  • Change cluster count, quality, merge threshold, Ignore dark and Ignore light; confirm extraction reruns and sample counts update.
  • Hover canvas pixels and verify HEX, RGB, HSL, luminance and pixel coordinates.
  • Pin colors, avoid duplicate pins and click swatches to copy HEX.
  • Verify palette swatches, tone bands, WCAG pairs and harmony output for photo and flat art images.
  • Check all four canvases in light and dark mode and after window resize.
  • Copy HEX, CSS and JSON; download JSON, SVG and CSV.
  • Run batch analysis with newline, comma, semicolon and space separated hex colors.
  • Test keyboard shortcuts J, H, R and E outside focused form controls.
  • Save to Library and restore a palette through AAImagePicker.restoreState().
  • If exposing palette comparison in the UI, add ipl-btn-compare and ipl-compare-results, then load two or more images and run the comparison matrix.
  • Regenerate documentation RSS, feed, sitemap, PWA cache manifest and search index after docs changes.

For user-facing workflow details, see the Image Picker User Guide.