Chaosxmk
Chaosxmk

Reputation: 745

Resizing/cropping images in PHP results in images with black border on one side

I created a function that takes images, resizes them to fit at least one dimension perfectly onto a canvas and finally crops out excess image content.

Process:

  1. Take a 640x400 image
  2. Scale image fit into 450x450 canvas (image is now 450x281)
  3. Crop out excess data if any

The problem I'm encountering currently involves images that are too small for the newly created thumbnail (such as the one provided in the example above). I expected the output to either have a white background(JPGs) or a transparent background(PNGs). However, despite my best efforts, this tends to be the resulting mess:

Broken image

As can be observed, the image has a black background in place of a transparent/white background. I am completely stumped on how to correct this flaw.

A copy of my code:

function create_thumbnail($path, $saveto, $width, $height) {
    ini_set('memory_limit', '128M');    //Unlocking more memory for download
    $info = getimagesize($path);
    $rate = $info[0]/$info[1];

    // Determine image size/position
    if ($info[0] < $width || $info[1] < $height) {
        // Image is too small
        if ($info[0] < $width && $info[1] < $height) {
            // Both width and height too small
            $nw = $info[0];
            $nh = $info[1];
        } else if ($info[0] < $width) {
            // Width is too small
            $nw = ($info[0]*$height)/$info[1];
            $nh = $height;
        } else if ($info[1] < $height) {
            // Height is too small
            $nw = $width;
            $nh = ($info[1]*$width)/$info[0];
        }
    } else {
        // Image fits
        if (($width/$height) > $rate) {
            $nw = $width;
            $nh = $width/$rate;
        } else {
            $nw = $height*$rate;
            $nh = $height;
        }
    }

    $nw = round($nw);
    $nh = round($nh);

    $x_mid = round($nw/2);
    $y_mid = round($nh/2);

    switch($info[2]) {
        case IMAGETYPE_PNG :
            $src = imagecreatefrompng($path);
            break;
        case IMAGETYPE_JPEG :
            $src = imagecreatefromjpeg($path);
            break;
        case IMAGETYPE_GIF :
            $src = imagecreatefromgif($path);
            break;
        default :
            return false;
    }

    // Create image
    $proc = imagecreatetruecolor($nw, $nh);
    $clr = imagecolorallocate($proc, 255, 255, 255);
    imagefill($proc, 0, 0, $clr);
    imagecopyresampled($proc, $src,  0, 0, 0, 0, $nw, $nh, $info[0], $info[1]);

    $thmb = imagecreatetruecolor($width, $height);
    $clr = imagecolorallocate($thmb, 255, 255, 255);
    imagefill($thmb, 0, 0, $clr);
    imagecopyresampled($thmb, $proc, 0, 0, ($x_mid-($width/2)), ($y_mid-($height/2)), $width, $height, $width, $height);

    if ($info[2] == IMAGETYPE_PNG || $info[2] == IMAGETYPE_GIF) {
        $trnprt_idx = imagecolortransparent($src);

        if ($trnprt_idx >= 0) {
            // Attempt to forcefully correct transparencies using original image's color index
            $trnprt_clr = imagecolorsforindex($src, $trnprt_idx);
            $trnprt_idx = imagecolorallocate($thmb, $trnprt_clr['red'], $trnprt_clr['green'], $trnprt_clr['blue']);
            imagefill($thmb, 0, 0, $trnprt_idx);
            imagecolortransparent($thmb, $trnprt_idx);

            imagealphablending($thmb, false);
            imagesavealpha($thmb, true);
        } else if ($info[2] == IMAGETYPE_PNG) {
            // Attempt to forcefully correct transparencies by shutting down blending
            $clr = imagecolorallocatealpha($thmb, 0, 0, 0, 127);
            imagefill($thmb, 0, 0, $clr);
            imagealphablending($thmb, false);
            imagesavealpha($thmb, true);
        }
    }

    switch($info[2]) {
        case IMAGETYPE_PNG :
            imagepng($thmb, $saveto);
            break;
        case IMAGETYPE_JPEG :
            imagejpeg($thmb, $saveto, 100);
            break;
        case IMAGETYPE_GIF :
            imagegif($thmb, $saveto);
            break;
        default :
            return false;
    }

    return true;
} //End of create_thumbnail()

I have attempted to correct the transparency/coloring (as visible in my code), but it only affects one side of the image. Everything I have tried has either resulting in one side having a transparent/white background or both sides being completely black.

Upvotes: 0

Views: 1665

Answers (1)

Chaosxmk
Chaosxmk

Reputation: 745

After a long time spent playing around trying to figure out what exactly was going on and breaking, I have found the solution.

The problem is here:

$proc = imagecreatetruecolor($nw, $nh);
$clr = imagecolorallocate($proc, 255, 255, 255);
imagefill($proc, 0, 0, $clr);
imagecopyresampled($proc, $src,  0, 0, 0, 0, $nw, $nh, $info[0], $info[1]);

$thmb = imagecreatetruecolor($width, $height);
$clr = imagecolorallocate($thmb, 255, 255, 255);
imagefill($thmb, 0, 0, $clr);
imagecopyresampled($thmb, $proc, 0, 0, ($x_mid-($width/2)), ($y_mid-($height/2)), $width, $height, $width, $height);

The newly created image $proc was not transferring it's transparency over to $thmb when I was doing imagecopyresampled from one to the other. The solution I found was to either skip creating/using $thmb altogether, or to save $proc as a png/gif first, then use that saved image for imagecopyresample.

Upvotes: 4

Related Questions