Как создать изображение с размытым фоном изображения в php

Я пытаюсь создать с помощью php изображение 4:3 с любым изображением, загруженным пользователем. Независимо от исходного размера изображения, я хочу заполнить фон размытой копией того же изображения.

Это код, который я использую (из István Ujj -Месарош):

function resize($source_image, $destination, $tn_w, $tn_h, $quality = 90) {

    $info = getimagesize($source_image);
    $imgtype = image_type_to_mime_type($info[2]);

    #assuming the mime type is correct
    switch ($imgtype) {
        case 'image/jpeg':
            $source = imagecreatefromjpeg($source_image);
            break;
        case 'image/gif':
            $source = imagecreatefromgif($source_image);
            break;
        case 'image/png':
            $source = imagecreatefrompng($source_image);
            break;
        default:
            die('Invalid image type.');
    }

    #Figure out the dimensions of the image and the dimensions of the desired thumbnail
    $src_w = imagesx($source);
    $src_h = imagesy($source);

    #Do some math to figure out which way we'll need to crop the image
    #to get it proportional to the new size, then crop or adjust as needed
    $x_ratio = $tn_w / $src_w;
    $y_ratio = $tn_h / $src_h;

    if (($src_w <= $tn_w) && ($src_h <= $tn_h)) {
        $new_w = $src_w;
        $new_h = $src_h;
    } elseif (($x_ratio * $src_h) < $tn_h) {
        $new_h = ceil($x_ratio * $src_h);
        $new_w = $tn_w;
    } else {
        $new_w = ceil($y_ratio * $src_w);
        $new_h = $tn_h;
    }

    $newpic = imagecreatetruecolor(round($new_w), round($new_h));
    imagecopyresampled($newpic, $source, 0, 0, 0, 0, $new_w, $new_h, $src_w, $src_h);
    $final = imagecreatetruecolor($tn_w, $tn_h);

    // This code fill with green color
    //$backgroundColor = imagecolorallocate($final, 0, 255, 0);
    //imagefill($final, 0, 0, $backgroundColor);
    imagecopy($final, $newpic, (($tn_w - $new_w)/ 2), (($tn_h - $new_h) / 2), 0, 0, $new_w, $new_h);

    // This code generates a blurred image
    # ****************************************************
    //for ($x=1; $x <=2; $x++){
    //    imagefilter($final, IMG_FILTER_GAUSSIAN_BLUR, 999);
    //} 
    //imagefilter($final, IMG_FILTER_SMOOTH,99);
    //imagefilter($final, IMG_FILTER_BRIGHTNESS, 10);  
    # ****************************************************

    if (imagejpeg($final, $destination, $quality)) {
        return true;
    }
    return false;
}

// targetFilePath contains the folder an filename
resize($targetFilePath,$targetFilePath,640,480,90);

Результат выглядит следующим образом: мой результат до сих пор

Что мне нужно? Результат, на который я надеюсь

Пожалуйста, любая идея будет приветствоваться. Заранее спасибо!!!


person mhuenchul    schedule 03.07.2018    source источник
comment
Можете ли вы использовать Imagick? php.net/manual/en/imagick.blurimage.php   -  person Lee Kowalkowski    schedule 04.07.2018
comment
... или php.net/manual/en/function.imagefilter.php?   -  person Lee Kowalkowski    schedule 04.07.2018
comment
Спасибо @LeeKowalkowski, но я не могу использовать класс Imagick на рабочем сервере. С другой стороны, как вы можете видеть в приведенном выше коде, я использую фильтр изображений, но моя проблема заключается в том, как соединить 2 изображения вместе.   -  person mhuenchul    schedule 04.07.2018


Ответы (3)


Я улучшил код @mhuenchul, и теперь он работает независимо от размера изображения.

