11

私はたくさん検索しましたが、いくつかの解決策しか見つかりませんでした(Googleとstackoverflowで、本当に重複した質問がない限り、これを重複としてマークしないでください)が、問題はハードエッジです。ベースカラーを変更する適切な方法はありますか?たとえば、背景が透明な黒い形のpng画像をソフトエッジを維持するために変更する方法はありますか?

これは画像の例です:

ここに画像の説明を入力

私はそれを次のようにしたい:

ここに画像の説明を入力

しかし、私が見つけた解決策は私にこれを与えます:

ここに画像の説明を入力

私は自分のローカルホストでこれを使用するので、個人的な使用のみを目的としているため、これを実現するのに役立つ任意の php ライブラリを高く評価します。

アップデート:

これは私に3番目の画像を与える関数です:

function LoadPNG($imgname)
{
    $im = imagecreatefrompng ($imgname);
    imagetruecolortopalette($im,false, 255);
    $index = imagecolorclosest ( $im,  0,0,0 ); // GET BLACK COLOR
    imagecolorset($im,$index,0,150,255); // SET COLOR TO BLUE
    $name = basename($imgname);
    imagepng($im, getcwd()."/tmp/$name" ); // save image as png
    imagedestroy($im);
}
$dir = getcwd()."/img/";
$images = glob($dir."/*.png",GLOB_BRACE);
foreach($images as $image) {
    LoadPNG($image);
}

本来、この機能はGIF画像(255色のパレット)に対する解決策だったので、ハードエッジがあるのはそのためだと思います。PNG 画像の透明度とソフト エッジを維持するための解決策 (このスクリプトの改善) を探しています。

編集2:

ここでhtml5キャンバスとjavascriptを使用した興味深いアプローチを見つけました: http://users7.jabry.com/overlord/mug.html

可能であれば、誰かがこれを PHP に変換する方法を考えているかもしれません。

新しいソリューション

回答で

4

6 に答える 6

15

このコードは問題を例示していませんが、次のように色を変換します。

ここに画像の説明を入力

画像の ALPHA チャネルを使用してカラーリングを決定します。他の結果については、次のことを試してみてimagecolorallocatealpha()ください。

function colorizeBasedOnAplhaChannnel( $file, $targetR, $targetG, $targetB, $targetName ) {

    $im_src = imagecreatefrompng( $file );

    $width = imagesx($im_src);
    $height = imagesy($im_src);

    $im_dst = imagecreatefrompng( $file );

    // Note this:
    // Let's reduce the number of colors in the image to ONE
    imagefilledrectangle( $im_dst, 0, 0, $width, $height, 0xFFFFFF );

    for( $x=0; $x<$width; $x++ ) {
        for( $y=0; $y<$height; $y++ ) {

            $alpha = ( imagecolorat( $im_src, $x, $y ) >> 24 & 0xFF );

            $col = imagecolorallocatealpha( $im_dst,
                $targetR - (int) ( 1.0 / 255.0  * $alpha * (double) $targetR ),
                $targetG - (int) ( 1.0 / 255.0  * $alpha * (double) $targetG ),
                $targetB - (int) ( 1.0 / 255.0  * $alpha * (double) $targetB ),
                $alpha
                );

            if ( false === $col ) {
                die( 'sorry, out of colors...' );
            }

            imagesetpixel( $im_dst, $x, $y, $col );

        }

    }

    imagepng( $im_dst, $targetName);
    imagedestroy($im_dst);

}

unlink( dirname ( __FILE__ ) . '/newleaf.png' );
unlink( dirname ( __FILE__ ) . '/newleaf1.png' );
unlink( dirname ( __FILE__ ) . '/newleaf2.png' );

$img = dirname ( __FILE__ ) . '/leaf.png';
colorizeBasedOnAplhaChannnel( $img, 0, 0, 0xFF, 'newleaf1.png' );
colorizeBasedOnAplhaChannnel( $img, 0xFF, 0, 0xFF, 'newleaf2.png' );
?>

Original
<img src="leaf.png">
<br />
<img src="newleaf1.png">
<br />
<img src="newleaf2.png">
于 2013-07-19T20:22:03.727 に答える
2

の受け入れられたコードを出発点として使用SteApして(それで透明性を達成できなかったため、白い背景だけ)、上記のコードを適応させたところ、結果は次のようになりました。

<?php 

function colorizeKeepAplhaChannnel( $inputFilePathIn, $targetRedIn, $targetGreenIn, $targetBlueIn, $outputFilePathIn ) {
    $im_src = imagecreatefrompng( $inputFilePathIn );
    $im_dst = imagecreatefrompng( $inputFilePathIn );
    $width = imagesx($im_src);
    $height = imagesy($im_src);

    // Note this: FILL IMAGE WITH TRANSPARENT BG
    imagefill($im_dst, 0, 0, IMG_COLOR_TRANSPARENT);
    imagesavealpha($im_dst,true);
    imagealphablending($im_dst, true);

    $flagOK = 1;
    for( $x=0; $x<$width; $x++ ) {
        for( $y=0; $y<$height; $y++ ) {
            $rgb = imagecolorat( $im_src, $x, $y );
            $colorOldRGB = imagecolorsforindex($im_src, $rgb);
            $alpha = $colorOldRGB["alpha"];
            $colorNew = imagecolorallocatealpha($im_src, $targetRedIn, $targetGreenIn, $targetBlueIn, $alpha);

            $flagFoundColor = true;
            // uncomment next 3 lines to substitute only 1 color (in this case, BLACK/greys)
/*
            $colorOld = imagecolorallocatealpha($im_src, $colorOldRGB["red"], $colorOldRGB["green"], $colorOldRGB["blue"], 0); // original color WITHOUT alpha channel
            $color2Change = imagecolorallocatealpha($im_src, 0, 0, 0, 0); // opaque BLACK - change to desired color
            $flagFoundColor = ($color2Change == $colorOld);
*/

            if ( false === $colorNew ) {
                //echo( "FALSE COLOR:$colorNew alpha:$alpha<br/>" );
                $flagOK = 0; 
            } else if ($flagFoundColor) {
                imagesetpixel( $im_dst, $x, $y, $colorNew );
                //echo "x:$x y:$y col=$colorNew alpha:$alpha<br/>";
            } 
        }
    }
    $flagOK2 = imagepng($im_dst, $outputFilePathIn);

    if ($flagOK && $flagOK2) {
        echo ("<strong>Congratulations, your conversion was successful </strong><br/>new file $outputFilePathIn<br/>");
    } else if ($flagOK2 && !$flagOK) {
        echo ("<strong>ERROR, your conversion was UNsuccessful</strong><br/>Please verify if your PNG is truecolor<br/>input file $inputFilePathIn<br/>");
    } else if (!$flagOK2 && $flagOK) {
        $dirNameOutput = dirname($outputFilePathIn)."/";
        echo ("<strong>ERROR, your conversion was successful, but could not save file</strong><br/>Please verify that you have PERMISSION to save to directory $dirName <br/>input file $inputFilePathIn<br/>");
    } else {
        $dirNameOutput = dirname($outputFilePathIn)."/";
        echo ("<strong>ERROR, your conversion was UNsuccessful AND could not save file</strong><br/>Please verify if your PNG is truecolor<br/>Please verify that you have PERMISSION to save to directory $dirName <br/>input file $inputFilePathIn<br/>");
    }

    echo ("TargetName:$outputFilePathIn wid:$width height:$height CONVERTED:|$flagOK| SAVED:|$flagOK2|<br/>");
    imagedestroy($im_dst);
    imagedestroy($im_src);
}




$targetRed = 0;
$targetGreen = 180;
$targetBlue = 0;

//$inputFileName = 'frameSquareBlack_88x110.png';
$inputFileName = 'testMe.png';
$dirName = "../img/profilePics/";
$nameTemp = basename($inputFileName, ".png");
$outputFileName = $nameTemp."_$targetRed"."_$targetGreen"."_$targetBlue.png";
$inputFilePath = $dirName.$inputFileName;
$outputFilePath = $dirName.$outputFileName;

