i am using this code to create watermark.
$image = '1.jpg';
$overlay = 'stamp.png';
$opacity = "20";
if (!file_exists($image)) {
die("Image does not exist.");
}
// Set offset from bottom-right corner
$w_offset = 0;
$h_offset = 100;
$extension = strtolower(substr($image, strrpos($image, ".") + 1));
// Load image from file
switch ($extension)
{
case 'jpg':
$background = imagecreatefromjpeg($image);
break;
case 'jpeg':
$background = imagecreatefromjpeg($image);
break;
case 'png':
$background = imagecreatefrompng($image);
break;
case 'gif':
$background = imagecreatefromgif($image);
break;
default:
die("Image is of unsupported type.");
}
// Find base image size
$swidth = imagesx($background);
$sheight = imagesy($background);
// Turn on alpha blending
imagealphablending($background, true);
// Create overlay image
$overlay = imagecreatefrompng($overlay);
// Get the size of overlay
$owidth = imagesx($overlay);
$oheight = imagesy($overlay);
// Overlay watermark
imagecopymerge($background, $overlay, $swidth - $owidth - $w_offset, $sheight - $oheight - $h_offset, 0, 0, $owidth, $oheight, $opacity);
imagejpeg($background,$image);
// Destroy the images
imagedestroy($background);
imagedestroy($overlay);
the png image contains a text with all other region as transparent.
but when i execute this code , it applys the png over jpg, but the transparecy is not maintained of the png. it shows in a box.
how can i acheive that . ie if a png contains transaparent part , it should show the below image in that part....?
replacing imagecopymerge with imagecopy solved the issue. here is the new code
function watermark($image){
$overlay = '../../../photos/photosets/stamp.png';
$opacity = "20";
if (!file_exists($image)) {
die("Image does not exist.");
}
// Set offset from bottom-right corner
$w_offset = 0;
$h_offset = 100;
$extension = strtolower(substr($image, strrpos($image, ".") + 1));
// Load image from file
switch ($extension)
{
case 'jpg':
$background = imagecreatefromjpeg($image);
break;
case 'jpeg':
$background = imagecreatefromjpeg($image);
break;
case 'png':
$background = imagecreatefrompng($image);
break;
case 'gif':
$background = imagecreatefromgif($image);
break;
default:
die("Image is of unsupported type.");
}
// Find base image size
$swidth = imagesx($background);
$sheight = imagesy($background);
// Turn on alpha blending
imagealphablending($background, true);
// Create overlay image
//$overlay = imagecreatefrompng($overlay);
// Get the size of overlay
$owidth = imagesx($overlay);
$oheight = imagesy($overlay);
$photo = imagecreatefromjpeg($image);
$watermark = imagecreatefrompng($overlay);
// This is the key. Without ImageAlphaBlending on, the PNG won't render correctly.
imagealphablending($photo, true);
// Copy the watermark onto the master, $offset px from the bottom right corner.
$offset = 10;
imagecopy($photo, $watermark, imagesx($photo) - imagesx($watermark) - $offset, imagesy($photo) - imagesy($watermark) - $offset, 0, 0, imagesx($watermark), imagesy($watermark));
// Output to the browser
header("Content-Type: image/jpeg");
imagejpeg($photo,$image);
// Overlay watermark
// Destroy the images
imagedestroy($background);
imagedestroy($overlay);
}
The jpg format doesn't support transparency, so conceptually you will have to:
grab the pixels from the larger image (the jpeg) and put them into a buffer
grab the non-transparent pixels from the smaller image (the watermark) and move them into that buffer, applying the alpha along the way
You probably want to let a library do this. I like ImageMagick, especially since it's built in to php... here's an example of how to use it for this purpose from PHP:
// Let's read the images.
$glasses = new Imagick();
if (FALSE === $glasses->readImage($dir . '/glasses.png'))
{
throw new Exception();
}
$face = new Imagick();
if (FALSE === $face->readImage($dir . '/face.jpg'))
{
throw new Exception();
}
// Let's put the glasses on (10 pixels from left, 20 pixels from top of face).
$face->compositeImage($glasses, Imagick::COMPOSITE_DEFAULT, 10, 20);
And here's the link to the PHP manual page for ImageMagick::compositeImage (from which the above example came).
Have you tried using imagecopyresampled()?
http://php.net/manual/en/function.imagecopyresampled.php
Related
I'm currently trying to work with pictures and PHP, thanks to GD functions.
Now I would like to modify the size of PNG pictures. Here is an example of a PNG I'd like to resize :
The dotted line represent the border of the PNG, the background is transparent, and I only have a star lost on the middle of a large space. I'd like to crop this star, to get a simple square of the star (even if the new background becomes blank, It doesn't matter).
How could I do something like that efficiently ? I thought about doing a loop checking every pixel of the picture.. Trying to find where the image is, to finally crop with a little margin based on the minimum x / maximum X and minimum y / maximum y values, but If I start working with hundreds of pictures, It would be really long.
EDIT :
<?php
$file = "./crop.png";
$ext = pathinfo($file, PATHINFO_EXTENSION);
$image;
switch ($ext){
case 'png':
$image = imagecreatefrompng($file);
break;
case 'jpeg':
case 'jpg':
$image = imagecreatefromjpeg($file);
break;
case 'gif':
$image = imagecreatefromgif($file);
break;
}
$cropped = imagecropauto($image, IMG_CROP_DEFAULT);
if ($cropped !== false) { // in case a new image resource was returned
echo "=> Cropping needed\n";
imagedestroy($image); // we destroy the original image
$image = $cropped; // and assign the cropped image to $im
}
imagepng($image, "./cropped.png");
imagedestroy($image);
If you read and follow the php php-gd documentation, you'll find a function called imagecropauto which does exactly what you want, it crops the alpha channel of the image.
Crop an PNG image with alpha channel
$im = imagecreatefrompng("./star-with-alpha.png");
$cropped = imagecropauto($im, IMG_CROP_DEFAULT);
if ($cropped !== false) { // in case a new image resource was returned
imagedestroy($im); // we destroy the original image
$im = $cropped; // and assign the cropped image to $im
}
imagepng($im, "./star-with-alpha-crop.png");
imagedestroy($im);
You can try it dirrectly to a php page using this code:
<body>
<img src="star-with-alpha.png">
<?php
$im = imagecreatefrompng("./star-with-alpha.png");
$cropped = imagecropauto($im, IMG_CROP_DEFAULT);
if ($cropped !== false) { // in case a new image resource was returned
imagedestroy($im); // we destroy the original image
$im = $cropped; // and assign the cropped image to $im
}
imagepng($im, "./star-with-alpha-crop.png");
imagedestroy($im);
?>
<img src="star-with-alpha-crop.png">
</body>
The result
http://zikro.gr/dbg/php/crop-png/
[This is for ubuntu 12]
The only problem with the imagecropauto is that it works only on Mac & Windows.
And since most of the servers today use ubuntu/debain - this function is of no use.
Instead use Imagick() for this.
Here is a sample code I wrote which does exactly this:
//Add background transmparent
$background = 'none';
$image = new Imagick($path);
$image->trimImage(0);
//add transparent border
//border add start
/** Set border format **/
$borderWidth = 20;
$borderColor = 'none';
$borderPadding = 10;
$imageWidth = $image->getImageWidth() + ( 2 * ( $borderWidth +
$borderPadding ) );
$imageHeight = $image->getImageHeight() + ( 2 * ( $borderWidth +
$borderPadding ) );
Create Imagick object for final image with border
$imageWithBorder = new Imagick();
// Set image canvas
$imageWithBorder->newImage( $imageWidth, $imageHeight, new ImagickPixel(
'none' ));
// Create ImagickDraw object to draw border
$border = new ImagickDraw();
// Set fill color to transparent
$border->setFillColor( 'none' );
// Set border format
$border->setStrokeColor( new ImagickPixel( $borderColor ) );
$border->setStrokeWidth( $borderWidth );
$border->setStrokeAntialias( false );
Draw border
$border->rectangle(
$borderWidth / 2 - 1,
$borderWidth / 2 - 1,
$imageWidth - ( ($borderWidth / 2) ),
$imageHeight - ( ($borderWidth / 2) )
);
// Apply drawed border to final image
$imageWithBorder->drawImage( $border );
$imageWithBorder->setImageFormat('png');
Save Image
// Put source image to final image
$imageWithBorder->compositeImage(
$image, Imagick::COMPOSITE_DEFAULT,
$borderWidth + $borderPadding,
$borderWidth + $borderPadding
);
$imageWithBorder->writeImage($path);
Recenter and fit to original image height and width
$imageWithBorder->scaleImage(FINAL_WIDTH, FINAL_HEIGHT, true);
$imageWithBorder->setImageBackgroundColor($background);
$w = $imageWithBorder->getImageWidth();
$h = $imageWithBorder->getImageHeight();
$imageWithBorder->extentImage(FINAL_WIDTH, FINAL_HEIGHT, ($w -
FINAL_WIDTH) / 2, ($h - FINAL_HEIGHT)/ 2);
$imageWithBorder->writeImage($path);
Hope it helps.
Cheers!
Is there any way to resize the $_FILES["xfile1"]["tmp_name"] before I send it off to the move_uploaded_file() function? I checked every where but nobody seems to use this function after resizing the image.
ADDED*
// Create image from file
switch(strtolower($_FILES['xfile1']['type']))
{
case 'image/jpeg':
$image = imagecreatefromjpeg($_FILES['xfile1']['tmp_name']);
break;
case 'image/png':
$image = imagecreatefrompng($_FILES['xfile1']['tmp_name']);
break;
case 'image/gif':
$image = imagecreatefromgif($_FILES['xfile1']['tmp_name']);
break;
default:
exit('Unsupported type: '.$_FILES['xfile1']['type']);
}
// Delete original file
#unlink($_FILES['image']['tmp_name']);
// Target dimensions
$max_width = 540;
$max_height = 540;
// Get current dimensions
$old_width = imagesx($image);
$old_height = imagesy($image);
// Calculate the scaling we need to do to fit the image inside our frame
$scale = min($max_width/$old_width, $max_height/$old_height);
// Get the new dimensions
$new_width = ceil($scale*$old_width);
$new_height = ceil($scale*$old_height);
// Create new empty image
$new = imagecreatetruecolor($new_width, $new_height);
// Resample old into new
imagecopyresampled($new, $image,
0, 0, 0, 0,
$new_width, $new_height, $old_width, $old_height);
ob_start();
imagejpeg($new,'saved.jpeg' , 90);
$data = ob_get_clean();
So i have this so far. I have this $data variable which i want to replace with $_FILES["xfile1"]["tmp_name"] in the move_uploaded_file() function. Is that possible?
Thanks in Advance.
I am trying to allow the uploading of transparent profile pictures (PNGs and GIFs) on my site because it is sometimes quite annoying for the user to upload a transparent profile picture and the transparent areas become black. The problem is that the transparency is still being lost even after using the imagealpha*() functions.
I do realize that there are other questions about this, but the answers on them aren't working for me.
Here is my code:
// [...]
switch(strtolower($_FILES['picture']['type'])) {
case 'image/jpeg':
$image = imagecreatefromjpeg($_FILES['picture']['tmp_name']);
break;
case 'image/png':
$image = imagecreatefrompng($_FILES['picture']['tmp_name']);
break;
case 'image/gif':
$image = imagecreatefromgif($_FILES['picture']['tmp_name']);
break;
default:
msg('Sorry, but the type of file that you selected is not allowed. We only allow JPEG, PNG, and GIF.','error');
header("Location: /settings/profile");
exit;
}
// Target dimensions
$max_width = 143;
$max_height = 143;
// Get current dimensions
$old_width = imagesx($image);
$old_height = imagesy($image);
// Calculate the scaling we need to do to fit the image inside our frame
$scale = min($max_width/$old_width, $max_height/$old_height);
// Get the new dimensions
$new_width = ceil($scale*$old_width);
$new_height = ceil($scale*$old_height);
// Create new empty image
$new = imagecreatetruecolor($new_width, $new_height);
// Resize old image into new
imagecopyresampled($new, $image, 0, 0, 0, 0, $new_width, $new_height, $old_width, $old_height);
$file_name = 'avatar_'.randString(20).mt_rand(111,999).'.'.str_replace('image/','',$_FILES['picture']['type']);
switch(strtolower($_FILES['picture']['type'])) {
case 'image/jpeg':
$img = imagejpeg($new, 'user/uploads/'.$file_name, 95);
break;
case 'image/png':
imagealphablending($new, false);
imagesavealpha($new, true);
$img = imagepng($new, 'user/uploads/'.$file_name, 95);
break;
case 'image/gif':
imagealphablending($new, false);
imagesavealpha($new, true);
$img = imagegif($new, 'user/uploads/'.$file_name);
break;
}
imagedestroy($image);
imagedestroy($new);
if($img) {
$dbUpdate = mysql_query("UPDATE users SET user_pic = '$file_name' WHERE uid = $userid");
}
if($img && $dbUpdate) {
msg("Your profile picture has been changed successfully.","success");
header("Location: /settings/profile");
exit;
}
// [...]
I tried uploading this GIF just for testing:
But it lost its transparency after it was uploaded:
I am trying to keep the transparency information with it, but it doesn't seem to be working. Am I not doing something right?
Thanks in advance.
Create a transparent color and fill the $new image with that color before the copy. If you don't do that, the background color of the new image will default to black.
$new = imagecreatetruecolor($new_width, $new_height);
$transparent = imagecolorallocatealpha($new, 0, 0, 0, 127);
imagefill($new, 0, 0, $transparent);
imagealphablending($new, true);
You can also check this question
I am trying to add a watermark to an image using PHP and the GD image library. I can apply the watermark where I specify with the correct opacity setting.
The problem is that my watermark itself has a transparent background. When I try to apply this watermark to the image I get a black background.
The image which the watermark is being applied to is a jpeg. Could this be the problem? If so how would I convert the jpeg into a format which supports transparency, apply watermark, then convert it back?
This is the key bit of code I have at the moment.
// Determine image size and type
$size = getimagesize($this->image_path);
$size_x = $size[0];
$size_y = $size[1];
$image_type = $size[2]; // This is always a JPEG
// load source image
$image = $this->ImageCreateFromType($image_type, $this->image_path);
// Determine watermark size and type
$wsize = getimagesize($watermark_path);
$watermark_x = $wsize[0];
$watermark_y = $wsize[1];
$watermark_type = $wsize[2]; // This is typically a PNG
// load watermark
$watermark = $this->ImageCreateFromType($watermark_type, $watermark_path);
$dest_x = $this->setX($size_x, $watermark_x);
$dest_y = $this->setY($size_y, $watermark_y);
imagecopymerge($image, $watermark, $dest_x, $dest_y, 0, 0, $watermark_x, $watermark_y, $this->opacity);
While not really relevant, here is the code for the ImageCreateFromType function
function ImageCreateFromType($type,$filename) {
$im = null;
switch ($type) {
case 1:
$im = ImageCreateFromGif($filename);
break;
case 2:
$im = ImageCreateFromJpeg($filename);
break;
case 3:
$im = ImageCreateFromPNG($filename);
imagealphablending($im, true);
imagesavealpha($im, true);
break;
}
return $im;
}
Have a read about the imagecolortransparent() function: http://php.net/manual/en/function.imagecolortransparent.php
You may also want to look at this question: Can PNG image transparency be preserved when using PHP's GDlib imagecopyresampled?
I'm using imagecopyresampled to create thumbnails based on a certain width and height. The problem I'm having is that their height is being squished. What I want is for all thumbnail images to be 140x84 and if their aspect ratio does not match that the top and bottom extra portions of the image are cropped to center.
Here is what I have so far, any ideas would be greatly appreciated.
// Create Thumbnail
$imgsize = getimagesize($targetFile);
switch(strtolower(substr($targetFile, -3))){
case "jpg":
$image = imagecreatefromjpeg($targetFile);
break;
case "png":
$image = imagecreatefrompng($targetFile);
break;
case "gif":
$image = imagecreatefromgif($targetFile);
break;
default:
exit;
break;
}
$width = 140; //New width of image
$height = $imgsize[1]/$imgsize[0]*$width; //This maintains proportions
$x_mid = $width/2; //horizontal middle
$y_mid = $height/2; //vertical middle
$src_w = $imgsize[0];
$src_h = $imgsize[1];
$picture = imagecreatetruecolor($width, $height);
imagealphablending($picture, false);
imagesavealpha($picture, true);
$bool = imagecopyresampled($picture, $image, 0, 0, 0, ($y_mid-(84/2)), $width, $height, $src_w, $src_h);
if($bool){
switch(strtolower(substr($targetFile, -3))){
case "jpg":
header("Content-Type: image/jpeg");
$bool2 = imagejpeg($picture,$file_dir."/thumbs/".$imageName,85);
break;
case "png":
header("Content-Type: image/png");
imagepng($picture,$file_dir."/thumbs/".$imageName);
break;
case "gif":
header("Content-Type: image/gif");
imagegif($picture,$file_dir."/thumbs/".$imageName);
break;
}
}
imagedestroy($picture);
imagedestroy($image);
You need to first work out if you're going to re-size your image based on it's height or width. You'd usually work this out depending if your original image is portrait or landscape, and the orientation of your desired image size. You then need to work out the other edge programmatically from your choice.
Once you have, you can simple resample your original image at (0,0) and the over-hanging image data will be truncated.