I am trying to merge two images in PHP, overlapping each other in the middle like in here : http://i.stack.imgur.com/ejdDQ.jpg
However, I am having no luck.
On the ImageMagick page, they are using this method to do it in the command line:
http://www.imagemagick.org/Usage/photos/#overlap
But since I cannot use exec on my server, I have to do it somehow with the help of the imagick extension installed on the server (http://us1.php.net/manual/en/book.imagick.php).
Is there any way to make this work?
Using the source files from the link and the code below generates the image:
//Load the images
$left = new Imagick(realpath('../images/im/holocaust_tn.gif'));
$right = new Imagick(realpath('../images/im/spiral_stairs_tn.gif'));
$gradient = new Imagick(realpath('../images/im/overlap_mask.png'));
//The right bit will be offset by a certain amount - avoid recalculating.
$offsetX = $gradient->getImageWidth() - $right->getImageWidth();
//When doing the fading of the images, ImageMagick uses "White == show image".
//The gradient is setup with black on the left, white on the right. So the for
//the left image we need to reverse the gradient to make it white on the left.
$negativeGradient = clone $gradient;
$negativeGradient->negateimage(false);
//Fade out the left part
$left->compositeimage(
$negativeGradient,
Imagick::COMPOSITE_COPYOPACITY,
0, 0
);
//Fade out the right part - offset the gradient
//to make it align in the final image
$right->compositeimage(
$gradient,
Imagick::COMPOSITE_COPYOPACITY,
-$offsetX, 0
);
//Create a new canvas to render everything in to.
$canvas = new Imagick();
$canvas->newImage($gradient->getImageWidth(), $gradient->getImageHeight(), new ImagickPixel('black'));
//Blend left half into final image
$canvas->compositeimage(
$left,
Imagick::COMPOSITE_BLEND,
0, 0
);
//Blend Right half into final image
$canvas->compositeimage(
$right,
Imagick::COMPOSITE_BLEND,
$offsetX, 0
);
//Output the final image
$canvas->setImageFormat('png');
header("Content-Type: image/png");
echo $canvas->getImageBlob();
// And Robert is your father's brother.
Related
I need help (My english is not good, please try to understand what i'm trying to find). Currently i'm working in a project based on image transformation, where i'm using imagick to transform image. I'm successfully transformed my image. What i am doing in my project is taking a photo(photo1), placing it to another photo (photo2 {the grey are is transparent}) which create the following effect photo3. Then replaceing it again with photo2 (to create the mask effect which showing the hand), and the result is (photo4). But the problem is, photo1 area in photo4 gets darker. {Please compare photo3 and photo4}. Can anyone help me how to keep the original color of photo1 in photo4. Here is my code:
$image1 = new imagick( public_path("img/testImage2.jpg") );
$image2 = new imagick( public_path("storage/Templates/romantisch copy.png"));
$image3 = new imagick( public_path("storage/Templates/romantisch copy.png") );
//for preserving transparency
$image2->mergeImageLayers(\Imagick::LAYERMETHOD_FLATTEN);
$image3->mergeImageLayers(\Imagick::LAYERMETHOD_FLATTEN);
//resizing photo1
$image1->resizeImage(468, 729, Imagick::FILTER_LANCZOS, 1);
/* Fill background area with transparent */
$image1->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
// $image2->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
$image1->setImageArtifact('compose:args', "1,0,-0.5,0.5");
$image1->setImageMatte(true);
$controlPoints = array(
0, 0, //initial point (top left)
0, 0, //targeted point (top left)
0, $image1->getImageHeight(), //initial point (bottom left)
0, $image1->getImageHeight(), //targeted point (bottom left)
$image1->getImageWidth(), 0, //initial point (top right)
$image1->getImageWidth(), 0, //targeted point (top right)
$image1->getImageWidth(), $image1->getImageHeight(), //initial point (bottom right)
$image1->getImageWidth(), $image1->getImageHeight() //targeted point (bottom right)
);
// /* Perform the distortion */
$image1->distortImage(Imagick::DISTORTION_PERSPECTIVE, $controlPoints, true);
$image2->compositeImage($image1, Imagick::COMPOSITE_OVER, 720, 368);
$image2->compositeImage($image3, Imagick::COMPOSITE_OVER, 0, 0);
/* Ouput the image */
header("Content-Type: image/png");
$image2->writeImage ("test_0.png");
echo $image2;
Found my solution. Changing my colorspace solved the problem. still don't know why.
$image2->transformImageColorspace(\Imagick::COLORSPACE_XYZ);
$image3->transformImageColorspace(\Imagick::COLORSPACE_XYZ);
I want to stay away from using exec if possible. I have a jpg image on the server that never changes. I just want to place some text over the top of it but I want that text to be curved and virticle. So far I have created the virticle curved text with a transparent background. Now I just want to slide it over an image that is already made and sitting on the server. Is this possible to do with out saving the generated text image I have?
I have been playing with compositeImage but I am messing something up because the page fails to load with no error.
Here is what I have so far:
$phone='555-555-5555';
$draw = new ImagickDraw();
$draw->setFontSize(48);
$draw->setStrokeAntialias(true);
$draw->setTextAntialias(true);
$draw->setFillColor('#'.$color);
$textOnly = new Imagick();
$textOnly->newImage(900, 300, "none");
$textOnly->setImageFormat('png');
$textOnly->annotateImage($draw, 0, 100, 0, $phone);
$distort = array(270);
$textOnly->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
$textOnly->setImageMatte(true);
$textOnly->distortImage(Imagick::DISTORTION_ARC, $distort, false);
$textOnly->setImagePage(0, 0, 0, 0);
$textOnly->setformat('png');
$textOnly->cropImage(170, 445, 45, 105);
header("Content-Type: image/png");
print $textOnly->getimageblob();
I have also tried the above code with this at the end but I get 500 errors:
$bgImage->readImage(BASE_PATH.'/src-images/background.jpg');
$bgImage->compositeImage($textOnly, Imagick::COMPOSITE_DEFAULT, 10, 20);
header("Content-Type: image/png");
echo $bgImage->getimageblob();
Here is the resulting image when I get it working with text only and without trying to add the second image:
This resolved it....
$bgImage = new Imagick
NOT
$bgImage->readImage
How to merge images if in image color white get transparency status white color?
I have this situation:
I need this result:
This is not a best result, since I didn't know better method to achieve this. Here is my result:
Here is the PHP:
<?php
/** Set source image location **/
$baseImageSource = 'http://q/stock-photos/tux.png';
$overlayImageSource = 'http://q/stock-photos/firefox-logo-small.jpg';
/** Overlay image configuration **/
// Set this value between 0 and 100. 10 will doing great
$fuzz = 10;
// Set position of overlay image, from top and left;
$overlayTop = 240;
$overlayLeft = 200;
/** Core program **/
// Create Imagick object for source image
$overlayImage = new Imagick( $overlayImageSource );
$finalImage = new Imagick( $baseImageSource );
// Remove overlay image background
$overlayImage->paintTransparentImage(
$overlayImage->getImagePixelColor( 0, 0 ),
0, round( $fuzz * 655.35 )
);
// Set image overlay format
$overlayImage->setImageFormat('png');
// Put overlay image to base image
$finalImage->compositeImage(
$overlayImage, Imagick::COMPOSITE_DEFAULT,
$overlayLeft,
$overlayTop
);
// Set output image format
$finalImage->setImageFormat('png');
// Prepare image and publish!
header('Content-type: image/png');
echo $finalImage;
Basically this is just a modification of this answer (to achieve image merger) and this answer (to achieve background removal). The method used to remove background is Imagick::paintTransparentImage(), with Imagick::getImagePixelColor() is used to detect background color. Then we just need to merge both image with Imagick::compositeImage().
But still, this result is far from perfect, especially if you compare it with image processing app like GIMP or Photoshop. But you should give it a try. Hope it helps :)
You need to use a program like Gimp, add a transparency layer, delete the white from the firefox image, and save as PNG.
I'm using ImageMagick to create transparent images from text with PHP.
I would like to know if it's possible (and how) to add a pattern overlay over the generated image.
The idea is to leave the background transparent and to apply the texture over the text :
The actual result:
The desired result:
Any advice would be greatly appreciated.
Use ImagickDraw to create a "draw" object (it's like a layer), then add it over your image. Here's an example:
// create canvas
$draw = new ImagickDraw();
$draw->setfont('/path/to/your/font.ttf');
// load your overlay image
$overlay = new Imagick('/path/to/your/pattern.png');
// define pattern
$draw->pushPattern('myOverlay', 0, 0,
$overlay->getImageWidth(), $overlay->getImageHeight());
// fill canvas with the pattern (tile)
$draw->composite(Imagick::COMPOSITE_COPY, 0, 0,
$overlay->getImageWidth(), $overlay->getImageHeight(), $overlay);
// destroy pattern
$draw->popPattern();
$draw->setFillPatternURL('#myOverlay');
// put text
$draw->setFontSize(100);
$draw->annotation(0, 0, 'My TextImage');
// create your image (800x400)
$output = new Imagick();
$output->newimage(800, 400, 'transparent');
// this will center your canvas
$output->setGravity(Imagick::GRAVITY_CENTER);
// render canvas on this image
$output->drawImage($draw);
$output->setImageFormat('png');
header('Content-Type: image/png');
print $output;
If you want the overlay to be stretched to fit 800x600, then use that size instead of the pattern size when compositing
I am working on improving one of my Facebook apps by allowing the user to upload an image and apply a styled border, or frame to it (i.e. clouds, stars, sky etc). The user chould also be able to save the image, with the border after it has been applied. This explains a little better what I need:
http://zbrowntechnology.info/ImgDisp/imgdisp.php
If you have any other questions or need more details, please let me know.. I'll edit this post.
Use imagecopy(). The example on that page is done using the transparency option with imagecopymerge() but I don't think you need that.
Using imagecopy() you'll specify the X/Y coordinates to use for positioning:
imagecopy( $borderimage, $topimage, 20, 20, 0, 0, $width, $height);
Where $width and $height will be the entire width and height of the top image. You'll want to replace 20 and 20 with the measurement for how much of the border image will be showing around the borders. You will probably have to resize the top image to the exact dimensions you want, or else it might overlap the border a little too far to the right or bottom. (see imagecopyresampled())
Edit:
Here's a rough way to do the whole process (assuming chosenborder.png is the border they chose, and uploadedimage.png is the image they uploaded. If it's a different image type you'll use the corresponding function).
$borderx = 20; // The width of our border
$border = imagecreatefrompng("chosenborder.png");
$topimage = imagecreatefrompng("uploadedimage.png");
$bordersize = getimagesize($border);
$topimagesize = getimagesize($topimage);
/* The new dimensions of topimage. $borderx*2 means we account for
the border on both left and right, top and bottom. */
$newx = $bordersize[0] - ($borderx*2);
$newy = $bordersize[1] - ($borderx*2);
imagecopyresampled( $topimage_scaled, $topimage, 0, 0, 0, 0,
$newx, $newy, $topimagesize[0], $topimagesize[1]);
/* Merge the images */
imagecopy( $border, $topimage_scaled, $borderx, $borderx,
0, 0, $width, $height);
/* Output the image */
imagepng($border, "newimage.png");
/* Free up the memory occupied by the image resources */
imagedestroy($border);
imagedestroy($topimage);
After the user uploads their image, find chosenborder.png and uploadedimage.png, run the above script, then display newimage.png to the user and you're good to go. Just make sure you call imagedestroy() on the temporary image resources or they'll eat up memory.
If you don't want to keep the generated image on your server, you can omit the second argument to imagepng() which will make it send the image information directly as an image to the browser, in which case you'll want to write the correct image HTTP headers.
Client-side solution by using css3:
checkout the css3 property border-image
(dosen't meet the requirement of saving the img with the border)
Server-side solution by merging 2 different images:
<?php
$imgFile = 'img.jpg';
$brdFile = 'brd.jpg';
$img = addBorder($imgFile,$brdFile);
outputImage($img);
function addBorder($imgFile,$brdFile)
{
$img=imagecreatefromjpeg($imgFile);
$brd=imagecreatefromjpeg($brdFile);
$imgSize = getimagesize($imgFile);
$brdSize = getimagesize($brdFile);
//NOTE: the border img MUST be bigger then the src img
$dst_x = ceil(($brdSize[0] - $imgSize[0])/2);
$dst_y = ceil(($brdSize[1] - $imgSize[1])/2);
imagecopymerge ( $brd, $img, $dst_x, $dst_y, 0, 0, $imgSize[0], $imgSize[1] ,100 );
return $brd;
}
function outputImage($img)
{
header('Content-type: image/png');
imagepng($img);
}
?>