4

I am trying to compress & resize my images using the php GD library. Nearly every answer on SO and everywhere else is the same, but for my solution, the PNG's are not being correctly transformed, and some jpg's are giving bizarre results.

This is the code I am using:

public function resizeImages() {
    ini_set('max_execution_time', 0);

    //Initial settings, Just specify Source and Destination Image folder.
    $ImagesDirectory    = FCPATH . 'design/img/test/'; //Source Image Directory End with Slash
    $DestImagesDirectory    = FCPATH . 'design/img/test/thumb/'; //Destination Image Directory End with Slash
    $NewImageWidth      = 150; //New Width of Image
    $NewImageHeight     = 150; // New Height of Image
    $Quality        = 90; //Image Quality

    //Open Source Image directory, loop through each Image and resize it.
    if($dir = opendir($ImagesDirectory)){
        while(($file = readdir($dir))!== false){
            $imagePath = $ImagesDirectory.$file;
            $destPath = $DestImagesDirectory.$file;
            $checkValidImage = @getimagesize($imagePath);

            if(file_exists($imagePath) && $checkValidImage) //Continue only if 2 given parameters are true
            {
                //Image looks valid, resize.
                if (resize_image($imagePath,$destPath,$NewImageWidth,$NewImageHeight,$Quality))
                {
                    echo $file.' resize Success!<br />';
                    /*
                    Now Image is resized, may be save information in database?
                    */

                } else {
                    echo $file.' resize Failed!<br />';
                }
            }
        }
        closedir($dir);
    }
}

and the resize_image function looks like this:

function resize_image($SrcImage,$DestImage, $MaxWidth,$MaxHeight,$Quality)
    {
        list($iWidth,$iHeight,$type)    = getimagesize($SrcImage);
        $ImageScale             = min($MaxWidth/$iWidth, $MaxHeight/$iHeight);
        $NewWidth               = ceil($ImageScale*$iWidth);
        $NewHeight              = ceil($ImageScale*$iHeight);
        $NewCanves              = imagecreatetruecolor($NewWidth, $NewHeight);

        $imagetype = strtolower(image_type_to_mime_type($type));

        switch($imagetype)
        {
            case 'image/jpeg':
                $NewImage = imagecreatefromjpeg($SrcImage);
                break;
            case 'image/png':
                $NewImage = imagecreatefrompng($SrcImage);
                break;
            default:
                return false;
        }

        //allow transparency for pngs
        imagealphablending($NewCanves, false);
        imagesavealpha($NewCanves, true);

        // Resize Image
        if(imagecopyresampled($NewCanves, $NewImage,0, 0, 0, 0, $NewWidth, $NewHeight, $iWidth, $iHeight))
        {
            switch ($imagetype) {
                case 'image/jpeg':
                    if(imagejpeg($NewCanves,$DestImage,$Quality))
                    {
                        imagedestroy($NewCanves);
                    }
                    break;
                case 'image/png':
                    if(imagepng($NewCanves,$DestImage,$Quality))
                    {
                        imagedestroy($NewCanves);
                    }
                    break;
                default:
                    return false;
            }
            return true;
        }
    }

Every single png is not working, it just returns a file with 0 bytes and "file type is not supported", even though the type is recognized as .PNG in Windows...

Some JPG's return a weird result as well, see the following screenshot which indicates my issues regarding png's and some jpg's: faulty images

Dennis
  • 3,044
  • 2
  • 33
  • 52

1 Answers1

1

1) Do not use getimagesize to verify that the file is a valid image, to mention the manual:

Do not use getimagesize() to check that a given file is a valid image. Use a purpose-built solution such as the Fileinfo extension instead.

$checkValidImage = exif_imagetype($imagePath);
if(file_exists($imagePath) && ($checkValidImage == IMAGETYPE_JPEG || $checkValidImage == IMAGETYPE_PNG))

2) While imagejpeg() accepts quality from 0 to 100, imagepng() wants values between 0 and 9, you could do something like that:

if(imagepng($NewCanves,$DestImage,round(($Quality/100)*9)))

3) Using readdir () you should skip the current directory . and the parent..

    while(($file = readdir($dir))!== false){
        if ($file == "." || $file == "..")
            continue;

edit

Point 2 is particularly important, imagepng () accepts values greater than 9 but then often fails with error in zlib or libpng generating corrupt png files.

I tried resizing some png and jpeg and I didn't encounter any problems with these changes.

Alex
  • 3,264
  • 1
  • 25
  • 40