繁体   English   中英

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 文件和 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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM