Have you ever wondered how design tools automatically pick the perfect background colour for an image? Or how e-commerce sites group products by colour? The secret lies in colour extraction algorithms that analyze images and identify their dominant hues.
In this tutorial, I’ll show you two powerful techniques for extracting colours from images using PHP’s GD library. Whether you need a complete colour palette or just want to find that one perfect accent colour, these methods have you covered.

What You’ll Learn
We’ll explore two distinct approaches to colour extraction:
1. The Colour Palette Method – Sample pixels across an image to discover multiple dominant colours. This technique is perfect when you need to understand the full colour composition of an image, like creating a colour scheme or building a design palette.
2. The Average Colour Method – A clever trick that shrinks an entire image down to a single pixel, revealing its overall dominant colour. This lightning-fast technique is ideal for generating dynamic backgrounds, matching UI themes, or quick colour categorization.
Why This Matters
Colour extraction opens up a world of possibilities:
- Dynamic theming – Automatically match your UI to uploaded images
- Visual search – Let users find products by colour
- Content organization – Categorize images by their colour properties
- Accessibility – Calculate proper text contrast against extracted backgrounds
- Design automation – Generate colour schemes without manual work
What You’ll Need
- PHP with GD library enabled (most hosting providers include this)
- Basic understanding of PHP and image handling
- Sample images to experiment with
The best part? Both techniques are surprisingly simple. The palette method samples pixels intelligently to find popular colours, while the average colour method uses a brilliant one-liner that leverages image resizing to do the heavy lifting.
Ready to dive in? Let’s start extracting colours!
<?php
/**
* ============================================================================
* IMAGE COLOR EXTRACTION TUTORIAL
* ============================================================================
*
* This tutorial demonstrates two powerful techniques for extracting colors
* from images using PHP's GD library:
*
* 1. DOMINANT COLOR PALETTE - Extract multiple prominent colors from an image
* 2. AVERAGE COLOR - Calculate the single dominant/average color
*
* Both techniques are useful for:
* - Creating color-coordinated UI elements
* - Generating dynamic backgrounds
* - Image categorization and search
* - Automatic theme generation
* ============================================================================
*/
// Enable error reporting for debugging
error_reporting(E_ALL);
ini_set('display_errors', 1);
/**
* ============================================================================
* TECHNIQUE 1: EXTRACTING A COLOR PALETTE (Multiple Dominant Colors)
* ============================================================================
*
* This function samples pixels across an image and identifies the most
* frequently occurring colors. Think of it as taking a survey of the image's
* colors and finding the most popular ones.
*
* @param string $image - Path to the image file
* @param int $num - Number of colors to extract (e.g., top 5, top 10)
* @param int $level - Sampling rate (higher = faster but less accurate)
* 1 = check every pixel (slow but accurate)
* 5 = check every 5th pixel (faster, still accurate)
* 10 = check every 10th pixel (very fast, less accurate)
*
* @return array|bool - Array of hex color codes, or true on error
*/
function detectColors($image, $num, $level = 5) {
// Ensure $level is an integer to prevent errors in loops
$level = (int) $level;
// This array will store colors as keys and their frequency as values
// Example: ['FF0000' => 150, '00FF00' => 89, '0000FF' => 234]
$palette = [];
// Get image dimensions and basic information
// Returns array: [width, height, type, attr string]
$size = getimagesize($image);
// If getimagesize fails, the file is invalid or doesn't exist
if (!$size) {
return true;
}
// Load the image into memory as a GD image resource
// imagecreatefromstring automatically detects the image format (JPEG, PNG, GIF, etc.)
// This is more flexible than using imagecreatefromjpeg, imagecreatefrompng separately
$img = imagecreatefromstring(file_get_contents($image));
// If image creation fails, return early
if (!$img) {
return true;
}
/**
* THE PIXEL SAMPLING LOOP
*
* This nested loop walks through the image, sampling pixels at regular intervals.
* Instead of checking EVERY pixel (which would be slow), we skip pixels based
* on the $level parameter.
*
* For a 1000x1000 image:
* - $level = 1: checks 1,000,000 pixels (slow but comprehensive)
* - $level = 5: checks 40,000 pixels (much faster, still accurate)
* - $level = 10: checks 10,000 pixels (very fast)
*/
// Loop through image width (x-axis), jumping by $level pixels each time
for($i = 0; $i < $size[0]; $i += $level) {
// Loop through image height (y-axis), jumping by $level pixels each time
for($j = 0; $j < $size[1]; $j += $level) {
// Get the color value at this specific pixel coordinate
// Returns an integer representing the color
$thisColor = imagecolorat($img, $i, $j);
// Convert the integer color value to RGB components
// Returns array: ['red' => 255, 'green' => 128, 'blue' => 0, 'alpha' => 0]
$rgb = imagecolorsforindex($img, $thisColor);
// Convert RGB values to hexadecimal format (e.g., "FF8000")
// sprintf with %02X ensures each component is 2 digits with leading zeros
// Example: RGB(255, 128, 0) becomes "FF8000"
$color = sprintf(
'%02X%02X%02X',
$rgb['red'],
$rgb['green'],
$rgb['blue']
);
// Add this color to our palette or increment its count
// If color exists: increment counter, if new: set to 1
// This is a concise way of doing:
// if (isset($palette[$color])) {
// $palette[$color]++;
// } else {
// $palette[$color] = 1;
// }
$palette[$color] = isset($palette[$color]) ? ++$palette[$color] : 1;
}
}
// Sort the palette by frequency (value), highest to lowest
// After this, the most common colors appear first in the array
arsort($palette);
// Return only the top $num colors (just the hex codes, not the counts)
// array_keys() extracts the color hex codes from the array
// array_slice() takes the first $num items
return array_slice(array_keys($palette), 0, $num);
}
/**
* ============================================================================
* DEMONSTRATION: EXTRACTING AND DISPLAYING COLOR PALETTE
* ============================================================================
*/
// Specify the image to analyze
$img = 'unsplash.jpg';
// Extract the top 8 most common colors
// Using $level=1 for maximum accuracy (checks every pixel)
$palette = detectColors($img, 8, 1);
// Display the original image
echo '<img src="' . $img . '" style="max-width:100%">';
// Create a table to show the extracted color palette
echo '<table>';
// Loop through each extracted color and display it with its hex code
foreach ($palette as $color) {
// Each row shows a color swatch and its hex value
echo '<tr><td style="background:#' . $color . '; width:36px;"></td><td>#' . $color . '</td></tr>';
}
echo '</table>';
/**
* ============================================================================
* TECHNIQUE 2: EXTRACTING THE AVERAGE/DOMINANT COLOR
* ============================================================================
*
* This technique uses a different approach: instead of sampling pixels,
* it shrinks the ENTIRE image down to a single 1x1 pixel. That pixel's
* color represents the average of all colors in the image.
*
* This is faster than the palette method and gives you the "overall" color
* impression of the image - perfect for background colors or theme matching.
*
* The process works like this:
* 1. Load the full-size image
* 2. Create a tiny 1x1 pixel image
* 3. Resize the full image into that 1x1 space
* 4. The resulting pixel color is the average of all pixels
* ============================================================================
*/
/**
* EXAMPLE 1: Extract average color for 'unsplash.jpg'
*/
// Specify the image file
$value = 'unsplash.jpg';
// Get image information including MIME type
// This tells us if it's a JPEG, PNG, GIF, etc.
$info = getimagesize($value);
$mime = $info['mime'];
// Select the appropriate image creation function based on file type
// Different image formats require different loading functions
switch ($mime) {
case 'image/jpeg':
$image_create_func = 'imagecreatefromjpeg';
break;
case 'image/png':
$image_create_func = 'imagecreatefrompng';
break;
case 'image/gif':
$image_create_func = 'imagecreatefromgif';
break;
}
// Load the image using the appropriate function
// We store the function name as a string, then call it
$avg = $image_create_func($value);
// Get the dimensions of the original image
list($width, $height) = getimagesize($value);
// Create a new 1x1 pixel image - this will hold our average color
// imagecreatetruecolor creates a new true color image (24-bit RGB)
$tmp = imagecreatetruecolor(1, 1);
// This is where the magic happens!
// imagecopyresampled resizes the full image into our 1x1 pixel
// Parameters breakdown:
// - $tmp: destination image (our 1x1 pixel)
// - $avg: source image (full-size original)
// - 0, 0: destination x, y (top-left of our 1x1 image)
// - 0, 0: source x, y (top-left of original image)
// - 1, 1: destination width, height (our tiny 1x1 canvas)
// - $width, $height: source width, height (full original image)
//
// When GD shrinks the image to 1x1, it averages all the pixel colors together
imagecopyresampled($tmp, $avg, 0, 0, 0, 0, 1, 1, $width, $height);
// Get the color of our single pixel - this is the average color!
$rgb = imagecolorat($tmp, 0, 0);
// Extract individual RGB components using bitwise operations
// The color is stored as a single integer, so we need to extract each component:
// - >> 16: shift right 16 bits to get red (bits 16-23)
// - >> 8: shift right 8 bits to get green (bits 8-15)
// - & 0xFF: mask to get only the last 8 bits for blue (bits 0-7)
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// Display the image with its average color as the background
// This creates a nice preview showing how the color relates to the image
echo '<div style="display:inline-block; width:auto; height:150px; margin:8px; padding:24px; box-sizing:border-box; background-color:rgb('.$r.','.$g.','.$b.');">';
echo '<img style="width:auto; max-height:100%; max-width: 100%; vertical-align:middle; height:auto; margin-bottom:5px;" src="'.$value.'">';
echo '</div>';
/**
* EXAMPLE 2: Extract average color for 'melissa.jpg'
* (Same process as above - showing it works for different images)
*/
$value = 'melissa.jpg';
$info = getimagesize($value);
$mime = $info['mime'];
switch ($mime) {
case 'image/jpeg':
$image_create_func = 'imagecreatefromjpeg';
break;
case 'image/png':
$image_create_func = 'imagecreatefrompng';
break;
case 'image/gif':
$image_create_func = 'imagecreatefromgif';
break;
}
$avg = $image_create_func($value);
list($width, $height) = getimagesize($value);
$tmp = imagecreatetruecolor(1, 1);
imagecopyresampled($tmp, $avg, 0, 0, 0, 0, 1, 1, $width, $height);
$rgb = imagecolorat($tmp, 0, 0);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
echo '<div style="display:inline-block; width:auto; height:150px; margin:8px; padding:24px; box-sizing:border-box; background-color:rgb('.$r.','.$g.','.$b.');">';
echo '<img style="width:auto; max-height:100%; max-width: 100%; vertical-align:middle; height:auto; margin-bottom:5px;" src="'.$value.'">';
echo '</div>';
/**
* EXAMPLE 3: Extract average color for 'stalker.jpg'
* This example also demonstrates converting RGB to hexadecimal format
*/
$value = 'stalker.jpg';
$info = getimagesize($value);
$mime = $info['mime'];
switch ($mime) {
case 'image/jpeg':
$image_create_func = 'imagecreatefromjpeg';
break;
case 'image/png':
$image_create_func = 'imagecreatefrompng';
break;
case 'image/gif':
$image_create_func = 'imagecreatefromgif';
break;
}
$avg = $image_create_func($value);
list($width, $height) = getimagesize($value);
$tmp = imagecreatetruecolor(1, 1);
imagecopyresampled($tmp, $avg, 0, 0, 0, 0, 1, 1, $width, $height);
$rgb = imagecolorat($tmp, 0, 0);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// Convert RGB to hexadecimal format (alternative to RGB format)
// %02x formats each value as lowercase hex with leading zero if needed
// Example: RGB(255, 128, 0) becomes "#ff8000"
$hex = sprintf("#%02x%02x%02x", $r, $g, $b);
// Display with hex color format instead of rgb()
echo '<div style="display:inline-block; width:auto; height:150px; margin:8px; padding:24px; box-sizing:border-box; background-color:'.$hex.';">';
echo '<img style="width:auto; max-height:100%; max-width: 100%; vertical-align:middle; height:auto; margin-bottom:5px;" src="'.$value.'">';
echo '</div>';
/**
* ============================================================================
* KEY DIFFERENCES BETWEEN THE TWO TECHNIQUES:
* ============================================================================
*
* COLOR PALETTE METHOD (detectColors function):
* ✓ Extracts multiple distinct colors
* ✓ Shows color distribution and variety
* ✓ Better for understanding color composition
* ✓ Slower (samples many pixels)
* ✓ Great for: color schemes, palettes, detailed analysis
*
* AVERAGE COLOR METHOD (1x1 resize technique):
* ✓ Extracts single dominant color
* ✓ Shows overall color "mood" or "tone"
* ✓ Very fast (single resize operation)
* ✓ Better for: backgrounds, themes, quick categorization
* ✓ Great for: UI matching, ambient colors, thumbnails
*
* ============================================================================
* PRACTICAL APPLICATIONS:
* ============================================================================
*
* 1. Dynamic UI theming - Set page backgrounds based on hero images
* 2. E-commerce - Group products by color automatically
* 3. Photo galleries - Create color-coordinated layouts
* 4. Accessibility - Ensure text contrast against extracted colors
* 5. Design tools - Generate complementary color suggestions
* 6. Social media - Create attractive post backgrounds
* 7. Content management - Auto-categorize images by color
*
* ============================================================================
* PERFORMANCE TIPS:
* ============================================================================
*
* 1. Cache results - Save extracted colors to database
* 2. Process on upload - Extract colors when images are uploaded
* 3. Use appropriate $level - Balance speed vs. accuracy (5-10 is good)
* 4. Resize before processing - Work with smaller versions of large images
* 5. Consider image complexity - Simple images need less sampling
*
* ============================================================================
*/