使用PHP生成颜色数组

Is it possible to create an array of colors with PHP?

What I'm trying to do:

  1. Select a start and end color
  2. Choose an amount of "steps"
  3. Create an array of those colors blending together (as a gradient) with that amount of steps.

Example:

Start color: White
End color: Black
Steps: 3

Result:

  1. "white",
  2. "gray",
  3. "black"

Of course the colors would be in RGB/hex

Anyone with a solution on this?

 $greys=rainbow('000000','FFFFFF',3);

 function rainbow($start, $end, $steps)
 {
    $s=str_to_rgb($start);
    $e=str_to_rgb($end);
    $out=array();
    $r=(integer)($e['r'] - $s['r'])/$steps;
    $g=(integer)($e['g'] - $s['g'])/$steps;
    $b=(integer)($e['b'] - $s['b'])/$steps;
    for ($x=0; $x<$steps; $x++) {
       $out[]=rgb_to_str(
          $s['r']+(integer)($r * $x),
          $s['g']+(integer)($g * $x),
          $s['b']+(integer)($b * $x));
    }
    return $out;
 }
 function rgb_to_str($r, $g, $b)
 {
      return str_pad($r, 2, '0', STR_PAD_LEFT)
          .str_pad($g, 2, '0', STR_PAD_LEFT)
          .str_pad($b, 2, '0', STR_PAD_LEFT);
 }
 function str_to_rgb($str)
 {
    return array (
      'r'=>hexdec(substr($str, 0, 2)),
      'g'=>hexdec(substr($str, 3, 2)),
      'b'=>hexdec(substr($str, 5, 2))
    );
 }

There's a basic tutorial here about making hex colours that you can use as a starting point. The key idea is being able to work out how to progress along the separate RGB base-16 hex codes to make a smooth progression of colours, rather than just sequential numbers.

//Assumption: $start and $end have the start/end colors, $steps has the step count

$start=array(255,255,255); //White
$end=array(0,0,0); //Black
$steps=3;

$colors=array($start); //You want the start color to be part of the result array
$intervals=$steps-1; //You want 3 steps to mean 2 intervals

$current=$start;
$delta=array(
   ($end[0]-$start[0])/$intervals,
   ($end[1]-$start[1])/$intervals,
   ($end[2]-$start[2])/$intervals
);

for ($i=1;$i<$intervals;$i++) {
  $current=array($current[0]+$delta[0],$current[1]+$delta[1],$current[2]+$delta[2]);
  $colors[]=array(round($current[0],$current[1],$current[2]);
}

$colors[]=$end; //You want the end color to be part of the result array

Will give you an array of colors, each being an array of r,g,b

To create the hex representation use

function hexcolorFromArraycolor($arraycolor) {
  return '#'
     .substr('0'.dechex($arraycolor[0]),-2)
     .substr('0'.dechex($arraycolor[1]),-2)
     .substr('0'.dechex($arraycolor[2]),-2)
  ;
}

Let's say you have colors in one numeric value such as from (RGB) 0x000000 to 0x112233, first of all you need to extract all values:

function hexToArray( $value){
    return array(
      'r' => ($value >> 16) & 0xff,
      'g' => ($value >> 8) & 0xff,
      'b' => ($value >> 0) & 0xff,
    );
}

Than you have to create some stepping algorithm, most obvious is increasing each component in each step:

Ri = Rstart + floor(i * (Rend - Rstart)/ steps)

Which would look like:

$steps--; // Due to 0
$a = hexToArray( 0x000000);
$b = hexToArray( 0x112233);
$step = array();
$result = array();

// Prepare steps
foreach( array( 'r', 'g', 'b') as $color){
    $step[$color] = ($b[$color] - $a['color'])/$steps;
}

for( $i = 0; $i <= $steps; $i++){
    $tmp = array();
    foreach( array( 'r', 'g', 'b') as $color){
        $tmp[$color] = $a['color'] + floor($step[$color]*$i);
    }
    $result[] = $tmp;
}
return $result;

You also may add transformation back to long int or to string.

When you will have hex values you will also require other hexToArray function.

I needed to take GPS points from a driver's route and map them (using google maps) by time. I figued I would rainbow color them from oldest to newest. I found http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm as good starting point. I re-wrote as PHP functions...

$blue = 0;
$factor = 0;
$green = 0;
$red = 0;

function adjustColor($color) {
    global $factor;
    if ($color == 0.0) {
        return 0;
    } else {
        return round ( 255.0 * pow ( ($color * $factor), 0.80 ) );
    }
}

function setColors($wavelength) {
    global $red, $green, $blue;
    if ($wavelength >= 380 && $wavelength <= 439) {
        $red = - ($wavelength - 440.0) / (440.0 - 380.0);
        $green = 0.0;
        $blue = 1.0;

    } elseif ($wavelength >= 440 && $wavelength <= 489) {
        $red = 0.0;
        $green = ($wavelength - 440.0) / (490.0 - 440.0);
        $blue = 1.0;

    } elseif ($wavelength >= 490 && $wavelength <= 509) {
        $red = 0.0;
        $green = 1.0;
        $blue = - ($wavelength - 510.0) / (510.0 - 490.0);

    } elseif ($wavelength >= 510 && $wavelength <= 579) {
        $red = ($wavelength - 510.0) / (580.0 - 510.0);
        $green = 1.0;
        $blue = 0.0;

    } elseif ($wavelength >= 580 && $wavelength <= 644) {
        $red = 1.0;
        $green = - ($wavelength - 645.0) / (645.0 - 580.0);
        $blue = 0.0;

    } elseif ($wavelength >= 645 && $wavelength <= 780) {
        $red = 1.0;
        $green = 0.0;
        $blue = 0.0;

    } else {
        $red = 0.0;
        $green = 0.0;
        $blue = 0.0;
    }
}

function setFactor($wavelength) {
    global $factor;
    if ($wavelength >= 380 && $wavelength <= 419) {
        $factor = 0.3 + 0.7 * ($wavelength - 380.0) / (420.0 - 380.0);
    } elseif ($wavelength >= 420 && $wavelength <= 700) {
        $factor = 1.0;
    } elseif ($wavelength >= 701 && $wavelength <= 780) {
        $factor = 0.3 + 0.7 * (780.0 - $wavelength) / (780.0 - 700.0);
    } else {
        $factor = 0.0;
    }
}

Then use the functions to get each point's color.

for($i = 0; $i < $numSteps; $i ++) {
    $lambda = round ( 380 + 400 * ($i / ($numSteps - 1)) );
    setColors ( $lambda );
    setFactor ( $lambda );
    $red = adjustColor ( $red, $factor );
    $green = adjustColor ( $green, $factor );
    $blue = adjustColor ( $blue, $factor );
    $redHex = dechex ( $red );
    $redHex = (strlen ( $redHex ) < 2) ? "0" . $redHex : $redHex;
    $greenHex = dechex ( $green );
    $greenHex = (strlen ( $greenHex ) < 2) ? "0" . $greenHex : $greenHex;
    $blueHex = dechex ( $blue );
    $blueHex = (strlen ( $blueHex ) < 2) ? "0" . $blueHex : $blueHex;
    $bgcolor = "#" . $redHex . $greenHex . $blueHex;
    echo $bgcolor;
}