1

以下 php 代码块应该将此图像作为输入并生成此图像作为输出(将黑色转换为黄色,将浅蓝色转换为黑色):

但是,我将此图像作为输出。

任何人都可以看到我的代码的问题吗?

$im = imagecreatefrompng("./input.png");
$width = imagesx($im);
$height = imagesy($im);
$new = imagecreate($width, $height);
imagecopy($new, $im, 0, 0, 0, 0, $width, $height);
imagecolorset($new, imagecolorexact($new, 0, 0, 0), 255, 255, 0);

for($i = 0; $i < $width; $i++) {
    for($j = 0; $j < $height; $j++) {
        $index = imagecolorat($new, $i, $j);
        $rgb = imagecolorsforindex($new, $index);
        if($rgb['red'] != 255 && $rgb['green'] != 255 && $rgb['blue'] != 0) {
            echo '(' . $i . ', ' . $j . ')' . 'color => (' . (255 - $rgb['blue']) . ', ' . (255 - $rgb['blue']) . ', 0)<br />';
            $color = imagecolorallocate($new, 255 - $rgb['blue'], 255 - $rgb['blue'], 0);
            imagesetpixel($new,  $i, $j, $color);
        }
        unset($index);
        unset($rgb);
    }
}
imagepng($new, 'tesst.png');
imagedestroy($im);
imagedestroy($new);
4

2 回答 2

1

我相信这里问题的根源在于,当使用基于调色板的图像时,例如您通过调用创建的图像,imagecreate()可以在调色板中的多个索引处声明相同的颜色。

这意味着,因为您imagecolorallocate()在每次迭代时都在调用,所以调色板最终会变满并imagecolorallocate()开始返回(如果您在调用之前false可以看到这一点)。转换为整数时计算为零 - 因此当调色板填满时,所有剩余像素都有效地转换为背景颜色。var_dump($color);imagesetpixel()false

对此您可以做两件事,第一件事可能也是最简单的就是使用真彩色图像,这只是更改imagecreate($width, $height);imagecreatetruecolor($width, $height);.

如果您想坚持使用基于调色板的图像(例如,出于输出图像数据大小的原因 - 对于包含如此少颜色的图像,基于调色板的图像会小得多),您将需要手动缓存分配的颜色所以你可以重复使用它们,像这样:

// ...

$colors = array();

for ($x = 0; $x < $width; $x++) { // iterate x axis
    for ($y = 0; $y < $height; $y++) { // iterate y axis
        // Get the color at this index
        $index = imagecolorat($new, $x, $y);

        // Only allocate a new color if not already done
        if (!isset($colors[$index])) {
            $rgb = imagecolorsforindex($new, $index);
            if ($rgb['red'] != 255 || $rgb['green'] != 255 || $rgb['blue'] != 0) {
                // If it's not the background color allocate a new color
                $r = $g = 255 - $rgb['blue'];
                $b = 0;

                $colors[$index] = imagecolorallocate($new, $r, $g, $b);
            } else {
                // Otherwise set the index to false, we can ignore it
                $colors[$index] = false;
            }
        }

        // If there's something to do, do it
        if ($colors[$index] !== false) {
            imagesetpixel($new, $x, $y, $colors[$index]);
        }
    }
}

// ...

您可能还希望跟踪图像中使用的颜色,以便之后可以“清理调色板”(即,取消分配图像中不再使用的任何颜色,这将进一步有助于减少数据大小)。尽管可以说最好从一个干净的调色板开始并检查旧图像资源以获取像素细节,而不是将原始图像复制到新图像资源中。

于 2013-04-10T10:04:51.107 回答
0

是的,你的

$color = imagecolorallocate($new, 255 - $rgb['blue'], 255 - $rgb['blue'], 0);

把一切都搞砸了。。

如果您想要相同的输出...只需将行粘贴到 for 循环之外,如果您想要特定图像,这将解决您的问题:

$color = imagecolorallocate($new, 35, 35, 0); //got from debugging

它会得到你想要的输出。

丁斯

于 2013-04-10T10:10:29.523 回答