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

Php GD adds black background around cropped source image

我正在创建一个可以上传 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% 黑色,然后使它也透明,这是不应该的。

带有指示的客户端裁剪示例

带有附加指示的当前最终图像结果

据我所知,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);

到目前为止的结果:

此时我才发送新的图片,按照指定的宽高进行裁剪。代码如下:

$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

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

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

我也确实遇到了 png 文件和 imagecrapauto 函数这个恼人的黑色背景问题。 经过“一些”测试后,我似乎找到了解决方案。至少它对我有用。 这是我修改后的代码:

$im=imagecreatefrompng("yourpicture.png");
$cropped=imagecropauto($im, IMG_CROP_SIDES);
imagesavealpha($cropped,true);
if($cropped !==false) {
    imagedestroy($im);
    $im=$cropped;
}
imagepng($im, "yourpicturecropped.png");
imagedestroy($im);