0

I have inherited a function which resizes images. It works well in most cases, but for some reason, in some cases the result of resizing the image is totally different than the image initially contained. The function is as follows:

function image_resize($source, $destination, $width, $height, $resizeMode='fit', $type = 'jpeg', $options = array()) {


    $defaults = array(
        'output' => 'file',
        'isFile' => true,
        'quality' => '100',
        'preserveAnimation' => false,
        'offsetTop' => 0,
        'offsetLeft' => 0,
        'offsetType' => 'percent'
    );

    foreach ($defaults as $k => $v) {
        if (!isset($options[$k])) {
            $options[$k] = $v;
        }
    }

    if ($options['isFile']) {
        $image_info = getimagesize($source);
        $image = null;
        switch ($image_info[2]) {
            case IMAGETYPE_JPEG:
                $image = imagecreatefromjpeg($source);
                break;
            case IMAGETYPE_PNG:
                $image = imagecreatefrompng($source);
                break;
            case IMAGETYPE_GIF:
                $image = imagecreatefromgif($source);
                break;
            case IMAGETYPE_BMP:
                $image = imagecreatefromwbmp($source);
                break;
            default :
                return false;
        }
    } else {
        $image = imagecreatefromstring($source);
    }

    //we have an image resource
    $iwidth = imagesx($image);
    $iheight = imagesy($image);

    //We need $width and $height for this call
    if (QM::isAcceptableProfilePhotoSize($width, $height) == false)
    {
        throw new Exception("Size of ".$width."x".$height." is not supported");
    }

    //determine ratios
    $wratio = $width / $iwidth;
    $hratio = $height / $iheight;
    $mratio = min(array($wratio, $hratio));

    $rimage = null;

    switch ($resizeMode) {
        case 'fit':
            $rimage = imagecreatetruecolor($iwidth * $mratio, $iheight * $mratio);
            $image = imagecopyresampled($rimage, $image, 0, 0, 0, 0, $iwidth * $mratio, $iheight * $mratio, $iwidth, $iheight);
            break;
        case 'crop':
            $rratio = $width / $height;


            if ($rratio < 1) {
                $nwidth = $iwidth;
                $nheight = $iwidth * 1/$rratio;
                if ($nheight>$iheight) {
                    $nwidth = $nwidth*$iheight/$nheight;
                    $nheight = $iheight;
                }
            } else {
                $nwidth = $iheight*$rratio;
                $nheight = $iheight;
                if ($nwidth>$iwidth) {
                    $nheight = $nheight*$iwidth/$nwidth;
                    $nwidth = $iwidth;
                }
            }
            switch ($options['offsetType']) {
                case 'percent':
                    $sx = ($iwidth-$nwidth)*$options['offsetLeft']/100;
                    $sy = ($iheight-$nheight)*$options['offsetTop']/100;
                    break;
                default :
                    return false;
            }

            $rimage = imagecreatetruecolor($width, $height);
            $image = imagecopyresampled($rimage, $image, 0, 0, $sx, $sy, $width, $height, $nwidth, $nheight);
            break;
        default :
            return false;
            break;
    }

    if (!is_writeable(dirname($destination))) {
        throw new Exception(getcwd(). "/" .dirname($destination)." is not writeable");
    }

    switch ($options['output']) {
        case 'file':
            switch ($image_info[2]) {
                case IMAGETYPE_JPEG:
                    return imagejpeg($rimage, $destination, $options['quality']);
                case IMAGETYPE_PNG:
                    return imagepng($rimage, $destination, 0);
                case IMAGETYPE_GIF:
                    return imagegif($rimage, $destination);
                case IMAGETYPE_BMP:
                    return imagejpeg($rimage, $destination, $options['quality']);
                default :
                    return false;
                    break;
            }
            return true;
            break;
        default :
            return false;
            break;
    }
}

Example image causing the problem: enter image description here

This image is successfully uploaded, but when I try to resize it, the resulting image is:

enter image description here

I call the function this way:

image_resize($ofile, $cfile, $width, $height, 'crop', 'jpeg');

Where $ofile is the original file, $cfile is the planned destination, $width is the desired width (90 in this case), $height is the desired height (90 in this case), 'crop' is the selected strategy and 'jpeg' is a certain $type value, which is unused in the function (as I have mentioned, I have inherited the code). Also, the only example where the problem could be reproduced is the attached image, which is a png, other png files are uploaded correctly, so I do not understand the cause of the issue and do not know how to solve it. Can anybody describe the cause of the problem? I have searched and experimented for a long while without achieving success.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • http://stackoverflow.com/questions/24430176/trouble-cropping-and-resizing-image/24431514#24431514 – TBI Oct 10 '14 at 14:04
  • Possibly related to transparency http://stackoverflow.com/questions/279236/how-do-i-resize-pngs-with-transparency-in-php ? – Danack Oct 10 '14 at 17:42

1 Answers1

1

i tried your "image_resize" function with your bird picture, and it works perfectly fine on my computer, whether i set the source image to jpg or png, it works as expected :

resized bird

However why not choosing "fit" instead of "crop" like so :

image_resize($ofile, $cfile, $width = 90, $height = 90, 'fit', 'jpeg');

Edit: based on other people's issues about getting black image after resizing PNG, this would be the correction:

