Refactor imagegammacorrect()

We apply the law `(b**r)**s == b**(r*s)` which holds for all non-negative b
and positive r,s, so a single pow() suffices. Furthermore, we precompute the
gamma, so the refactored code is simpler and faster.
This commit is contained in:
Christoph M. Becker 2016-09-25 09:47:23 +02:00
parent 47f1666f7c
commit 65ee87f20d
5 changed files with 81 additions and 7 deletions

View file

@ -3025,7 +3025,7 @@ PHP_FUNCTION(imagegammacorrect)
zval *IM;
gdImagePtr im;
int i;
double input, output;
double input, output, gamma;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rdd", &IM, &input, &output) == FAILURE) {
return;
@ -3036,6 +3036,8 @@ PHP_FUNCTION(imagegammacorrect)
RETURN_FALSE;
}
gamma = input / output;
if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
RETURN_FALSE;
}
@ -3048,9 +3050,9 @@ PHP_FUNCTION(imagegammacorrect)
c = gdImageGetPixel(im, x, y);
gdImageSetPixel(im, x, y,
gdTrueColorAlpha(
(int) ((pow((pow((gdTrueColorGetRed(c) / 255.0), input)), 1.0 / output) * 255) + .5),
(int) ((pow((pow((gdTrueColorGetGreen(c) / 255.0), input)), 1.0 / output) * 255) + .5),
(int) ((pow((pow((gdTrueColorGetBlue(c) / 255.0), input)), 1.0 / output) * 255) + .5),
(int) ((pow((gdTrueColorGetRed(c) / 255.0), gamma) * 255) + .5),
(int) ((pow((gdTrueColorGetGreen(c) / 255.0), gamma) * 255) + .5),
(int) ((pow((gdTrueColorGetBlue(c) / 255.0), gamma) * 255) + .5),
gdTrueColorGetAlpha(c)
)
);
@ -3060,9 +3062,9 @@ PHP_FUNCTION(imagegammacorrect)
}
for (i = 0; i < gdImageColorsTotal(im); i++) {
im->red[i] = (int)((pow((pow((im->red[i] / 255.0), input)), 1.0 / output) * 255) + .5);
im->green[i] = (int)((pow((pow((im->green[i] / 255.0), input)), 1.0 / output) * 255) + .5);
im->blue[i] = (int)((pow((pow((im->blue[i] / 255.0), input)), 1.0 / output) * 255) + .5);
im->red[i] = (int)((pow((im->red[i] / 255.0), gamma) * 255) + .5);
im->green[i] = (int)((pow((im->green[i] / 255.0), gamma) * 255) + .5);
im->blue[i] = (int)((pow((im->blue[i] / 255.0), gamma) * 255) + .5);
}
RETURN_TRUE;

View file

@ -0,0 +1,72 @@
--TEST--
Apply imagegammacorrect() to a step wedge
--SKIPIF--
<?php
if (!extension_loaded('gd')) die('skip gd extension not available');
?>
--FILE--
<?php
require __DIR__ . DIRECTORY_SEPARATOR . 'func.inc';
test_gamma_both(1, 2);
test_gamma_both(1, 1);
test_gamma_both(2, 1);
function test_gamma_both($in, $out)
{
test_gamma($in, $out, 'imagecreate');
test_gamma($in, $out, 'imagecreatetruecolor');
}
function test_gamma($in, $out, $constructor)
{
$im = $constructor(640, 480);
for ($j = 0; $j < 4; $j++) {
for ($i = 0; $i < 32; $i++) {
draw_cell($im, $i, $j);
}
}
imagegammacorrect($im, $in, $out);
$filename = __DIR__ . DIRECTORY_SEPARATOR
. "imagegammacorrect_variation2_{$in}_{$out}.png";
$kind = $constructor === 'imagecreate' ? 'palette' : 'truecolor';
echo "$kind gamma ($in, $out): ";
test_image_equals_file($filename, $im);
}
function draw_cell($im, $x, $y)
{
$x1 = 20 * $x;
$y1 = 120 * $y;
$x2 = $x1 + 19;
$y2 = $y1 + 119;
$color = cell_color($im, $x, $y);
imagefilledrectangle($im, $x1,$y1, $x2,$y2, $color);
}
function cell_color($im, $x, $y)
{
$channel = 8 * $x + 4;
switch ($y) {
case 0:
return imagecolorallocate($im, $channel, $channel, $channel);
case 1:
return imagecolorallocate($im, $channel, 0, 0);
case 2:
return imagecolorallocate($im, 0, $channel, 0);
case 3:
return imagecolorallocate($im, 0, 0, $channel);
}
}
?>
===DONE===
--EXPECT--
palette gamma (1, 2): The images are equal.
truecolor gamma (1, 2): The images are equal.
palette gamma (1, 1): The images are equal.
truecolor gamma (1, 1): The images are equal.
palette gamma (2, 1): The images are equal.
truecolor gamma (2, 1): The images are equal.
===DONE===

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB