I'm trying to create a photo collage in php by combining two images, a background and an image.
Certain part of my background is transparent, I want to put the image into that part of the background and merge them. The transparent part could be a square, circle, oval rectangle or any other shape. I tried the following code, but it doesn't work
$image_1 = imagecreatefrompng('images/background.png');
$image_2 = imagecreatefrompng('images/image.png');
imagealphablending($image_1, true);
imagesavealpha($image_1, true);
imagecopy($image_1, $image_2, 0, 0, 0, 0, 100, 100);
imagepng($image_1, 'images/3.png');
The code above combines the two images, but with one of them being very small, and the other take up the whole screen which is not what I wanted. I need to have the the image fit into the transparent part of the background of the newly combined image.
Related
I'm creating a program to create a product image based on choices made by the customer. The product is men's tights, with or without codpiece, with or without feet, in three different styles.
To do this, I have seventeen PNG images: background, a pair of actual feet, torso and arms above the waist (all in color); leg options all in grayscale: right leg, left leg, right codpiece, left codpiece, etc., colorized as they're laid in.
Here is the specific issue I'm trying to work out: every image is transparent (except the background) and they layer up just fine. However, the codpiece casts a shadow on the leg: right now that shadow is a black gradient fading to transparent. Combined with the picture below it, the shadow becomes a large stain (see below).
I have google-d like crazy and tried everything I can think of, but I can't find the right combination of functions. Is what I want to do possible, and if so, how?
tl;dr: How do I get one image to cast a shadow on another?
// image paths are stored in an array, built based on customer choices
$dest = imagecreatefrompng("./layers/{$layers[0][0]}.png");
for($i = 0; $i < count($layers); $i++){
imagealphablending($dest, false);
imagesavealpha($dest, true);
$src = imagecreatefrompng("./layers/{$layers[$i][0]}.png");
// apply color to the current image as appropriate
$color = $colors[$layers[$i][1]] ?? '';
if($color != ''){
colorize($src, $color);
}
// lay the current image onto the image we're building
imagecopymerge_alpha($dest, $src, 0, 0, 0, 0, 4000, 4000, 100);
}
I need to merge the following images, however my solution is not working.
My code is the following (I pass the URL of the images to the script via GET parameter)
<?php
$dest = imagecreatefrompng($_GET['img1']);
$src = imagecreatefrompng($_GET['img2']);
imagecopymerge($dest, $src, 0, 0, 0, 0, 1500, 1500, 50);
$white = imagecolorallocate($dest, 255, 255, 255);
imagecolortransparent($dest, $white);
header('Content-Type: image/png');
imagepng($dest);
?>
Both image are PNG with transparent background and both are 1500x1500.
First image:
Second image:
What I get:
Why can't I make the final image have the right opacity? I tried changing the last value of imagecopymerge() to 0 or 100 but in those cases I only get one image or another. I need them both, exactly overlapped on one another!
Also, if you look carefully around the gem in the final image, there is some extra blue color... how is this possible?
This is caused by setting the resulting image to use image transparency rather than per-pixel alpha-channel transparency by your call to imagecolortransparent which sets any white (#ffffff) pixels to 100% transparent.
The artefacts ('extra blue colour' and edge pixels) on the resulting image are caused by the alpha-channel transparency from the original images not being saved and the pixels (which were 100% transparent but not white) showing their original colour.
The 'washed out' look of your result comes from telling imagecopymerge to merge the two images with 50% transparency.
The solution is to use the correct alpha settings:
<?php
$dest = imagecreatefrompng($_GET['img1']);
$src = imagecreatefrompng($_GET['img2']);
imagesavealpha($dest, true);
imagecopy($dest, $src, 0, 0, 0, 0, 1500, 1500);
header('Content-Type: image/png');
imagepng($dest);
While reading up on the issues merging transparent images in PHP, it seems that everyone is in the "it works" or "it doesn't work" camps. I have found a way to demonstrate each case.
I wish to take a PNG, cut an ALPHA hole in it and then merge it on top of another image. In this case, I cut a hole in an image from google maps, and paste it over a red block. I have two images from google maps. One is of Manhattan and one is of my house. One works, and one does not. The only difference is one was "saved" via a browser.
If you run the code below, you will see the difference in outputs. Does anyone know why the same code would treat two PNG files completely differently? It must be the difference in the PNG files themselves, but then what would it be?
<?php
sometimesworks("https://maps.googleapis.com/maps/api/staticmap?center=40.714728,-73.998672&zoom=12&size=400x400&maptype=hybrid", "google");
sometimesworks("https://lh4.googleusercontent.com/UQvV_dpBa3_rVf25pvLXKD3OwzF4FtPnHBHkzdWqjCQ5mlFqcFfId9echIgDMv_xYRRYzLaKEXphw7g=w2447-h1106", "myhouse");
function sometimesworks($p_image, $p_prefix)
{
$image_top =imagecreatefrompng($p_image);
$brush = imagecolorallocate($image_top, 0, 0, 0); //create a black brush
imagefilledpolygon($image_top, explode(",", "10,10, 120,22, 80,280, 200, 191"), 4, $brush); //fill a polygon
imagecolortransparent($image_top, $brush); //turn the black to be transparent
imagepng($image_top, './'.$p_prefix.'.transparent.png'); //save the file to confirm that it is working.
//create a big red square
$image_bottom = imagecreatetruecolor(imagesx($image_top), imagesy($image_top));
$red = imagecolorallocate($image_bottom, 255, 0, 0);
imagefill($image_bottom, 0, 0, $red);
imagepng($image_bottom, './'.$p_prefix.'.red.png');
//merge the top onto the bottom.
$out = imagecreatetruecolor(imagesx($image_top), imagesy($image_top));
imagecopy($out, $image_bottom, 0, 0, 0, 0, imagesx($image_top), imagesy($image_top));
imagecopy($out, $image_top, 0, 0, 0, 0, imagesx($image_top), imagesy($image_top));
imagepng($out, './'.$p_prefix.'.out.png');
}
The issue with the above code is that the PNG files were of different type. One was a truecolor image and the other was a palette. The code to merge files differs depending on what is being done.
This is a good reference for the merging of "palette" based PNG files with transparency.
This is blowing my mind. I want to merge 2 transparent PNGs.
One is a circle ($source) generated on the fly from a square image.
The second is a map marker ($marker) with a transparent circle to fit the first behind.
imagepng($source); and imagepng($marker); outputs just as one might expect.
With transparent backgrounds.
I then create an empty transparent image the size of the marker to place them both together:
//NEW BLANK TRANSPARENT IMAGE
$dest = imagecreatetruecolor(50, 61);
$transparent = imagecolorallocatealpha($dest, 0, 0, 0, 127);
imagefill($dest, 0, 0, $transparent);
imagealphablending($dest, true);
imagesavealpha($dest,true);
//COPY THE CIRCLE
imagecopy($dest, $source, 5, 5, 0, 0, 41, 41);
//AND THE MARKER ON TOP
imagecopy($dest, $marker, 0, 0, 0, 0, 50, 61);
In the result, the circle appears as a black square with the circle inside.
I tried a lot of combinations of imagealphablending and imagesavealpha both on $source and $dest and nothing seems to work.
How can I remove the black square and leave the $source transparent in the result as it is before the merge?
The problem here was:
To generate the circle on the fly, I was creating a circular mask and making everything else transparent making it red and then making red transparent.
This is incompatible with imagesavealpha(true) as it says the gd engine exactly to ignore transparent colors and save the whole alpha channel instead.
When merging both images, the color once transparent is now black.
The solution to my case was to analise it pixel per pixel and copy it to a blank image if it's inside the circle using the circular equation.
Ive been working on this project for days now and for some reason just not able to get rid of an unexpected 1px by 1px (approx) white spot that apears in each and every tile that is processed.
Summary:
I am using an original image ( say original.jpeg ) as referance to create a mosaic image ( say mosaic.jpeg which is approx 1000px by 1000px ) by merging totegher much much smaller jpeg images ( aprox 10px by 10px ).
I have a data set of approx 20,000 tile images to work with.
Process so far
I have mapped the original.jpeg image to cut it up into 5px by 5px tiles, then found the average color of each tile and saved it for further use.
I have scanned all the (10x10) tile images and stored their individual average colors as well.
i have calculated which tile image would fit closest to which tile of the original image by using Weighted ref : euclidean distance from the site mentioned.
I have managed to use PHP gd library to create a new truecolor image with all the matching tiles placed in the right position ( thus effectively creating a mosaic of the original.jpeg image )
The Problem
I am not getting a clear mosaic i had expected, for some reason the tiles do not match properly.
The Workaround
Now due to lack of time i an using a quick fix where in i take the original image, give it some 50% opacity and overlay it on top of each tile while it is being placed into the final mosaic.
NOTE: Although i am effectively overlaying the original image over the mosaic image, im NOT doing it in one go. The overlaying HAS to happen at each tile level.
So in short : Before placing each tile at the correct position of the final mosaic, i do the following
1. get that particular section of the original image ( 5x5px )
2. expand it to match the final tile size ( 10x10px )
3. set transparency for the section
4. place it over the tile that will be placed
5. merge this new tile over the final mosaic at the corresponding position.
Here is the function i have created to overlay part of the image along with transparency set to it.
public function overlay($dImg, $sImg, $opacity = null) {
// set default Opacity if not specified
$opacity = (is_null($opacity)) ? $this->opacity : $opacity;
// get width, height of sourceImage
$sWidth = imagesx($sImg);
$sHeight = imagesy($sImg);
// get width height of final image
$dWidth = imagesx($dImg);
$dHeight = imagesy($dImg);
$image = imagecreatetruecolor($dWidth, $dHeight);
imagecopyresampled($image, $sImg, 0, 0, 0, 0, $dWidth, $dHeight, $sWidth, $sHeight);
$background = imagecolorallocatealpha($image, 255, 255, 255, 127);
imagefill($image, 0, 0, $background);
imagealphablending($image, true);
imagecopymerge($dImg, $image, 0, 0, 0, 0, $dWidth, $dHeight, $opacity);
imagedestroy($image);
return $dImg;
}
THE REAL PROBLEM
in theory all of this seems perfectly fine. But the results have their own say in the matter.
I noticed an unusual almost 1x1px white patch at the start of every tile of the final mosaic.
This white patch only appears when the transparency technique above is applied. It does not happen otherwise.
I am clueless as to why this is happening, Due to this white patch the entire image looks like it has white noise all over it and degrades the overall quality immensely.
Please guide me in any direction as to why something like this could be happening.
your problem lies on these two lines:
$background = imagecolorallocatealpha($image, 255, 255, 255, 127);
imagefill($image, 0, 0, $background);
you don't need those, because imagefill is used to fill an area that have same/similar color with the color located on the supplied coordinate, in your case 0, 0 (top left), when there is no adjacent similar color, then it just change the color at the given coordinate.
you can use imagefilledrectangle instead, but i still think you don't need that, just comment out those 2 lines and see the result if it match your requirement, if not, then go ahead use imagefilledrectangle
imagefilledrectangle