Zain Shabir
Zain Shabir

Reputation: 75

Compress png and jpg Images during upload in PHP OOP


I have E-commerce website, In Users system, When user upload/update his/her profile picture then It should be compressed like: If real image size is 1MB then after uploading It should compress and save with 50kb minimum and 200kb maximum, I am doing it like this, Here is my code:

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);

}

You can see my compressImage() function, If i write imagejpeg() function then It compresses fine but in png (transparent) image, It saves with black background. So, I replaced with imagepng() function, But It is not compressing the image, It is increasing the size of the image after saving to Database, like my image size was 2 MB, When I upload then It saves with size of 11 MB. I don't know what happened.
To be clear: I just want to compress png and jpg images and transparent images should not save with black background. Please help me

Upvotes: 0

Views: 1243

Answers (2)

Miroslav Ćurčić
Miroslav Ćurčić

Reputation: 146

If your goal is to compress images you must save them as JPG. PNG is lossless format so there is no room for saving space as PNG.

Unfortunately JPG cannot preserve transparency. Transparent pixels must be colored with some color.

I suggest you to draw white rectangle over whole image and then put your image over that, like:

$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

Upvotes: 1

wawa
wawa

Reputation: 5066

I haven't tested it, but as far as I recall you simply need to change imagealphablending($image, false); to imagealphablending($image, true);, however potentially you'll have to explicitly set a transparent background like this: https://stackoverflow.com/a/2611911/2989952

However, this doesn't really compress your images! You'll need some external programs to achieve what you want.

JPEG:

PNG:

If you're using Symfony as a base, you can easily use them thanks to LiipImagineBundle, if not you can take a look at how they are doing it.

Furthermore I'd suggest using webp which works well as a replacement for both JPEG as well as PNG images. For now you'll need both .webp as well as the old formats, as not all browsers support webp yet. You can conditionally serve images in Nginx using for example:

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

server {
    [...]

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

Upvotes: 1

Related Questions