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