Php GD在裁剪的源图像周围添加黑色背景

问题描述 投票:1回答:1

我正在创建一个可以上传jpg,giff和png图像的上传器。然后将它们转换为太透明的PNG,然后根据从客户端发送的裁剪参数裁剪图像。裁剪甚至可以提供负轴坐标,这意味着图像被裁剪超出图像尺寸。

为了确保所有支持的格式都具有透明度,我首先将图像重新创建为透明的png,这样做效果很好。

//GET WIDTH AND HIEGHT OF UPLOADED JPG
list($imageWidth,$imageHeight)= getimagesize($originalDirectory.$file_name);
$image = imagecreatefromjpeg($originalDirectory.$file_name);

//CREATE NEW IMAGE BASED ON WIDTH AND HEIGHT OF SROUCE IMAGE
$bg = imagecreatetruecolor($imageWidth, $imageHeight);

//TRANSPARENCY SETTINGS FOR BOTH DESTINATION AND SOURCE IMAGES
$transparent2 = imagecolorallocatealpha($bg, 0, 0, 0, 127);
$transparent = imagecolorallocatealpha($image, 0,128,255,50); //ONLY TO ENSURE TRANSPARENCY IS WORKING

//SAVE TRANSPARENCY AMD FILL DESTINATION IMAGE
imagealphablending( $bg, false );
imagesavealpha($bg, true);
imagefill($bg, 0, 0, $transparent2);

//SAVE TRANSPARENCY AMD FILL SOURCE IMAGE
imagealphablending( $image, false );
imagesavealpha($image, true);
imagefill($image, 0, 0, $transparent); //ONLY TO ENSURE TRANSPARENCY IS WORKING

//CREATE AND SAVE AS PNG FILE WITH TRANSPARENCY
imagecopy($bg, $image, 0, 0, 0, 0, $imageWidth,$imageHeight);
header('Content-type: image/png');
imagepng($bg, $originalDirectory.$jpgFile);
imagedestroy($bg);

在创建新的png之后,我使用它然后根据从客户端脚本编写传递的参数来仅裁剪图像。

//GET NEWLY CREATED PNG
$src = imagecreatefrompng($originalSRC);
// NOT SURE IF NECESSARY BUT HAS NO EFFECT ON FINAL RESULT REGGARDLESS OF ANY SETTINGS DONE
imagealphablending( $image, false );
imagesavealpha($image, true);

//DEFINE DESTINATION CROPPED FILE
$thumbHighFilename = $thumbHighDirectory.'test.png';

//CREATE NEW IMAGE BASED ON FINAL CROP SIZE
$tmp = imagecreatetruecolor($cropWidth, $cropHeight);

//ENSURE DESTINATION HAS TRANSPARENT BACKGROUND
$transparent2 = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
imagealphablending( $tmp, false );
imagesavealpha($tmp, true);
imagefill($tmp, 0, 0, $transparent2);

/* -------------------------------------------------
PROBLEM HERE
When I try to merge the two with the crop paramaters
send from client side. All transparencies work, except
where crop X and Y axis exceeds source image paramaters.
Currently 50px offset on destination image is to verify
transparency works.
The source coordinates are based on image not crop area.
Tried with both imagecopyresized & imagecopyresampled
-------------------------------------------------*/
imagecopyresized($tmp, $src, -50,-50, $xAxis,$yAxis,$cropWidth, $cropHeight, $pW, $pH);

//SAVE FINAL IMAGE
header('Content-type: image/png');
imagepng($tmp, $thumbHighFilename);
imagedestroy($tmp);

这是源图像和目标图像仍然具有透明度的地方;但负坐标会在源图像周围创建黑色背景。我怎样才能让它变得透明?

虽然我发现很多关于透明胶片的东西,但没有什么是合适的解决方案。例如,之后的图像填充将不起作用,因为源可以在边缘周围使用100%黑色并且将使其也是透明的,它不应该。

带有指示的客户端作物示例enter image description here

当前的最终图像结果与增加的指示enter image description here

php gd
1个回答
0
投票

根据我的发现,似乎没有办法让GD imagecopyresized和imagecopyresampled继承它正在裁剪的图像的默认背景。因此,它不断向源图像添加默认黑色背景。

我遇到的最大问题实际上是作物容器响应,因此很难确定作物参数。

为了解决这个问题,我让我的前端开发人员向我发送了更多参数。下面是现在传递给php的所有参数,以及php中与所接收参数链接的变量:

  • $ xAxisCropper&$ yAxisCropper - 变量获取容器的X和Y坐标,而不是被裁剪的图像。
  • $ pW&$ pH - 定义裁剪框的宽度和高度。
  • $ containerWidth&$ containerheight - 当容器响应时,获取高度和宽度有助于了解计算的坐标的大小。
  • $ imResizeHeight&$ imResizeWidth - 由于容器中的图像始终设置为包含在容器中,因此获取CSS调整图像大小的宽度和高度非常重要。了解响应容器中图像的内容。
  • $ originalWidth&$ originalHeight - 定义图像的原始大小,可以传递给php,也可以从上传到服务器的原始图像中检索。

使用这些参数,我现在可以在中心重新创建包含图像的容器,并裁剪新创建的图像。在裁剪之前,为裁剪图像进行正确缩放非常重要,以确保在裁剪之前裁剪最佳质量的图像并且不进行压缩。

