dpbf62565 2019-02-26 11:28
浏览 112
已采纳

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

I’m creating an uploader that can upload jpg, giff and png images. Then converts them all too transparent PNG’s and then crops the image based on crop parameters send from client side. The crop can even supply negative axis coordinates, meaning the image is being cropped beyond image dimensions.

To ensure all supported formats can have transparency I first recreate the image into a transparent png, and this is working well.

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

After the new png is created I use it to then only crop the image according to the parameters passed through from the client side scripting.

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

This is where the source and destination images still has there transparency; however the negative coordinates creates a black background around the source image. How can I get that to be transparent?

While I found a lot about transparencies, nothing has been a proper solution. For example imagefill afterwards will not work as source could use 100% black around the edges and will make that also transparent then, which it shouldn’t.

CLIENT SIDE CROP EXAMPLE WITH INDICATIONS enter image description here

CURRENT FINAL IMAGE RESULT WITH ADDED INDICATIONS enter image description here

  • 写回答

1条回答 默认 最新

  • dongqiang2024 2019-02-28 14:15
    关注

    From what I could find it seems that there is no way for the GD imagecopyresized and imagecopyresampled to inherit the default backgrounds of the images it is cropping. Thus it keeps adding the default black background to the source image.

    The biggest problem I’ve had was actually the crop container being responsive, thus very difficult to determine crop parameters.

    To get around the problem I asked my frontend developer to send me more parameters from the crop. Below are all parameters now being passed to php, and the variables in php that are linked to the parameters received:

    • $xAxisCropper & $yAxisCropper – The variables get the X and Y coordinates of the container not the image being cropped.
    • $pW & $pH – Defines the width and height of the crop box.
    • $containerWidth & $containerheight – As the container is responsive getting the height and width helps understand what size the coordinates where calculated on.
    • $imResizeHeight & $imResizeWidth – Since the images in the container are always set to be contained within the container, it was important to get the width and height into which the image is being resized by the CSS. Giving understanding of what is happening with the image within the responsive container.
    • $originalWidth & $originalHeight – Defines the original size of the image and could either be passed to php or retrieved from the original image uploaded to the server.

    With these parameters I could now recreate the container with the image in the centre, and crop the newly created image. Before I crop it’s important to get the right scaling of the image for the crop, in order to ensure the best quality image is cropped and not compressed before cropping.

    To do this I started by determining if the image in the container is being scaled up or down within the container. If scaled up image needs to be scaled to container size, if scaled down the container needs to be increased to have the image fit in the container. Below is the code that currently determines this, and changes the necessary parameters accordingly:

        //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)));
    }
    

    Once the parameters have been redefined according to the scaling, I then create the transparent background according to the container size and add the image in the centre. Thus creating a proper version of the crop container as an image, below the code for creating the new image:

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

    The result till thus far: enter image description here

    It is only at this point that I send the new image to be cropped according to the specified width and height. Code below:

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

    Final result cropped 400x300 enter image description here

    This has been the only way so far that I’ve managed to solve the problem. Code could probably still be optimised, but if someone has a more optimal solution please share.

    I also wish to thank my frontend developer Salem for helping me to solve this irritating issue.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 CSS实现渐隐虚线边框
  • ¥15 thinkphp6配合social login单点登录问题
  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题