Creative Problem Solver. Programmer. Bodysurfing. Sometime Comics.
Blogger since 2001.

own yr www rn! #IndieWeb

Extracting CSS Colors from Screenshots of Web Pages

I’ve talked a lot about the headers on this site over the years. It’s one of my favorite long-term projects. One thing that I’ve considered over the years is making associated styling for the footer of the site or other parts based on colors in them.

Try 1: parse HTML for colors

The first thing I did was write code to parse the HTML for the headers and seek out colors. It wasn’t bad code, and I was able to find colors in whatever format, keywords like ‘blue’ or ‘black’ or ‘white’ and parse rgba() and rub() and find them in all kinds of inline style attributes. All fine and good.

Try 1, Part 2: parse images for colors

So I began to write code to capture each image locally and parse each image for colors and see what the results are. Weirdly straightforward to write code that reads the image into a GD object and run over every pixel.

$im = imagecreatefrompng($directory . '/' . $file);
// blur the image
// save the image
$uniqueColorsAndCount = [];
for ($x = 0; $x < imagesx($im); $x++) {
	for ($y = 0; $y < imagesy($im); $y++) {
		$rgb = imagecolorat($im, $x, $y);
		$r = ($rgb >> 16) & 0xFF;
		$g = ($rgb >> 8) & 0xFF;
		$b = $rgb & 0xFF;
		$hex = sprintf("#%02x%02x%02x", $r, $g, $b);
		if (in_array($hex, $ignoreColors)) {
			continue;
		}
		if (!in_array($hex, $ignoreColors)) {
			if (!array_key_exists($hex, $uniqueColorsAndCount)) {
				$uniqueColorsAndCount[$hex] = 1;
			} else {
				$uniqueColorsAndCount[$hex]++;
			}
		}
	}
}

And doing this for each image definitely gave me results which seemed like valid answers and some ok colors.

But also the images live on backgrounds, and just because a a color appears in a css gradient doesn’t mean it’s significant and some of the colors were essentially black. Pixel count is not significance.

Realization A: Significant Colors are not in the code or images, they’re part of the whole

I got frustrated. I was doing all this work to interpret the HTML and component images and what I wanted was to look at the totality of the way the headers look. So I went looking for other solutions for this problem. And immediately found a great library in PHP I could install with composer. And here was the question Detect main colors in an image with PHP. The PHP League’s Color Extractor library looked great, and I could run it on my header screenshots previously grabbed with the excellent shot scraper library.

Try 2: Use Color Extractor

Trying some examples with that library the colors it chose were far more representative of the overall. I ran it on a few screenshots and I liked the variety of colors it provided. I wanted to leave it to me to decide which foreground and background colors I wanted so I just dumped out the colors in CSS blocks for review in my editor.

The code looks like:

$palette = Palette::fromGD($im);
$topColors = $palette->getMostUsedColors(12);
$colorCount = count($palette);
// an extractor is built from a palette
$extractor = new ColorExtractor($palette);
// League\ColorExtractor\ColorExtractor library does work to
// get the most representative colors
$colors = $extractor->extract(5);
// populate the css file with colors
foreach($colors as $color) {
	printf("--color: %s;\n", Color::fromIntToHex($color));
	printf("--backgroundColor: %s;\n", Color::fromIntToHex($color));
}

The full code is now in a GitHub Gist.

Opening the resulting CSS file looks like:

My editor phpStorm is reminding me with that highlighting that I have duplicate CSS variable definitions. It also has this excellent feature that shows a swatch of the color itself next to any mention of a CSS color. Once I had that, my editorial task was to go through each block and leave one color and one backgroundColor to suit my tastes. I went through the many headers and did that, and integrated that into the site’s CSS. And now for all blog posts and date-based archive pages the footer has colors defined for the footer. I may yet use that CSS variable in more places. For now, just the footer:


My aesthetic is on the quirky side so these fit in great and they add some personality to archive pages that I like.

It’s also a reminder that for any task it’s helpful to think aloud “what task am I trying to solve?” and in this case I started with the question “what are the colors in these header files and header images?” and the better question is “what are the most iconically representative colors in each header as it appears on screens?”

Of course, it often takes experimentation to get from the first question to the final question!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.