128) // don't want to tax server/bandwidth too much $h = 128; if ($sw) // base width on number of samples? $w = (count($series)-$order) * $sw; if (!$w) // or just guess one if not already here $w = $h * 4; if ($w > 1024) // limit again $w = 1024; // we'll draw to a 2x res bitmap then downsample... easiest way to antialias for now if ($aa) { $w *= 2; $h *= 2; } $im = @imagecreatetruecolor($w, $h) or die("Couldn't initialize new GD image stream"); // we allow multiple ways to define a color, all use hex bumbers // B = 0xBBBBBB (greyscale) // B9 = 0xB9B9B9 (greyscale) // B94 = 0xBB9944 // B94CD1 = 0xB94CD1 function ParseColorValue($col) { sscanf($col, "%6x", $val); // read the raw number if (strlen($col) == 1) $val = $val * 0x111111; else if (strlen($col) == 2) $val = $val * 0x10101; else if (strlen($col) == 3) $val = (($val & 0xF00) * 0x1100) + (($val & 0xF0) * 0x110) + (($val & 0xF) * 0x11); return $val; } // allocate inks if (empty($bg)) $bg = 0xffffff; else $bg = ParseColorValue($bg); if (empty($fill)) $fill = 0xcccccc; else $fill = ParseColorValue($fill); if (empty($tint)) // used for optional range bars $tint = 0xf0f0f0; else $tint = ParseColorValue($tint); if (empty($line)) $line = 0x444444; else $line = ParseColorValue($line); // clear to background color imagefilledrectangle($im, 0, 0, $w, $h, $bg); // get data range $lower = $upper = $series[0]; for ($i = 1; $i < count($series); $i++) { if ($lower > $series[$i]) $lower = $series[$i]; else if ($upper < $series[$i]) $upper = $series[$i]; } // if user has supplied additional min and max values [to expand to, not collapse] if (!empty($min) && $lower > $min) $lower = $min; if (!empty($max) && $upper < $max) $upper = $max; if ($lower == $upper) // avoid Divide by zero error, impose a 1.0 range { $upper += 0.5; $lower -= 0.5; } function ScaleForRange($v) { global $lower, $upper; return ($v - $lower) / ($upper - $lower); } $fudge = 0; function ScaleForBitmap($v) { global $h, $fudge; return $h - ScaleForRange($v) * ($h-2) - 1 + $fudge; // pixel fudging ;) } $zero = ScaleForBitmap($zero); if (!($zero & 1) && $aa) { $fudge = 1; $zero ++; } // we can provide color bands to give some visual indications of scale if (!empty($zone)) { $zone = explode(",", $zone); for ($i = 0; $i < count($zone) >> 1; $i++) imagefilledrectangle($im, 0, ScaleForBitmap($zone[$i*2+1]), $w, ScaleForBitmap($zone[$i*2]), $tint); } if (!$gap) $gap = 0; $gap *= 0.5; // shave half off either end (see below) for ($i = 0; $i < $w; $i++) { if ($order == 2) // quadratic? { $x = $i * (count($series)-2) / $w; $f = $x - (int)$x; $y = ($series[$x] * (1-($f*0.5+0.5)) + $series[$x+1] * ($f*0.5+0.5)) * (1-$f) + ($series[$x+1] * (1-$f*0.5) + $series[$x+2] * $f*0.5) * $f; } else if ($order == 1) // linear? { $x = $i * (count($series)-1) / $w; $f = $x - (int)$x; $y = $series[$x] * (1-$f) + $series[$x+1] * $f; } else // bar { $x = $i * count($series) / $w; $f = $x - (int)$x; $y = $series[$x]; } if ($gap && ($f < $gap || $f > 1-$gap)) // per sample gap continue; $v = ScaleForBitmap($y); if ($style & 4) // intensity plot { $color = ScaleForRange($y); // mix the colors $color = ((int)(($line & 0xff) * $color + ($bg & 0xff) * (1-$color)) & 0xff) + ((int)(($line & 0xff00) * $color + ($bg & 0xff00) * (1-$color)) & 0xff00) + ((int)(($line & 0xff0000) * $color + ($bg & 0xff0000) * (1-$color)) & 0xff0000) ; imagefilledrectangle($im, $i, 0, $i, $h, $color); } if ($style & 2) // fill { if ($v <= $zero) { $y1 = $v; $y2 = $zero; } else { $y2 = $v+1; $y1 = $zero+1; } imagefilledrectangle($im, $i, $y1, $i, $y2, $fill); } if (($style & 1) || !$style) // line? { if (!empty($last)) // only if we have a last point to draw from { if ($order) // continuous plot { imageline($im, $i-1, $last, $i, $v, $line); //imageline($im, $i-1, $last+1, $i, $y+1, $line); imageline($im, $i, $last, $i+1, $v, $line); } else // square trace { imageline($im, $i-1, $last, $i-1, $v, $line); imageline($im, $i-1, $v, $i, $v, $line); } } $last = $v; } } if ($aa) { $im2 = @imagecreatetruecolor(intval($w*0.5), intval($h*0.5)) or die("Couldn't initialize new GD image stream"); imagecopyresampled($im2, $im, 0, 0, 0, 0, imagesx($im2), imagesy($im2), imagesx($im), imagesy($im)); imagedestroy($im); $im = $im2; } // doesn't really need to change at all, but added this just in case the algorithm changes @header("Last-Modified: " . gmdate("D, d M Y H:i:s", intval(time() / 86400) * 86400) . " GMT"); @header("Content-type: image/png"); imagepng($im); imagedestroy($im); exit; ?>