Search code examples
phpimage-processingmirroring

I'm trying to implement user-supplied example code in the php manual but it doesn't behave as expected


I'm trying to implement the code supplied by killing_wombles0000 (8 years ago) on this page of the PHP manual: https://www.php.net/manual/en/function.imagecopymerge.php Trouble is there are errors / unexpected behaviour in the code (for example, $a is undefined) It sort of works, however the mirrored image fades to white and I want it to fade to black. When I make what I believe are the needed changes I can't get it to do as I want. There are too many image functions that are new to me in the code and I can't get my head round them working together.

I've spent the whole day reading up on each function, trying to work logically through the code, commenting out parts, changing transparency colours and generally clutching at straws. I thought that changing the 255,255,255 wherever it occurred to 0,0,0 woud fade the mirrored image to black. How naive of me ;)

This is the code supplied by the user on that page of the PHP manual:

$in = imagecreatefromjpeg('C:\test.jpg');
$reflection_strength = 120;        //    starting transparency (0-127, 0 being opaque)
$reflection_height = 40;        //     height of reflection in pixels
$gap = 10;                        //    gap between image and reflection

$orig_height = imagesy($in);                                //    store height of original image
$orig_width = imagesx($in);                                    //    store height of original image
$output_height = $orig_height + $reflection_height + $gap;    //    calculate height of output image

// create new image to use for output. fill with transparency. ALPHA BLENDING MUST BE FALSE
$out = imagecreatetruecolor($orig_width, $output_height);
imagealphablending($out, false);
$bg = imagecolortransparent($out, imagecolorallocatealpha($out, 255, 255, 255, 127));
imagefill($out, 0, 0, $bg);
imagefilledrectangle($out, 0, 0, imagesx($in), imagesy($in), $bg1);

// copy original image onto new one, leaving space underneath for reflection and 'gap'
imagecopyresampled ( $out , $in , 0, 0, 0, 0, imagesx($in), imagesy($in), imagesx($in), imagesy($in));

 // create new single-line image to act as buffer while applying transparency
$reflection_section = imagecreatetruecolor(imagesx($in), 1);
imagealphablending($reflection_section, false);
$bg1 = imagecolortransparent($reflection_section, imagecolorallocatealpha($reflection_section, 255, 255, 255, 127));
imagefill($reflection_section, 0, 0, $bg1);

// 1. copy each line individually, starting at the 'bottom' of the image, working upwards.
// 2. set transparency to vary between reflection_strength and 127
// 3. copy line back to mirrored position in original
for ($y = 0; $y<$reflection_height;$y++)
{   
    $t = ((127-$reflection_strength) + ($reflection_strength*($y/$reflection_height)));
    imagecopy($reflection_section, $out, 0, 0, 0, imagesy($in)  - $y, imagesx($in), 1);
    imagefilter($reflection_section, IMG_FILTER_COLORIZE, 0, 0, 0, $t);
    imagecopyresized($out, $reflection_section, $a, imagesy($in) + $y + $gap, 0, 0, imagesx($in) - (2*$a), 1, imagesx($in), 1);
}

// output image to view
header('Content-type: image/png');
imagesavealpha($out,true);
imagepng($out);

Setting $a to 0 before the loop enters removes the error.


Solution

  • It seems there are a few bugs in the code you found.

    1. $bg1 is not defined for the main output image. I changed $bg1 to $bg in imagefilledrectangle.
    2. $a is not defined. I changed references to $a to zero, as it references an "x" coordinate and it we want the entire width of the image, from zero to its full width.

    The reflection part is fading to transparent. Since the color of the page is white, the image looks like its fading to white. If you want to fade to black instead of transparent, I suggest leaving the default blending mode so that the background color will shine through and setting the background color to black:

    //imagealphablending($out, false);
    //$bg = imagecolortransparent($out, imagecolorallocatealpha($out, 255, 255, 255, 127));
    $bg = imagecolorallocatealpha($out, 0,0,0,0);
    

    For reference, see imagealphablending.

    Here's an example:

    $in = imagecreatefromjpeg('https://picsum.photos/id/1084/536/354?grayscale');
    $reflection_strength = 127;        //    starting transparency (0-127, 0 being opaque)
    $reflection_height = 40;        //     height of reflection in pixels
    $gap = 0;                        //    gap between image and reflection
    
    $orig_height = imagesy($in);                                //    store height of original image
    $orig_width = imagesx($in);                                    //    store height of original image
    $output_height = $orig_height + $reflection_height + $gap;    //    calculate height of output image
    
    // create new image to use for output. fill with BLACK.
    $out = imagecreatetruecolor($orig_width, $output_height);
    //imagealphablending($out, false);
    //$bg = imagecolortransparent($out, imagecolorallocatealpha($out, 255, 255, 255, 127));
    $bg = imagecolorallocatealpha($out, 0,0,0,0);
    imagefill($out, 0, 0, $bg);
    imagefilledrectangle($out, 0, 0, imagesx($in), imagesy($in), $bg);
    
    // copy original image onto new one, leaving space underneath for reflection and 'gap'
    imagecopyresampled ( $out , $in , 0, 0, 0, 0, imagesx($in), imagesy($in), imagesx($in), imagesy($in));
    
     // create new single-line image to act as buffer while applying transparency
    $reflection_section = imagecreatetruecolor(imagesx($in), 1);
    imagealphablending($reflection_section, false);
    $bg1 = imagecolortransparent($reflection_section, imagecolorallocatealpha($reflection_section, 255, 255, 255, 127));
    imagefill($reflection_section, 0, 0, $bg1);
    
    // 1. copy each line individually, starting at the 'bottom' of the image, working upwards.
    // 2. set transparency to vary between reflection_strength and 127
    // 3. copy line back to mirrored position in original
    for ($y = 0; $y<$reflection_height;$y++)
    {
        $t = ((127-$reflection_strength) + ($reflection_strength*($y/$reflection_height)));
        imagecopy($reflection_section, $out, 0, 0, 0, imagesy($in)  - $y, imagesx($in), 1);
        imagefilter($reflection_section, IMG_FILTER_COLORIZE, 0, 0, 0, $t);
        imagecopyresized($out, $reflection_section, 0, imagesy($in) + $y + $gap, 0, 0, imagesx($in) - 0, 1, imagesx($in), 1);
    }
    
    // output image to view
    header('Content-type: image/png');
    imagesavealpha($out,true);
    imagepng($out);
    

    Run on PHPFiddle