function image_blurred_bg($image, $dest, $width, $height){
try{
    $info = getimagesize($image);
} catch (Exception $e){
    return false;
}

$mimetype = image_type_to_mime_type($info[2]);
switch ($mimetype) {
    case 'image/jpeg':
        $image = imagecreatefromjpeg($image);
        break;
    case 'image/gif':
        $image = imagecreatefromgif($image);
        break;
    case 'image/png':
        $image = imagecreatefrompng($image);
        break;
    default:
        return false;
}

$wor = imagesx($image);
$hor = imagesy($image);
$back = imagecreatetruecolor($width, $height);

$maxfact = max($width/$wor, $height/$hor);
$new_w = $wor*$maxfact;
$new_h = $hor*$maxfact;
imagecopyresampled($back, $image, -(($new_w-$width)/2), -(($new_h-$height)/2), 0, 0, $new_w, $new_h, $wor, $hor);

// Blur Image
for ($x=1; $x <=40; $x++){
    imagefilter($back, IMG_FILTER_GAUSSIAN_BLUR, 999);
}
imagefilter($back, IMG_FILTER_SMOOTH,99);
imagefilter($back, IMG_FILTER_BRIGHTNESS, 10);

$minfact = min($width/$wor, $height/$hor);
$new_w = $wor*$minfact;
$new_h = $hor*$minfact;

$front = imagecreatetruecolor($new_w, $new_h);
imagecopyresampled($front, $image, 0, 0, 0, 0, $new_w, $new_h, $wor, $hor);

imagecopymerge($back, $front,-(($new_w-$width)/2), -(($new_h-$height)/2), 0, 0, $new_w, $new_h, 100);

// output new file
imagejpeg($back,$dest,90);
imagedestroy($back);
imagedestroy($front);

return true;
}
person Appoodeh    schedule 26.11.2019
comment
Вы должны добавить больше пояснений о том, что и почему вы изменили. Это не сильно поможет, если кто-то, кто найдет этот вопрос, не поймет, как вы улучшили принятый ответ. - person Michal Hynčica; 27.11.2019
comment
Принятый ответ работал неправильно, если высота изображения больше ширины, поэтому я удалил все ненужные строки кода и изменил математическое уравнение, которое вычисляет новый размер и проверяет его на размере нескольких изображений. - person Appoodeh; 27.11.2019
comment
Спасибо @Appoodeh Ваши улучшения в коде потрясающие! Ваш код работает очень хорошо! - person mhuenchul; 27.11.2019

Существует множество подходов, но я бы посоветовал вам использовать imagecopymerge вместо imagecopy. Вы указываете координаты пункта назначения и источника, а также размер источника и вуаля!

Однако обратите внимание, что таким образом вы не сохраните прозрачность (для GIF/PNG, если она присутствует). Для этого взгляните на этот комментарий Сины Салек в документации по PHP: ПОДДЕРЖКА АЛЬФА-КАНАЛОВ PNG для imagecopymerge().

Но я бы согласился с @LeeKowalkowski — в конечном итоге вам следует подумать о переходе на ImageMagick по многим причинам — прежде всего качество изображения.

РЕДАКТИРОВАТЬ: я забыл упомянуть перед слиянием установить прозрачный цвет (расширенный холст) с помощью imagecolortransparent . Затем комментарий Сины Салека в документации по PHP (ссылка выше).

person Philip Michaylov    schedule 04.07.2018

Хорошо, я сделал свою работу и больше изучил команды php image. Я написал решение, которое работает очень хорошо.

<?php

$image = "01.jpg";

image_web($image, 700, 525); // I need final images 700x525 (4:3)

echo '<img src="00.jpg"/>';

