PaletteFromImage
a palette built by clustering a bundled photograph's pixels, a woman before a wall of marigolds, most-used color first
- Run
swift run --package-path Examples Example-Color-PaletteFromImage- Imports
OllinSamplePhotos- Source
- Examples/Color/PaletteFromImage/Sketch.swift
import Ollin
import OllinSamplePhotos
/// Pulling a palette out of a photograph. `extractPalette(from:)` clusters an
/// image's pixels in a perceptual space and hands back the colors it is mostly
/// made of, most-used first.
///
/// The picture is one of the bundled sample photographs, a woman before a wall
/// of cempasúchil, the marigolds of Día de Muertos: one saturated orange over
/// most of the frame, a pink blouse, gray hair, and the greens of the stems.
/// The wide row is what the extraction found. The first swatch is the color the
/// picture is most made of, so the marigolds come first however many colors are
/// asked for.
///
/// The count cycles. Asking for fewer colors than the picture holds makes the
/// clustering merge the nearest ones rather than drop them, which is why the
/// pink and the gray survive down to three and fold into the orange at two.
@main
final class PaletteFromImage: Sketch {
var photograph = Image(width: 1, height: 1)
var extracted: [Palette] = [] // one per count, so `draw()` never clusters
override func setup() {
noStroke()
photograph = SamplePhoto.marigolds.load()
// Clustering is setup-time work. Extract once per count we might show.
extracted = (1...8).map { extractPalette(from: photograph, count: $0) }
}
override func draw() {
background(Color(hex: 0x101014))
// Cycle through the counts, holding each for a beat.
let count = 2 + Int(time * 0.5) % 7
let palette = extracted[count - 1]
let side = width - 180.0
let frame = Rectangle(x: 90, y: 80, width: side, height: side * 0.66)
drawImage(photograph, in: frame, fit: .cover)
// What the extraction found, in order: the first swatch is the color
// the picture is most made of.
let barY = frame.y + frame.height + 44
let step = side / Double(palette.count)
for (i, color) in palette.enumerated() {
fill(color)
drawRect(90 + Double(i) * step, barY, step, 130, cornerRadius: 4)
}
drawCaption("\(count) colors extracted from the photograph, most used first")
}
}