Enhance GD::greyscale to allow darker or lighter results, and change color weights for greyscale (#5332)

Tweaking the first three parameters (R, G, B) allows you to get a different mix of colors into grey, but it does not allow you to make the result lighter or darker because their total is normalized. This is quite a common operation on greyscaled images though, so I added a fourth parameter: brightness. It defaults to 100% so that it does not have any effect when not used (making this backwards compatible). $brightness = 50 will make it darker, $brightness = 150 will overlight it.
This commit is contained in:
JorisDebonnet 2016-04-21 09:26:46 +02:00 committed by Sam Minnée
parent 4f14175022
commit 9eac541740
2 changed files with 18 additions and 13 deletions

View File

@ -486,14 +486,16 @@ class GDBackend extends Object implements Image_Backend {
} }
/** /**
* Make the image greyscale * Make the image greyscale.
* $rv = red value, defaults to 38 * Default color weights are based on standard BT.601 (those used in PAL, NTSC and many software packages, also see
* $gv = green value, defaults to 36 * https://en.wikipedia.org/wiki/Grayscale#Luma_coding_in_video_systems )
* $bv = blue value, defaults to 26 *
* Based (more or less entirely, with changes for readability) on code from * $R = red weight, defaults to 299
* http://www.teckis.com/scriptix/thumbnails/teck.html * $G = green weight, defaults to 587
* $B = blue weight, defaults to 114
* $brightness = brightness in percentage, defaults to 100
*/ */
public function greyscale($rv=38, $gv=36, $bv=26) { public function greyscale($R=299, $G=587, $B=114, $brightness=100) {
$width = $this->width; $width = $this->width;
$height = $this->height; $height = $this->height;
$newGD = imagecreatetruecolor($this->width, $this->height); $newGD = imagecreatetruecolor($this->width, $this->height);
@ -502,15 +504,18 @@ class GDBackend extends Object implements Image_Backend {
imagealphablending($newGD, false); imagealphablending($newGD, false);
imagesavealpha($newGD, true); imagesavealpha($newGD, true);
$rt = $rv + $bv + $gv; $rt = $R + $G + $B;
$rr = ($rv == 0) ? 0 : 1/($rt/$rv); // if $rt is 0, bad parameters are provided, so result will be a black image
$br = ($bv == 0) ? 0 : 1/($rt/$bv); $rr = $rt ? $R/$rt : 0;
$gr = ($gv == 0) ? 0 : 1/($rt/$gv); $gr = $rt ? $G/$rt : 0;
$br = $rt ? $B/$rt : 0;
// iterate over all pixels and make them grey
for($dy = 0; $dy < $height; $dy++) { for($dy = 0; $dy < $height; $dy++) {
for($dx = 0; $dx < $width; $dx++) { for($dx = 0; $dx < $width; $dx++) {
$pxrgb = imagecolorat($this->gd, $dx, $dy); $pxrgb = imagecolorat($this->gd, $dx, $dy);
$heightgb = ImageColorsforIndex($this->gd, $pxrgb); $heightgb = ImageColorsforIndex($this->gd, $pxrgb);
$newcol = ($rr*$heightgb['red']) + ($br*$heightgb['blue']) + ($gr*$heightgb['green']); $newcol = ($rr*$heightgb['red']) + ($br*$heightgb['blue']) + ($gr*$heightgb['green']);
$newcol = min(255, $newcol*$brightness/100);
$setcol = ImageColorAllocateAlpha($newGD, $newcol, $newcol, $newcol, $heightgb['alpha']); $setcol = ImageColorAllocateAlpha($newGD, $newcol, $newcol, $newcol, $heightgb['alpha']);
imagesetpixel($newGD, $dx, $dy, $setcol); imagesetpixel($newGD, $dx, $dy, $setcol);
} }

View File

@ -91,8 +91,8 @@ class GDTest extends SapphireTest {
} }
// check various sample points // check various sample points
$this->assertColourEquals(96, $samples[0]['red'], $tolerance); $this->assertColourEquals(76, $samples[0]['red'], $tolerance);
$this->assertColourEquals(91, $samples[2]['red'], $tolerance); $this->assertColourEquals(149, $samples[2]['red'], $tolerance);
$this->assertColourEquals(0, $samples[8]['red'], $tolerance); $this->assertColourEquals(0, $samples[8]['red'], $tolerance);
$this->assertColourEquals(127, $samples[9]['red'], $tolerance); $this->assertColourEquals(127, $samples[9]['red'], $tolerance);