为此,我首先确定容器中的图像是在容器中放大还是缩小。如果按比例缩放图像需要缩放到容器大小,如果按比例缩小,则需要增加容器以使图像适合容器。下面是当前确定此内容的代码,并相应地更改必要的参数:

    //IF CSS CONTAIN RESIZES HEIGHT EQUAL TO CROP CONTAINER HEIGHT
if($imResizeHeight == $containerheight){

    //IF IMAGE SIZE WAS INCREASED
    if($imResizeHeight>$originalHeight){
        //DEFINE NEW IMAGE SIZE TO SCALE TO CONTAINER
        $new_height = $imResizeHeight;
        $new_width = $originalWidth * ($new_height / $originalHeight);

        $scale = 'image'; //DEFINE WHAT IS BEING INCREASED

    //ESLSE INCREASE CONTAINER TO IMAGE HEIGHT DIMENSIONS
    }else{
        //RECALCULATE WIDTH & HEIGHT OF CONTAINER
        $newContainerWidth = $containerWidth * ($originalHeight / $containerheight);
        $newContainerheight = $originalHeight;

        $scale = 'container'; //DEFINE WHAT IS BEING INCREASED
    }

//IF CSS CONTAIN RESIZES WIDTH EQUAL TO CROP CONTAINER WIDTH
}elseif($imResizeWidth == $containerWidth) {
    //IF IMAGE SIZE WAS INCREASED
    if($imResizeWidth>$originalWidth){
        //DEFINE NEW IMAGE SIZE TO SCALE TO CONTAINER
        $new_width = $imResizeWidth;
        $new_height =  $originalHeight * ($new_width / $originalWidth);

        $scale = 'image'; //DEFINE WHAT IS BEING INCREASED

    //ESLSE INCREASE CONTAINER TO IMAGE WIDTH DIMENSIONS
    }else{
        //RECALCULATE WIDTH & HEIGHT OF CONTAINER
        $newContainerheight =  $containerheight * ($originalWidth / $containerWidth);
        $newContainerWidth = $originalWidth;

        $scale = 'container'; //DEFINE WHAT IS BEING INCREASED
    }
}

//IF IMAGE WAS INCREASED
if($scale=='image'){
    //SCALE IMAGE
    $src = imagescale ( $src , $new_width , $new_height, IMG_BILINEAR_FIXED);
    imagepng($src,$originalSRC,0);

    //ADD CHANGES TO VARIABLES USED IN CROP
    $pH = $pH * ($new_height / $originalHeight);
    $pW = max(0, round($pW * ($new_width / $originalWidth)));
    $originalWidth = $new_width;
    $originalHeight = $new_height;
    $newContainerWidth = $containerWidth;
    $newContainerheight = $containerheight;

//ELSE CONTAINER WAS INCREASED
}else {
    //RECALCULATE COORDINATES OF CONTAINER
    $yAxisCropper = max(0, round($yAxisCropper * ($newContainerheight / $containerheight)));
    $xAxisCropper = max(0, round($xAxisCropper * ($newContainerWidth / $containerWidth)));
}

根据缩放重新定义参数后,我会根据容器大小创建透明背景,并将图像添加到中心。因此,在创建新图像的代码下方创建一个适当版本的裁剪容器作为图像:

//CALCULATE CENTRE OF NEW CONTAINER
$centreX = max(0, round(($newContainerWidth-$originalWidth)/2));
$centreY = max(0, round(($newContainerheight-$originalHeight)/2));

//CREATE NEW IMAGE BASED ON WIDTH AND HEIGHT OF SROUCE IMAGE
$bg = imagecreatetruecolor($newContainerWidth, $newContainerheight);

//SAVE TRANSPARENCY AMD FILL DESTINATION IMAGE
$transparent = imagecolorallocatealpha($bg, 0,0,0,127);
imagealphablending( $bg, false);
imagesavealpha($bg, true);
imagefill($bg, 0, 0, $transparent);

//CREATE AND SAVE AS PNG FILE WITH TRANSPARENCY
imagecopy($bg, $src, $centreX, $centreY, 0, 0,  $originalWidth,$originalHeight);
header('Content-type: image/png');
imagepng($bg, $originalSRC, 0);
imagedestroy($bg);

到目前为止的结果:enter image description here

只是在这一点上,我根据指定的宽度和高度发送要裁剪的新图像。代码如下:

$src = imagecreatefrompng($originalSRC);

$thumbHighFilename = $thumbHighDirectory.$new_image;

$tmp = imagecreatetruecolor($cropWidth, $cropHeight);
$transparent2 = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
imagealphablending( $tmp, false );

imagesavealpha($tmp, true);
imagefill($tmp, 0, 0, $transparent2);

imagealphablending( $tmp, false );

imagesavealpha($tmp, true);
imagecopyresampled($tmp, $src, 0,0, $xAxisCropper,$yAxisCropper,$cropWidth, $cropHeight, $pW, $pH);

header('Content-type: image/png');
imagepng($tmp, $thumbHighFilename, 2);

最终结果裁剪400x300 enter image description here

到目前为止,这是我设法解决问题的唯一方法。代码可能仍然可以优化,但如果有人有更优化的解决方案,请分享。

我还要感谢我的前端开发人员Salem帮助我解决这个恼人的问题。

© www.soinside.com 2019 - 2024. All rights reserved.