2013-07-18 6 views
11

Я много искал, и я нашел только несколько решений (в google и stackoverflow, поэтому, пожалуйста, не отмечайте это как дубликат, если нет действительно повторяющегося вопроса), но проблемы сложны кромки. Есть ли правильный способ изменения базового цвета, скажем, черного png-изображения с прозрачным фоном, но для сохранения мягких краев?Php - заменить базовый цвет прозрачного изображения png

Это пример изображения:

enter image description here

Я хочу, чтобы выглядеть следующим образом:

enter image description here

но решения я нашел дать мне этот:

enter image description here

Поскольку я буду использовать это на своем локальном хосте, только для личного использования, любая php-библиотека, которая могла бы помочь в достижении этого, ценится.

UPDATE:

Это функция, которая дает мне 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.

EDIT 2:

Я нашел интересный подход с использованием html5 холст и JavaScript здесь: http://users7.jabry.com/overlord/mug.html

Может быть кто-то может иметь представление о том, как перевести это в PHP, если вообще возможно.

НОВОЕ РЕШЕНИЕ

В ответах

+0

вы можете разместить код для решения, что привело к 3-изображение? – Maximus2012

+0

@ Maximus2012 да, пожалуйста, дайте мне мгновение, я должен найти его, потому что я пробовал много других, но безуспешно. –

+1

@ Maximus2012 обновил мой вопрос. –

ответ

14

Этот код не иллюстрировать эту проблему, но преобразовывает цвета, как это:

enter image description here

использует альфа-канал изображения, которое определяет окраску. Для других результатов, просто поиграйте с 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"> 
+1

Есть более темные края, если я прав (маленькое изображение, поэтому я не могу видеть отлично), но это, безусловно, лучшее решение на основе php. Спасибо за внимание, я приму этот ответ. –

0

Третье изображение не выглядит хорошо, потому что imagetruecolortopalette($im,true, 255); делает некрасивый изображение:

enter image description here

Поскольку второе изображение не хорошо выглядеть, третий тоже не может выглядеть красиво.

Код:

<?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"> 
+0

Как я. У вас есть решение для лучшего рендеринга? –

+0

@NikolaR. К сожалению, я не могу предоставить решение прямо сейчас. Слишком поздно ... Наверное, завтра. Интересный случай ... – SteAp

+1

Спасибо, я ценю! –

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> 

demo.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 асинхронных вызовов aynax). Когда исходные изображения кэшируются, он заканчивается намного быстрее. Качество изображения остается прежним.

Опять же, это решение для моего личного использования, поэтому код довольно неуправляемый, и я уверен, что его можно улучшить, но здесь вы идете - как есть, он работает.

2

Расширение на answer from 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); 
} 
2

Использование SteAp «s принял код в качестве отправной точки (так как с ним я не удается достичь прозрачности, просто белый фон), я адаптированной указанный код и результат:

<?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 /> 

enter image description here

это изменение меняет все цвета выбрали цвет (не только черный, простой IF может решить эту проблему - раскомментируйте 3 указаны строки в функции, и вы добьетесь этого)

enter image description here

В иллюстративных целях, в этом случае, следующий образ был использован (потому что leaf.png монохроматичен, с прозрачностью): enter image description here

Смежные вопросы