Сжатие изображений PNG и JPG во время загрузки в ООП PHP - PullRequest
0 голосов
/ 19 октября 2019


У меня есть сайт электронной коммерции, в системе «Пользователи», когда пользователь загружает / обновляет свое изображение профиля, оно должно быть сжато следующим образом: если реальный размер изображения составляет 1 МБ, то после загрузки оно должно быть сжато и сохранено с размером 50 КБ. минимум и максимум 200 КБ, я делаю это так, Вот мой код:

public function updateProfilePic($file, $userid) {
    $filename = $file['user_img']['name'];
    $filetmp = $file['user_img']['tmp_name'];
    $valid_ext = array('png', 'jpeg', 'jpg');
    $location = "user/profilepic/" . $filename;
    $file_extension = pathinfo($location, PATHINFO_EXTENSION);
    $file_extensionstr = strtolower($file_extension);

    if(!empty($filename)){
        if (in_array($file_extensionstr, $valid_ext)) {
            //Here i am compressing image
            $this->compressImage($filetmp, $location, 9);
            return $this->updateProfilePicture($filename, $userid);
        } else {
            $msg = '<div class="alert alert-danger" role="alert">Invalid file type. You can upload only:-' . implode(', ', $valid_ext) . '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>';
            return $msg;
        }
    } else {
        $msg = '<div class="alert alert-danger" role="alert">Please upload your profile picture.<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>';
        return $msg;
    }
}

public function updateProfilePicture($filename, $userid){
    $update = "UPDATE users SET user_img = '$filename' WHERE user_id = '$userid'";
    $result = $this->db->update($update);
    if($result){
        $msg = '<div class="alert alert-success" role="alert">Profile picture uploaded successfully <a href="profile.php">Go back</a><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>';
        return $msg;
    } else {
        $msg = '<div class="alert alert-danger" role="alert">Error while uploading profile picture. Pleas try again!<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>';
        return $msg;
    }
}

public function compressImage($source, $destination, $quality) {
    $info = getimagesize($source);

    if ($info['mime'] == 'image/jpeg'){
        $image = imagecreatefromjpeg($source);
    } elseif ($info['mime'] == 'image/png'){
        $image = imagecreatefrompng($source);
        imagealphablending($image, false);
        imagesavealpha($image, true);
    }

    imagepng($image, $destination, $quality);

}

Вы можете увидеть мою compressImage() функцию, если я напишу imagejpeg()Функция затем сжимает нормально, но в PNG (прозрачное) изображение, сохраняет с черным фоном. Итак, я заменил на imagepng() функцию, но она не сжимает изображение, она увеличивает размер изображения после сохранения до Database, как мой размер изображения был 2 MB, когда я загружаю, то сохраняет с размером11 MB. Я не знаю, что произошло.
Для ясности: Я просто хочу сжать изображения в формате png и jpg, а прозрачные изображения не следует сохранять на черном фоне. Пожалуйста, помогите мне

Ответы [ 2 ]

1 голос
/ 19 октября 2019

Если ваша цель - сжать изображения, вы должны сохранить их в формате JPG. PNG - это формат без потерь, поэтому нет места для экономии места как PNG.

К сожалению, JPG не может сохранить прозрачность. Прозрачные пиксели должны быть окрашены в какой-то цвет.

Я предлагаю вам нарисовать белый прямоугольник на всем изображении, а затем наложить на него свое изображение, например:

$image= $info['mime'] == 'image/png'         // open origin image
  ? imagecreatefrompng($source)
  : imagecreatefromjpeg($source);  
$target= imagecreatetruecolor($width, $height);           // open empty image with same size
$whitecolor= imagecolorallocate($target, 255, 255, 255);
imagefilledrectangle($target, 0,0, $width, $height, $whitecolor); // fill background
imagecopy($target, $image, $width,$height, 0,0, $width,$height);  // copy image over target
imagejpeg($target, $source);       // save as jpg
1 голос
/ 19 октября 2019

Я не проверял его, но, насколько я помню, вам просто нужно изменить imagealphablending($image, false); на imagealphablending($image, true);, однако, возможно, вам придется явно установить прозрачный фон, например: https://stackoverflow.com/a/2611911/2989952

Однако это не сжимает ваши изображения! Вам понадобятся некоторые внешние программы для достижения того, что вы хотите.

JPEG:

PNG:

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

Кроме того, я бы предложил использовать webp , который хорошо заменит как JPEG, так и PNG изображения. На данный момент вам понадобится как .webp, так и старые форматы, так как не все браузеры поддерживают webp . Вы можете условно обслуживать изображения в Nginx, например:

map $http_accept $img_suffix {
  "~*webp"  ".webp";
  "~*jxr"   ".jxr";
}

server {
    [...]

    location ~* \.(?:jpg|jpeg|png)$ {
        try_files   $uri$img_suffix $uri =404;
    }
}
...