Zostałem poprowadzony do tego wątku, kiedy potrzebowałem wymieszać dwa obrazy w GD. Wygląda na to, że nie ma kodu specjalnie dla tego, więc zostawię to tutaj dla przyszłych użytkowników tej strony.
To jest rozwidlenie z odpowiedzi colivier
, która obsługuje wielokrotne mieszanie dwóch obrazów.
Te dwa obrazy nie muszą mieć tego samego rozmiaru, ALE obraz nakładki zostanie przeskalowany i przycięty do rozmiaru dolnej warstwy. Zrobiłem funkcję pomocniczą fit
, aby to zrobić, ale nie przejmuj się tym.
imagecolorat
zwraca kolor bazowy, nawet z plikami PNG z przezroczystością. Oznacza to, że 50% czarny (widoczny jako (128, 128, 128)) zostanie zwrócony jako (0, 0, 0, 64) 64 będący wartością alfa. Ten kod bierze pod uwagę przezierność i konwertuje przezroczyste kolory do widocznych wartości kolorów.
// bottom layer
$img1 = imagecreatefromjpeg(realpath(__DIR__.'/profilePic.jpg'));
// top layer
$img2 = imagecreatefrompng(realpath(__DIR__.'/border2.png'));
imagealphablending($img2, false);
imagesavealpha($img2, true);
$imagex = imagesx($img1);
$imagey = imagesy($img1);
$imagex2 = imagesx($img2);
$imagey2 = imagesy($img2);
// Prereq: Resize img2 to match img1, cropping beyond the aspect ratio
$w1 = max(min($imagex2, $imagex), $imagex);
$h1 = max(min($imagey2, $imagey), $imagey);
$w_using_h1 = round($h1 * $imagex2/$imagey2);
$h_using_w1 = round($w1 * $imagey2/$imagex2);
if ($w_using_h1 > $imagex) {
fit($img2, $imagex, $imagey, 'HEIGHT', true);
}
fit($img2, $imagex, $imagey, 'WIDTH', true);
// Actual multiply filter
for ($x = 0; $x < $imagex; ++$x) {
for ($y = 0; $y < $imagey; ++$y) {
$rgb1 = imagecolorat($img1, $x, $y);
$rgb2 = imagecolorat($img2, $x, $y);
$idx1 = imagecolorsforindex($img1, $rgb1);
$idx2 = imagecolorsforindex($img2, $rgb2);
// Shift left 8, then shift right 7
// same as multiply by 256 then divide by 128
// approximate multiply by 255 then divide by 127
// This is basically multiply by 2 but, expanded to show that
// we are adding a fraction of white to the translucent image
// $adder = ($idx2['alpha'] <<8>> 7);
$adder = ($idx2['alpha'] << 1);
$rmul = min(255, $idx2['red'] + $adder);
$gmul = min(255, $idx2['green'] + $adder);
$bmul = min(255, $idx2['blue'] + $adder);
$color_r = floor($idx1['red'] * $rmul/255);
$color_g = floor($idx1['green'] * $gmul/255);
$color_b = floor($idx1['blue'] * $bmul/255);
$newcol = imagecolorallocatealpha($img1, $color_r, $color_g, $color_b, 0);
imagesetpixel($img1, $x, $y, $newcol);
}
}
imagejpeg($img1, __DIR__.'/out.jpg');
/**
* Fits an image to a $w x $h canvas
*
* @param type $w Target width
* @param type $h Target height
* @param int $fit_which Which dimension to fit
* @param bool $upscale If set to true, will scale a smaller image to fit the given dimensions
* @param bool $padded If set to true, will add padding to achieve given dimensions
*
* @return Image object
*/
function fit(&$img, $w, $h, $fit_which = 'BOTH', $upscale = false, $padded = true) {
if (!in_array($fit_which, array('WIDTH', 'HEIGHT', 'BOTH'))) {
$fit_which = 'BOTH';
}
$w0 = imagesx($img);
$h0 = imagesy($img);
if (!$upscale && $w0 <= $w && $h0 <= $h)
return $this;
if ($padded) {
$w1 = max(min($w0, $w), $w);
$h1 = max(min($h0, $h), $h);
}
else {
$w1 = min($w0, $w);
$h1 = min($h0, $h);
}
$w_using_h1 = round($h1 * $w0/$h0);
$h_using_w1 = round($w1 * $h0/$w0);
// Assume width, crop height
if ($fit_which == 'WIDTH') {
$w2 = $w1;
$h2 = $h_using_w1;
}
// Assume height, crop width
elseif ($fit_which == 'HEIGHT') {
$w2 = $w_using_h1;
$h2 = $h1;
}
elseif ($fit_which == 'BOTH') {
if (!$padded) {
$w2 = $w = min($w, $w_using_h1);
$h2 = $h = min($h, $h_using_w1);
}
else {
// Extend vertically
if ($h_using_w1 <= $h) {
$w2 = $w1;
$h2 = $h_using_w1;
}
// Extend horizontally
else {
$w2 = $w_using_h1;
$h2 = $h1;
}
}
}
$im2 = imagecreatetruecolor($w, $h);
imagealphablending($im2, true);
imagesavealpha($im2, true);
$transparent = imagecolorallocatealpha($im2, 255, 255, 255, 127);
imagefill($im2, 0, 0, $transparent);
imagealphablending($img, true);
imagesavealpha($img, true);
// imagefill($im, 0, 0, $transparent);
imagecopyresampled($im2, $img, ($w - $w2)/2, ($h - $h2)/2, 0, 0, $w2, $h2, $w0, $h0);
$img = $im2;
}
Dobrze, dziękuję bardzo! Wydaje się, że zapewnia to dokładną funkcjonalność jako filtr wielokrotny Photoshopa. – heintore
Użyłem tego w innym przykładzie, ale stwierdziłem, że ta implementacja jest naprawdę powolna. Najszybszym sposobem byłoby użycie filtru obrazu z IMG_FILTER_COLORIZE. Najpierw odwróć docelową kolorową wartość RGB, a następnie odwróć obraz za pomocą filtru obrazu ($ image, IMG_FILTER_NEGATE), a następnie zastosuj odwrócony kolor do odwróconego obrazu, a następnie odwróć obraz ponownie. Zobacz tutaj http://stackoverflow.com/questions/26005991/php-gd-multiply-image-colors-with-tint-color/26250684#26250684 –
Działa świetnie! Zaktualizowałem go trochę, aby pomnożyć dwa obrazy, a nie tylko obraz z kolorem: http://codepad.org/BSawY5ex –