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

时间:2019-02-26 11:28:12

标签: php gd

我正在创建一个可以上传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);

在这里,源图像和目标图像仍然具有透明度;但是,负坐标会在源图像周围创建黑色背景。我怎样才能做到透明?

虽然我发现很多关于透明胶片的内容,但没有什么是合适的解决方案。例如,之后的imagefill将无法正常工作,因为源可能会在边缘使用100%黑色,然后将其设为透明,而不应该这样做。

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

最新的最终影像结果及其他适应症 enter image description here

2 个答案:

答案 0 :(得分:0)

从我发现的情况来看,似乎无法对GD imagecopyresize和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帮助我解决了这个令人讨厌的问题。

答案 1 :(得分:0)

我也确实遇到了这个令人讨厌的黑色背景问题,包括png文件和imagecropauto函数。 经过“一些”测试后,我发现了一个解决方案。至少对我有用。 这是我的修正代码:

$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);