I have 2 source images and I want to:
I have tried many examples, but can't seem to maintain transparency on the final image.
I'm trying to achieve something like this:
This is an example of the output I am getting:
Here's my circle_crop function:
function create_circle( $img_path ) {
// Attribution: by NerdsOfTech
// Step 1 - Start with image as layer 1 (canvas).
if (! $img1 = $this->imageCreateFromAny( $img_path )) {
return FALSE;
}
$x=imagesx($img1);
$y=imagesy($img1);
// Step 2 - Create a blank image.
$img2 = imagecreatetruecolor($x, $y);
$bg = imagecolorallocate($img2, 255,0,255, 127); // wierdo pink background
// $bg = imagecolorallocate($img2, 0, 0, 0, 127 ); // white background
imagefill($img2, 0, 0, $bg);
imagecolortransparent($img2, $bg);
// Step 3 - Create the ellipse OR circle mask.
$e = imagecolorallocate($img2, 255, 255, 255); // black mask color
// Draw a ellipse mask
imagefilledellipse ($img2, ($x/2), ($y/2), $x, $y, $e);
// OR
// Draw a circle mask
// $r = $x <= $y ? $x : $y; // use smallest side as radius & center shape
// imagefilledellipse ($img2, ($x/2), ($y/2), $r, $r, $e);
// Step 4 - Make shape color transparent
imagecolortransparent($img2, $e);
// Step 5 - Merge the mask into canvas with 100 percent opacity
imagecopymerge($img1, $img2, 0, 0, 0, 0, $x, $y, 100);
// Step 6 - Make outside border color around circle transparent
imagecolortransparent($img1, $bg);
/* Clean up memory */
imagedestroy($img2);
return $img1;
}
Here's the code I pass in an array of image URL's and loop through calling the circle_crop function to return a cropped image and merge it onto my destination image.
function generate_collage( $img_name_path_array, $effect = 'POLAROID' ) {
$base_img_width = 800;
$base_img_height = 650;
if (empty($img_name_path_array)) {
error_log('Image name_path_array is blank?'.PHP_EOL);
return FALSE;
}
$effect = strtoupper($effect);
/* Create canvas */
$collage_img = imagecreatetruecolor($base_img_width, $base_img_height);
imagealphablending($collage_img, false);
imagesavealpha($collage_img,true);
/* Create alpha channel for transparent layer */
$trans_col=imagecolorallocatealpha($collage_img,255,255,255, 127);
/* Create overlapping transparent layer */
imagefilledrectangle($collage_img,0,0,$base_img_width,$base_img_height,$trans_col);
/* Continue to keep layers transparent */
imagealphablending($collage_img,true);
$size_reduction = .80;
$start_size = 100;
foreach ($img_name_path_array as $image_array ) {
$img_text = $image_array[0];
$img_path = $image_array[1];
if (! empty($img_path)) {
switch ($effect) {
/* Add other collage image effects here */
case 'POLAROID' : {
$temp_img = $this->create_polaroid($img_path, $img_text, TRUE);
break;
}
case 'CIRCLES' : {
// $temp_img = $this->circle_crop($img_path);
$temp_img = $this->create_circle($img_path);
break;
}
default : {
/* Default to polaroid for now */
$temp_img = $this->create_polaroid($img_path, $img_text, TRUE);
break;
}
}
if ($temp_img) {
/* Get original height and width paramaters */
$source_w = imagesx($temp_img);
$source_h = imagesy($temp_img);
/* Randomise X and Y coordinates */
$random_x_pos = rand(0, (int) ($base_img_width * .66));
$random_y_pos = rand(0, (int) ($base_img_height * .3));
/* Randomise image size */
$start_size = ($start_size * $size_reduction);
$random_img_size_ratio = $start_size / 100;
/* Add generated image to base collage image */
imagecopyresampled($collage_img, $temp_img, $random_x_pos, $random_y_pos, 0, 0, ($base_img_width * $random_img_size_ratio), ($base_img_height * $random_img_size_ratio), $source_w, $source_h);
imagecolortransparent($collage_img, $trans_col);
/* Keep transparent when saving */
imagesavealpha($collage_img,true);
/* Memory clean up */
imagedestroy($temp_img);
// break;
}
}
}
/* Now display PNG to browser */
$this->show_png_from_image_object($collage_img);
}
Here's my display function:
function show_png_from_image_object( $img_obj ) {
header ( 'Content-Type: image/png' );
/* Display PNG with max compression */
imagepng ( $img_obj, NULL, 9, PNG_ALL_FILTERS);
imagedestroy ( $img_obj );
}
I've pulled my hair out for 2 days, so any pointers would be greatly appreciated.
Thanks, Jason.
I've written the following class to handle all the required image processing:
class Img
{
public $img;
public $transparent;
public $width;
public $height;
public function __construct($img = null)
{
if (!empty($img)) {
$this->img = imagecreatefrompng($img);
$this->width = imagesx($this->img);
$this->height = imagesy($this->img);
$this->setTransparentColour();
}
}
public function create($width, $height, $transparent)
{
$this->img = imagecreatetruecolor($width, $height);
$this->width = $width;
$this->height =$height;
$this->setTransparentColour();
if (true === $transparent) {
imagefill($this->img, 0, 0, $this->transparent);
}
}
public function setTransparentColour($red = 255, $green = 0, $blue = 255)
{
$this->transparent = imagecolorallocate($this->img, $red, $green, $blue);
imagecolortransparent($this->img, $this->transparent);
}
public function circleCrop()
{
$mask = imagecreatetruecolor($this->width, $this->height);
$black = imagecolorallocate($mask, 0, 0, 0);
$magenta = imagecolorallocate($mask, 255, 0, 255);
imagefill($mask, 0, 0, $magenta);
imagefilledellipse(
$mask,
($this->width / 2),
($this->height / 2),
$this->width,
$this->height,
$black
);
imagecolortransparent($mask, $black);
imagecopymerge($this->img, $mask, 0, 0, 0, 0, $this->width, $this->height, 100);
imagedestroy($mask);
}
public function merge(Img $in, $dst_x = 0, $dst_y = 0)
{
imagecopymerge(
$this->img,
$in->img,
$dst_x,
$dst_y,
0,
0,
$in->width,
$in->height,
100
);
}
public function render()
{
header('Content-type: image/png');
imagepng($this->img);
}
}
As written, the class will only work with PNG files but you should be able to modify this easily enough, if required.
Example class usage:
// create a transparent base image that we will merge the cropped images into.
$img = new Img();
$img->create(400, 400, true);
// first image; crop and merge with base.
$img2 = new Img('./crop_1.png');
$img2->circleCrop();
$img->merge($img2, 50, 50);
// second image; crop and merge with base.
$img3 = new Img('./crop_2.png');
$img3->circleCrop();
$img->merge($img3, 25, 200);
$img->render();
This will result in the below image (of course, the transparency is impossible to see when embedded here so try opening the image separately):
I used these two source images:
you can use ImageArtist which a GD wrapper created for making image manipulation insanely easy with php
$overlay = new Overlay(720, 480, new Color(34,34,36));
$w = $overlay->getWidth();
$h = $overlay->getHeight();
$mi = new CircularShape("./mi.jpg");
$mi->scale(21);
$mi->setAxises(60,60);
$mi->build();
$mali = new CircularShape("./mali.jpg");
$mali->scale(60);
$mali->setAxises(140,140);
$mali->build();
$bach = new CircularShape("./har.jpeg");
$bach->scale(40);
$bach->setAxises(80,80);
$bach->build();
$borderd = new CircularShape(new Overlay($bach->getWidth()+10,$bach->getHeight()+10,new Color(255,255,255)));
$borderd->build();
$bach = $borderd->merge($bach,5,5);
$img = $overlay->merge($mi,$w/2 + 60,120);
$img->merge($mali,170,60);
$img->merge($bach,$w/2,200);
$img->dump(); //this just for demo, but you can use other methods to save this to disk
at the moment ImageArtist does not support borders but if you be little creative you can use an overlay instead. here is the output of the above code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With