function image_web($image, $width, $height){ // Get the image source and the final desire dimensions
    $info = getimagesize($image);
    //$mimetype = $info['mime']; // other way to get mimetype
    $mimetype = image_type_to_mime_type($info[2]);
    $allowTypes = array('image/jpeg','image/png','image/gif');    
    if(in_array($mimetype, $allowTypes)){
        switch ($mimetype) {
            case 'image/jpeg':
                $image = imagecreatefromjpeg($image);
                break;
            case 'image/gif':
                $image = imagecreatefromgif($image);
                break;
            case 'image/png':
                $image = imagecreatefrompng($image);
                break;
            default:
                die('Invalid image type.');
        }
    } else {
        echo 'Is not a image';
    }
    $image2 = $image; // Save a copy to be used for front image
    $wor = imagesx($image); // Get original image width
    $hor = imagesy($image); // Get original image height
    if ($hor >= $wor){ // If is vertical*******************************************************************************************************
        if ($wor >= $width){ // If image source is bigger than final desire dimensions
            $hcenter = ($hor/2)-($height/2); // center image source in height
            $back = imagecreatetruecolor(round($width), round($height));
            imagecopyresampled($back, $image, 0, -$hcenter, 0, 0, $wor, $hor, $wor, $hor);
        } else { // If image source is not bigger than final desire dimensions
            $hcenter = ($hor/2)-($height/2); // center image source in height
            $hnu = ($hor*$width)/$wor;
            $back = imagecreatetruecolor(round($width), round($height));
            imagecopyresampled($back, $image, 0, -$hcenter, 0, 0, $width, $hnu, $wor, $hor);
        }
    } else { // If is portrait rectangular****************************************************************************************************  
        $ratio = $wor/$hor;
        if($ratio > 1.3333333){ // If is portrait larger than 4:3       
            $wnu = ($wor*$height)/$hor;
            $wcenter = ($wnu/2)-($width/2); // center image in width
            $back = imagecreatetruecolor(round($width), round($height));
            imagecopyresampled($back, $image, -$wcenter, 0, 0, 0, $wnu, $height, $wor, $hor); 
        } else { // If portrait is not larger than 4:3
            $hnu = ($wor*$height)/$hor;
            $hcenter = ($hnu/2)-($height/2); // center image source in height
            $back = imagecreatetruecolor(round($width), round($height));
            imagecopyresampled($back, $image, 0, -$hcenter, 0, 0, $width, $hnu, $wor, $hor); 
        }
    }
    // Blur Image
    for ($x=1; $x <=40; $x++){
        imagefilter($back, IMG_FILTER_GAUSSIAN_BLUR, 999);
    } 
    imagefilter($back, IMG_FILTER_SMOOTH,99);
    imagefilter($back, IMG_FILTER_BRIGHTNESS, 10);
    // Getting the dimensions of the image
    $src_w = imagesx($image2);
    $src_h = imagesy($image2);
    // Do some math to figure out which way we'll need to crop the image
    // to get it proportional to the new size, then crop or adjust as needed
    $x_ratio = $width / $src_w;
    $y_ratio = $height / $src_h;
    if (($src_w <= $width) && ($src_h <= $height)) {
        $new_w = $src_w;
        $new_h = $src_h;
    } elseif (($x_ratio * $src_h) < $height) {
        $new_h = ceil($x_ratio * $src_h);
        $new_w = $width;
    } else {
        $new_w = ceil($y_ratio * $src_w);
        $new_h = $height;
    }
    $front = imagecreatetruecolor(round($new_w), round($new_h));
    imagecopyresampled($front, $image2, 0, 0, 0, 0, $new_w, $new_h, $src_w, $src_h);
    if ($new_h >= $new_w){ // If is vertical image
        $wctr = ($new_w/2)-($width/2);
        imagecopymerge($back, $front,-$wctr, 0, 0, 0, $new_w, $new_h, 100);
    } else { // if is portrait
        $hctr = ($new_h/2)-($height/2);
        imagecopymerge($back, $front,0, -$hctr, 0, 0, $new_w, $new_h, 100);
    }
    // output new file
    imagejpeg($back,'00.jpg',90);
    imagedestroy($back);
    imagedestroy($front);
    //*********************************************************************************
    /**
    Do other actions like send ajax responses, save in database, etc
    **/
}

?>
person mhuenchul    schedule 06.07.2018