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

これについてできることは 2 つあります。最初のおそらく最も簡単な方法は、トゥルーカラー イメージを使用することです。これは、 に変更する単純なケース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 に答える