function image_resize($source, $destination, $width, $height, $resizeMode='fit', $type = 'jpeg', $options = array()) {

    $defaults = array(
        'output' => 'file',
        'isFile' => true,
        'quality' => '100',
        'preserveAnimation' => false,
        'offsetTop' => 0,
        'offsetLeft' => 0,
        'offsetType' => 'percent'
    );

    foreach ($defaults as $k => $v) {
        if (!isset($options[$k])) {
            $options[$k] = $v;
        }
    }

    if ($options['isFile']) {
        $image_info = getimagesize($source);
        $image = null;
        switch ($image_info[2]) {
            case IMAGETYPE_JPEG:
                $image = imagecreatefromjpeg($source);
                break;
            case IMAGETYPE_PNG:
                $image = imagecreatefrompng($source);
                break;
            case IMAGETYPE_GIF:
                $image = imagecreatefromgif($source);
                break;
            case IMAGETYPE_BMP:
                $image = imagecreatefromwbmp($source);
                break;
            default :
                return false;
        }   
    } else {
        $image = imagecreatefromstring($source);
    }   

    //we have an image resource
    $iwidth = imagesx($image);
    $iheight = imagesy($image);

    //determine ratios
    $wratio = $width / $iwidth;
    $hratio = $height / $iheight;
    $mratio = min(array($wratio, $hratio));

    $rimage = null;

    switch ($resizeMode) {
        case 'fit':
            $rimage = imagecreatetruecolor($iwidth * $mratio, $iheight * $mratio);
            imagealphablending( $rimage, false );
            imagesavealpha( $rimage, true ); 
            $image = imagecopyresampled($rimage, $image, 0, 0, 0, 0, $iwidth * $mratio, $iheight * $mratio, $iwidth, $iheight);
            break;
        case 'crop':
            $rratio = $width / $height;


            if ($rratio < 1) {
                $nwidth = $iwidth;
                $nheight = $iwidth * 1/$rratio;
                if ($nheight>$iheight) {
                    $nwidth = $nwidth*$iheight/$nheight;
                    $nheight = $iheight;
                }
            } else {
                $nwidth = $iheight*$rratio;
                $nheight = $iheight;
                if ($nwidth>$iwidth) {
                    $nheight = $nheight*$iwidth/$nwidth;
                    $nwidth = $iwidth;
                }
            }
            switch ($options['offsetType']) {
                case 'percent':
                    $sx = ($iwidth-$nwidth)*$options['offsetLeft']/100;
                    $sy = ($iheight-$nheight)*$options['offsetTop']/100;
                    break;
                default :
                    return false;
            }

            $rimage = imagecreatetruecolor($width, $height);
            imagealphablending( $rimage, false );
            imagesavealpha( $rimage, true );
            $image = imagecopyresampled($rimage, $image, 0, 0, $sx, $sy, $width, $height, $nwidth, $nheight);
            break;
        default :
            return false;
            break;
    }

    if (!is_writeable(dirname($destination))) {
        throw new Exception(getcwd(). "/" .dirname($destination)." is not writeable");
    }

    switch ($options['output']) {
        case 'file':
            switch ($image_info[2]) {
                case IMAGETYPE_JPEG:
                    return imagejpeg($rimage, $destination, $options['quality']);
                case IMAGETYPE_PNG:
                    return imagepng($rimage, $destination, 0);
                case IMAGETYPE_GIF:
                    return imagegif($rimage, $destination);
                case IMAGETYPE_BMP:
                    return imagejpeg($rimage, $destination, $options['quality']);
                default :
                    return false;
                    break;
            }
            return true;
            break;
        default :
            return false;
            break;
    }
}
Yoric
  • 1,761
  • 2
  • 13
  • 15
  • 'fit' deforms the picture. 'crop' was chosen for a reason. Were you successfully running it with 'crop'? – Lajos Arpad Oct 10 '14 at 15:12
  • yes had no issue with "crop" parameter. (but it crops bird's tail on the right edge, that's why i prefer "fit", and i don't get deformed picture, image_resize automatically calculate the right width/height ratio) – Yoric Oct 10 '14 at 15:16
  • By deformation I mean that the width/height ratio is deformed. Naturally, the width of this picture is larger than its height, therefore by making them equal we are making it thinner in width, thus we are deforming the picture. Cropping keeps the correct looks of the picture, but it has the problem of cutting parts out. I rather choose in my case the cutting version than the deforming version. The point is that this code with crop at multiple computers generates the black image and that is the problem. If you cannot reproduce it then you will probably not be able to help. – Lajos Arpad Oct 10 '14 at 15:28
  • So, 'fit' is not an option. I believe that you were not able to reproduce it for some reason, but here the problem persists every time. If you can find out what is causing the issue at my end, then naturally I will upvote and accept your answer. – Lajos Arpad Oct 10 '14 at 15:30
  • yes if image is scaled to 90 x 90, it will be deformed. But here "fit" parameter prevent this to happen. Ratio is computed automatically by function image_resizeso() so dimensions will be forced to smaller scaled image 90 x 64. Example: $iwidth = 1622; $iheight = 1150; $width = 90; $height = 90; $wratio = 90/1622; $mratio = 90/1150; $mratio = 90/1622; And then you get width of 1622 x (90/1622) = 90 and height of 1150 x (90/1622) = 64 – Yoric Oct 10 '14 at 16:32
  • About getting a black image after resizing, it looks like some people having same issue solved it by adding those two lines of code before calling imagecopyresampled() : imagealphablending( $rimage, false ); imagesavealpha( $rimage, true ); see my edited post. – Yoric Oct 10 '14 at 16:38
  • My dear friend. If I want to have a picture of 90x90, then the picture will be deformed if it is not crop. Simple as the ABC. – Lajos Arpad Oct 10 '14 at 16:57
  • But, your solution is also as simple as the ABC, but I did not know it. Interesting point and thank you for sharing it. Upvote and answer acceptance is the well-deserved reward. – Lajos Arpad Oct 10 '14 at 17:03
  • Ok, i finally get your point on this. You want width = height = 90 pixels to fit in a square box. – Yoric Oct 10 '14 at 17:03
  • Yes, I guess I was not explaining it well. You are right, your solution is correct, thank you for the knowledge-sharing and for your patience. – Lajos Arpad Oct 10 '14 at 17:04