//echo "inputFileName:$inputFilePath<br>outputName:$outputFilePath<br>";
colorizeKeepAplhaChannnel( $inputFilePath, $targetRed, $targetGreen, $targetBlue, $outputFilePath);
?>
<br/><br/>
Original <br/>
<img src="<?php echo $inputFilePath; ?>">
<br /><br />Colorized<br/>
<img src="<?php echo $outputFilePath; ?>">
<br />

ここに画像の説明を入力

このバリエーションは、すべての色を選択した色に変更します(黒だけでなく、単純なIFで問題を解決できます-関数で示された3行のコメントを外すと、これが達成されます)

ここに画像の説明を入力

説明のために、この場合、次の画像が使用されました (leaf.png透過性を備えた単色であるため)。 ここに画像の説明を入力

于 2014-12-15T13:43:19.260 に答える
2

SteAp からの回答を拡張して、RGBA ターゲット カラーに基づいて各ピクセルの透明度を調整できるようにする必要もありました。

また、エッジが暗いという問題も修正しました。これは、各ピクセルの色が、アルファを独自に調整するのではなく、元のアルファ レベルによって調整された結果です。

// R,G,B = 0-255 range
// A = 0.0 to 1.0 range
function colorizeBasedOnAplhaChannnel($file, $targetR, $targetG, $targetB, $targetA, $targetName ) {
    $im_src = imagecreatefrompng($file);

    $width = imagesx($im_src);
    $height = imagesy($im_src);

    $im_dst = imagecreatefrompng($file);

    // Turn off alpha blending and set alpha flag
    imagealphablending($im_dst, false);
    imagesavealpha($im_dst, true);

    // Fill transparent first (otherwise would result in black background)
    imagefill($im_dst, 0, 0, imagecolorallocatealpha($im_dst, 0, 0, 0, 127));

    for ($x=0; $x<$width; $x++) {
        for ($y=0; $y<$height; $y++) {
            $alpha = (imagecolorat( $im_src, $x, $y ) >> 24 & 0xFF);

            $col = imagecolorallocatealpha( $im_dst,
                $targetR - (int) ( 1.0 / 255.0 * (double) $targetR ),
                $targetG - (int) ( 1.0 / 255.0 * (double) $targetG ),
                $targetB - (int) ( 1.0 / 255.0 * (double) $targetB ),
                (($alpha - 127) * $targetA) + 127
            );

            if (false === $col) {
                die( 'sorry, out of colors...' );
            }

            imagesetpixel( $im_dst, $x, $y, $col );
        }
    }

    imagepng( $im_dst, $targetName);
    imagedestroy($im_dst);
}
于 2014-11-07T01:47:11.573 に答える
1

すでに述べたように、私は検索に多くの時間を費やしましたが、これまでのところ、html5 キャンバス、javascript、および ajax を使用していることがわかりました。

私が使用した唯一のライブラリはjavascriptライブラリjQueryですが、これはオプションです。プレーンな JavaScript を使用するようにコードを簡単に書き直すことができます。

使い方:

1) js は、すべてのファイルの配列を返す ajax.php からデータを取得します。

2) js はファイル リストをループchange(src,color)し、各項目に対して実行します。

3) js 関数change(src,color)はソースから画像を読み込み、その色を置き換え、img 要素を追加し#Cellて表示します (デバッグ用)。

4)関数change()も呼び出しsave(src,filename,cname)ます。5) js 関数save(src,filename,cname)は、画像データを含む ajax リクエストを送信し、ajax.php画像をサーバーに保存します。

コードは次のとおりです。

ajax.php

<?php
$r = $_REQUEST;
$act = $r['action'];
if($act == "get_all") {
    $js = "";
    $dir = getcwd()."/img/";
    $images = glob($dir."/*.png",GLOB_BRACE);
    foreach($images as $image) {
        $name = basename($image);
        $js[] = $name;
    }
    echo json_encode($js);
    die();
}
elseif($act == "save") {
    $img = $r['file'];
    $name = $r['name'];
    $color = $r['color'];
    $dir = "results/$color";
    if(!file_exists($dir) || !is_dir($dir)) mkdir($dir,777,true);
    $file = $dir."/$name";
    file_put_contents($file,file_get_contents("data://".$img));
    if(file_exists($file)) echo "Success";
    else echo $file;
    die();
}

