homeaboutvideotry it nowpricingdocs
Docs

Getting Started

Colour palettes

Fileboy works out the main colours of every image you upload: the dominant colour, up to 16 colours with how much of the image each covers, vibrant and muted swatches, and a text colour that reads well on each. Use them for placeholders while images load, to theme a page around a picture, or to sort and search by colour.

Get the palette of an image

Add the

palette
transform to an image URL. The answer is JSON instead of the image:

1
https://api.fileboy.io/images/get/[:fileboy_id]?transform=palette
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  "version": 1,
  "dominant": { "hex": "#3d5a73", "rgb": [61, 90, 115], "share": 0.4213, "text": "#ffffff", "contrast": 7.22 },
  "colors": [
    { "hex": "#3d5a73", "rgb": [61, 90, 115], "share": 0.4213, "text": "#ffffff", "contrast": 7.22 },
    { "hex": "#e8d9c4", "rgb": [232, 217, 196], "share": 0.2876, "text": "#000000", "contrast": 15.15 },
    { "hex": "#c2452d", "rgb": [194, 69, 45], "share": 0.1102, "text": "#ffffff", "contrast": 5.02 }
  ],
  "swatches": {
    "vibrant": { "hex": "#c2452d", ... },
    "darkVibrant": null,
    "lightVibrant": { "hex": "#e8d9c4", ... },
    "muted": { "hex": "#3d5a73", ... },
    "darkMuted": null,
    "lightMuted": null
  },
  "transparentShare": 0
}
  • dominant
    is the colour that covers the most of the image, or null when nothing in it is visible.
  • colors
    are the main colours, most of the image first.
    share
    is how much of the visible image is that colour, from 0 to 1.
  • swatches
    are the six named swatches of Android's Palette library:
    vibrant
    ,
    darkVibrant
    ,
    lightVibrant
    ,
    muted
    ,
    darkMuted
    and
    lightMuted
    . Any of them is null when no colour in the image fits, and each colour is used for one swatch at most.
  • text
    is
    #000000
    or
    #ffffff
    , whichever contrasts more with the colour, and
    contrast
    is their WCAG 2 contrast ratio. One of the two always reaches at least 4.58:1, so the text colour always meets WCAG AA for normal text (4.5:1).
  • transparentShare
    is how much of the image is transparent, from 0 to 1. Transparent pixels are left out of every share, and half transparent ones count half.

The transform takes these options:

  • palette:json
    (the default) or
    palette:css
    , see below.
  • ~colors:4
    lists 0 to 16 colours (6 if you leave it out). The dominant colour and the swatches are always included, so
    palette~colors:0
    is the smallest answer.
  • ~prefix:hero
    names the CSS custom properties and classes (
    palette
    if you leave it out).

The palette URL follows the image's own read access: a public image's palette is public, and an image that needs a signed URL needs one for its palette too. Sign the palette URL like any transform URL.

Colours of part of an image

On its own,

palette
describes the original image. After other transforms it describes their result, the same way as
format:json
. To get the colours behind a heading at the top of a banner, crop first:

1
?transform=crop:100pcx20pc~position:top;palette~colors:3

Whichever of

format
and
palette
comes last decides what the response is, so
palette;format:webp
is an image. Transformed palettes are cached like transformed images.

CSS output

palette:css
answers with a stylesheet: a custom property for each colour and its text colour, and classes that use them.
-bg-
classes set the background and a readable text colour,
-fg-
classes set the text colour. Swatches the image does not have are left out.

1
<link rel="stylesheet" href="https://api.fileboy.io/images/get/[:fileboy_id]?transform=palette:css~prefix:hero">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* Fileboy colour palette, version 1 */
:root {
  --hero-dominant: #3d5a73;
  --hero-dominant-text: #ffffff;
  --hero-1: #3d5a73;
  --hero-1-text: #ffffff;
  --hero-2: #e8d9c4;
  --hero-2-text: #000000;
  --hero-vibrant: #c2452d;
  --hero-vibrant-text: #ffffff;
  ...
}
.hero-bg-dominant { background-color: #3d5a73; color: #ffffff; }
.hero-fg-dominant { color: #3d5a73; }
.hero-bg-1 { background-color: #3d5a73; color: #ffffff; }
...

From your server

The management API returns the same palette with your private key, at

GET /files/[:id]/palette
(with
?colors=
from 0 to 16). Every SDK has a method for it:

// needs the private key
const palette = await fileboy.getFilePalette(fileId, { colors: 4 })
palette.dominant?.hex // "#2f5d8a"
palette.colors.map(c => [c.hex, c.share]) // most of the image first
palette.swatches.vibrant?.text // "#ffffff" or "#000000", whichever reads better

File lists from

GET /files
include each image's
dominantColor
(null for files that are not images, and for older images until their palette has been worked out), so you can store it with your own records or render placeholders for a whole gallery from one call.

Placeholders while images load

Show the dominant colour where the image will be, so the page does not flash white. The React

Image
component does it with
placeholderColor
, and takes the colour away once the image has loaded so it never shows through transparent parts:

1
2
3
4
5
// best: the dominantColor you stored or listed on your server, shown at once
<Image id={file.id} placeholderColor={file.dominantColor ?? undefined} />

// or let it fetch the palette (a small JSON request) before the image arrives
<Image id={file.id} placeholderColor="auto" />

Anywhere else, a background colour on the

img
does the same job:
<img src="..." style="background:#3d5a73">
.

How the colours are picked

  • Large images are sampled on an even grid of about 16,000 pixels (real pixels, never blended, so a red and blue picture has no purple), so the cost is the same for a 1 and a 60 megapixel photo.
  • The pixels are grouped with median cut, then refined with k-means measured in CIELAB, so that colours that look alike are grouped together. Colours that look almost the same are merged into the more common one.
  • Nothing is random: the same image always gives the same palette. When the method changes,
    version
    goes up and stored palettes are worked out again the next time they are asked for.
  • The named swatches use the saturation and lightness targets of Android's Palette library, as Sanity and imgix do.

When it is worked out

The palette is worked out when a JPEG, PNG, WebP, BMP or TIFF image is uploaded and stored with it, so asking for it later does not read the image again. Images uploaded before palettes existed are worked out the first time their palette is asked for, then stored. The dashboard shows it on each image's Metadata tab.

GIF, SVG, HEIC and other files are answered with a 422 and the error
unsupported_image
. A transform written wrongly, such as
palette~colors:20
, is answered with a 400.

Colour palettes

Get the palette of an imageColours of part of an imageCSS outputFrom your serverPlaceholders while images loadHow the colours are pickedWhen it is worked out
hello@fileboy.io

Fileboy

HomeAboutPricingChangelog
© Copyright 2026, CD2 Solutions Ltd.
Terms and ConditionsPrivacy Policy