index.php (html のみ)

<!doctype html>
        <html>
<head>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="demo.js" type="text/javascript"></script>
</head>
<body>
<div id="ctrl">
    <input type="text" id="color" value="#666666" placeholder="Color in HEX format (ex. #ff0000)" />
    <input type="text" id="cname" value="grey" placeholder="Color name (destionation dir name)" />
    <button type="button" id="doit">Change</button>
</div>
<div id="Cell">

</div>
</body>

</html>

デモ.js

$(document).ready(function() {
    $(document).on("click","#doit",function() {
        var c = $("#color");
        if(c.val() != "") {
            $("#Cell").html("");
            $.post("ajax.php",{ action: "get_all" },function(s) {
                var images = $.parseJSON(s);
                $.each(images, function(index, element) {
                    change(images[index], c.val());
                });
            });
        }
    });
});
function change(src,color) {
    var myImg = new Image();
    myImg.src = "img/"+src;
    myImg.onload = function() {
        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d");
        ctx.drawImage(myImg,0,0);
        var imgd = ctx.getImageData(0, 0, myImg.width, myImg.height);
        canvas.height = myImg.height;
        canvas.width = myImg.width;
        var new_color = HexToRGB(color);
        // console.log(imgd)
        for (i = 0; i <imgd.data.length; i += 4) {
            imgd.data[i]   = new_color.R;
            imgd.data[i+1] = new_color.G;
            imgd.data[i+2] = new_color.B;
        }
        ctx.putImageData(imgd, 0, 0);
        var newImage=new Image()
        newImage.src=canvas.toDataURL("image/png");
        $(newImage).css("margin","5px");
        $(newImage).attr('data-title',src);
        $("#Cell").append(newImage);
        var c = $("#cname");
        if(c.val() == "") c.val("temp");
        save(newImage.src,src, c.val());
    };
}
function save(src,filename,cname) {
    $.post("ajax.php", { action: "save", file: src, name: filename, color: cname },function(s) {
        console.log(s);
    })
}
function HexToRGB(Hex)
{
    var Long = parseInt(Hex.replace(/^#/, ""), 16);
    return {
        R: (Long >>> 16) & 0xff,
        G: (Long >>> 8) & 0xff,
        B: Long & 0xff
    };
}

私はそれをテストしました.420個の24x24画像を再色付けして保存するために、10秒もかかりませんでした(ローカルホスト上)(420回の非同期ajax呼び出し)。元の画像がキャッシュされると、はるかに速く終了します。画質はオリジナルのままです。

繰り返しますが、このソリューションは私の個人的な使用のためのものであるため、コードはかなり管理されておらず、改善できると確信していますが、これで問題ありません。

于 2013-07-19T07:58:58.410 に答える
0

imagetruecolortopalette($im,true, 255);醜い画像をレンダリングするため、3 番目の画像は見栄えがよくありません。

ここに画像の説明を入力

2番目の画像がきれいに見えないので、3番目の画像も美しく見えません.

コード:

<?php
unlink( dirname ( __FILE__ ) . '/newleaf.png' );
unlink( dirname ( __FILE__ ) . '/newleaf1.png' );

function LoadPNG( $imgname )
{
    $im = imagecreatefrompng ($imgname);
    imagetruecolortopalette($im,true, 255);

    imagepng($im, 'newleaf1.png' ); // save image as png

    $index = imagecolorclosest ( $im,  0,0,0 ); // GET BLACK COLOR
    imagecolorset($im,$index,0,150,255); // SET COLOR TO BLUE
    $name = basename($imgname);
    imagepng($im, 'newleaf.png' ); // save image as png
    imagedestroy($im);
}

$img = dirname ( __FILE__ ) . '/leaf.png';
LoadPNG( $img );

?>

Original
<img src="leaf.png">
<br />After make truecolortopalette($im,true, 255);
<img src="newleaf1.png">
<br />Thus..
<img src="newleaf.png">
于 2013-07-18T22:07:38.117 に答える