I've got a GD Library upload script which processing and resizes images. After uploading PNGs are getting rendering as a different image, some stock-looking image, on the browser side, yet when opened on disk they are correct. I've re-saved the affected pngs via photoshop and uploaded directly, this fixes the display issue, but when i upload that image via the script the display issue returns, thus the script encoding seems to cause issue with the browser display, but why i know not.
Hosting environment is Hetzner Server.
Upload Sample:
//resize images
protected function resize($img, $w, $h, $newfilename) {
//Check if GD extension is loaded
if (!extension_loaded('gd') && !extension_loaded('gd2')) {
trigger_error("GD is not loaded", E_USER_WARNING);
return false;
}
//Get Image size info
$imgInfo = getimagesize($img);
switch ($imgInfo[2]) {
case 1: $im = imagecreatefromgif($img); break;
case 2: $im = imagecreatefromjpeg($img); break;
case 3: $im = imagecreatefrompng($img); break;
default: trigger_error('Unsupported filetype!', E_USER_WARNING); break;
}
//If image dimension is smaller, do not resize
if ($imgInfo[0] <= $w && $imgInfo[1] <= $h) {
$nHeight = $imgInfo[1];
$nWidth = $imgInfo[0];
}
else{
// yeah, resize it, but keep it proportional
if ($w/$imgInfo[0] > $h/$imgInfo[1]) {
$nWidth = $imgInfo[0]*($h/$imgInfo[1]);
$nHeight = $h;
}
else{
$nWidth = $w;
$nHeight = $imgInfo[1]*($w/$imgInfo[0]);
}
}
$nWidth = round($nWidth);
$nHeight = round($nHeight);
$newImg = imagecreatetruecolor($nWidth, $nHeight);
/* Check if this image is PNG or GIF, then set if Transparent*/
if(($imgInfo[2] == 1) OR ($imgInfo[2]==3)){
imagealphablending($newImg, false);
imagesavealpha($newImg,true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $nWidth, $nHeight, $transparent);
}
imagecopyresampled($newImg, $im, 0, 0, 0, 0, $nWidth, $nHeight, $imgInfo[0], $imgInfo[1]);
//Generate the file, and rename it to $newfilename
switch ($imgInfo[2]) {
case 1: imagegif($newImg,$newfilename); break;
case 2: imagejpeg($newImg,$newfilename,100); break;
case 3: imagepng($newImg,$newfilename,0); break;
default: trigger_error('Failed resize image!', E_USER_WARNING); break;
}
return $newfilename;
}
Can anyone give me some insight into this. Will provide more info if necessary. Ty
EDIT:
Browser Display
Disk Display
I have no clue where that image is coming from, it's on multiple uploads, when browsing the full path to the image on the browser the same image comes up so it's not a pathing issue.
Related
I want to use watermark image with php. This is my reference page
function imagecreatefromfile($image_path)
{
list($width, $height, $image_type) = getimagesize($image_path);
switch ($image_type)
{
case IMAGETYPE_GIF: return imagecreatefromgif($image_path); break;
case IMAGETYPE_JPEG: return imagecreatefromjpeg($image_path); break;
case IMAGETYPE_PNG: return imagecreatefrompng($image_path); break;
default: return ''; break;
}
}
$image = imagecreatefromfile($_GET['image']);
if (!$image) die('Unable to open image');
$watermark = imagecreatefromfile('uploads/files/water.png');
if (!$image) die('Unable to open watermark');
$watermark_pos_x = imagesx($image) - imagesx($watermark) - 8;
$watermark_pos_y = imagesy($image) - imagesy($watermark) - 10;
imagecopy($image, $watermark, $watermark_pos_x, $watermark_pos_y, 0, 0,
imagesx($watermark), imagesy($watermark));
header('Content-Type: image/jpg');
imagejpeg($image, '', 100);
imagedestroy($image);
imagedestroy($watermark);`
but my page seems empty ,
This is my test page
http://www.alanyaticaretrehberi.com/watermark.php?image=uploads/firmaresim/750/address-cikcilli-3jpg.jpeg
this worked in other servers but not worked in my server.
This is my phpinfo page..
http://www.alanyaticaretrehberi.com/php.php
I guess some setting missed in my php settings but i dont know what it is. May be it is about gd library or something else, can you give some advices for this issue.
So I've got this PHP script to scale and crop into a square from the center;
<?PHP
//resize and crop image by center
function resize_crop_image($max_width, $max_height, $source_file, $dst_dir, $quality = 80){
$imgsize = getimagesize($source_file);
$width = $imgsize[0];
$height = $imgsize[1];
$mime = $imgsize['mime'];
switch($mime){
case 'image/gif':
$image_create = "imagecreatefromgif";
$image = "imagegif";
break;
case 'image/png':
$image_create = "imagecreatefrompng";
$image = "imagepng";
$quality = 7;
break;
case 'image/jpeg':
$image_create = "imagecreatefromjpeg";
$image = "imagejpeg";
$quality = 80;
break;
default:
return false;
break;
}
$dst_img = imagecreatetruecolor($max_width, $max_height);
$src_img = $image_create($source_file);
$width_new = $height * $max_width / $max_height;
$height_new = $width * $max_height / $max_width;
//if the new width is greater than the actual width of the image, then the height is too large and the rest cut off, or vice versa
if($width_new > $width){
//cut point by height
$h_point = (($height - $height_new) / 2);
//copy image
imagecopyresampled($dst_img, $src_img, 0, 0, 0, $h_point, $max_width, $max_height, $width, $height_new);
}else{
//cut point by width
$w_point = (($width - $width_new) / 2);
imagecopyresampled($dst_img, $src_img, 0, 0, $w_point, 0, $max_width, $max_height, $width_new, $height);
}
$image($dst_img, $dst_dir, $quality);
if($dst_img)imagedestroy($dst_img);
if($src_img)imagedestroy($src_img);
}
//usage example
resize_crop_image(100, 100, "test.jpg", "test.jpg");p_image(100, 100, "test.jpg", "test.jpg");
?>
You can simply call the following function:
resize_crop_image(100, 100, "test.jpg", "test.jpg");p_image(100, 100, "test.jpg", "test.jpg");
Added to JSFiddle is my HTML5/JQuery preview file before uploading to the server.
1). Do I need to upload the image to the server before running this script?
2). If needing to prior upload, how can I use my form to upload into a temp location, do the job and move to a specific dir and delete the temp dir?
1) Yes, a copy of the image will need to be on server before you can edit/crop it. 2) Uploaded files are automatically stored in the temp directory (they are usually copied out to use the image, but don't have to be). They can be read as an image from the temp directory by your code and PHP will also automatically clean up the file at the end of the script.
When a file gets uploaded, in the $_FILES array there is a key with the tmp name. You can just pass that into your function as the source file and it should work with imagecopyresampled with no issue. The temp name will be something like $_FILES['nameFromFileFieldOnForm']['tmp_name'].
if your source file or destination file is
$source_file = www.example.com/storage/packages/image.jpg
change it to
$source_file = ./storage/packages/image.jpg
It works for me in laravel 5
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
Im developing a website where users can upload multiple images to the server/website, in my upload script I have put an image size limit of 10MB. This is because I thought a lot of modern cameras take large images.
The upload script takes each image, one at a time, and resizes in to 3 different versions, 900x600, 600x450 and a smaller thumbnail image, and also puts a watermark image over the top of the 2 larger images.
I set my php.ini memory_limit to 96MB which I presumed would be easily enough.
After a bit of testing, I was uploading a jpg image which is 6.38MB in size and the resolution is 6143 x 3855 px in size. I received the error message "Fatal error: Allowed memory size of 100663296 bytes exhausted (tried to allocate 24572 bytes)"
Do you think it is reasonable to need this much memory to upload and process an image of this size? or do you think it is more likely a problem with the coding in my script?
96 MB memory limit seems a lot to me. What are other peoples experience dealing with large image uploads? Should I set the memory limit to 128MB or higher? or should I look at rewriting my upload script?
My Code is added below :
//If a new image has been added, resize and upload to filesystem
if ($_FILES['new_image']['name'] !=''){
$allowed_types=array(
'image/gif' => '.gif',
'image/jpeg' => '.jpg',
'image/png' => '.png',
'image/x-png' => '.png',
'image/pjpeg' => '.jpg'
);
$img = $_FILES['new_image'];
// Check the file to be uploaded is the correct file type and is under 9MB
if ((array_key_exists($img['type'], $allowed_types)) && ($img['size'] < 9000000)) {
// File to be uploaded is Valid
// File to be uploaded is Valid
$imagename = stripslashes($_FILES['new_image']['name']);
// make the random file name
$randName = md5(rand() * time());
$ext = pathinfo($imagename, PATHINFO_EXTENSION);
$imagename = $randName . "." . $ext;
$source = $_FILES['new_image']['tmp_name'];
// Check if Directory Exists, if not create it
if(!file_exists("images/breeds/".$trimmed['profile_id']))
{
mkdir("images/breeds/".$trimmed['profile_id']) or die("Could not create images folder for article ".$trimmed['profile_id']);
}
// Check if thumbnail Directory Exists
if(!file_exists("images/breeds/".$trimmed['profile_id']."/thumbs"))
{
mkdir("images/breeds/".$trimmed['profile_id']."/thumbs") or die("Could not create thumbnail folder for article ".$trimmed['profile_id']);
}
// Check if thumbnail Directory Exists
if(!file_exists("images/breeds/".$trimmed['profile_id']."/large"))
{
mkdir("images/breeds/".$trimmed['profile_id']."/large") or die("Could not create thumbnail folder for article ".$trimmed['profile_id']);
}
$LargeImage = "images/breeds/".$trimmed['profile_id']."/large/".$imagename;
$NormalImage = "images/breeds/".$trimmed['profile_id']."/".$imagename;
$SmallImage = "images/breeds/".$trimmed['profile_id']."/thumbs/".$imagename;
//uploaded temp file
$file = $_FILES['new_image']['tmp_name'];
//Get Image size info
list($width, $height, $image_type) = getimagesize($file);
//SourceImage
switch ($image_type)
{
case 1: $image = imagecreatefromgif($file); break;
case 2: $image = imagecreatefromjpeg($file); break;
case 3: $image = imagecreatefrompng($file); break;
default: trigger_error('Unsupported filetype!', E_USER_WARNING); break;
}
// Constraints for Large Image
$max_width = 900;
$max_height = 600;
$ratioh = $max_height/$height;
$ratiow = $max_width/$width;
$ratio = min($ratioh, $ratiow);
if (($height < $max_height) && ($width < $max_width)) {
//keep same dimensions
$modwidth = $width;
$modheight = $height;
} else {
// New dimensions
$modwidth = intval($ratio*$width);
$modheight = intval($ratio*$height);
}
$tmpLarge = imagecreatetruecolor( $modwidth, $modheight );
imagecopyresampled($tmpLarge, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height) ;
// Add Watermark to large image at top right
$wm = "images/p4h-wm-200.png";
$wmImage = imagecreatefrompng($wm);
$wmW = imagesx($wmImage);
$wmH = imagesy($wmImage);
$photoW = imagesx($tmpLarge);
$photoH = imagesy($tmpLarge);
$dest_x = $photoW - $wmW - 10;
$dest_y = 10;
// imagecopymerge($tn, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH, 100);
imagecopy($tmpLarge, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH);
switch ($image_type)
{
case 1: imagegif($tmpLarge,$LargeImage); break;
case 2: imagejpeg($tmpLarge,$LargeImage, 80); break;
case 3: imagepng($tmpLarge,$LargeImage, 0); break;
default: trigger_error('Failed resize image!', E_USER_WARNING); break;
}
// Destroy tmp images to free memory
imagedestroy($tmpLarge);
imagedestroy($wmImage);
// Constraints for Normal Image
$max_width = 550;
$max_height = 413;
$ratioh = $max_height/$height;
$ratiow = $max_width/$width;
$ratio = min($ratioh, $ratiow);
if (($height < $max_height) && ($width < $max_width)) {
//keep same dimensions
$modwidth = $width;
$modheight = $height;
} else {
// New dimensions
$modwidth = intval($ratio*$width);
$modheight = intval($ratio*$height);
}
$tmpNormal = imagecreatetruecolor( $modwidth, $modheight );
imagecopyresampled($tmpNormal, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height) ;
// Add Watermark to large image at top right
$wm = "images/p4h-wm-150.png";
$wmImage = imagecreatefrompng($wm);
$wmW = imagesx($wmImage);
$wmH = imagesy($wmImage);
$photoW = imagesx($tmpNormal);
$photoH = imagesy($tmpNormal);
$dest_x = $photoW - $wmW - 10;
$dest_y = 10;
// imagecopymerge($tn, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH, 100);
imagecopy($tmpNormal, $wmImage, $dest_x, $dest_y, 0, 0, $wmW, $wmH);
switch ($image_type)
{
case 1: imagegif($tmpNormal,$NormalImage); break;
case 2: imagejpeg($tmpNormal,$NormalImage, 90); break;
case 3: imagepng($tmpNormal,$NormalImage, 0); break;
default: trigger_error('Failed resize image!', E_USER_WARNING); break;
}
// Destroy tmp images to free memory
imagedestroy($tmpNormal);
imagedestroy($wmImage);
// Now that the full size image has been saved, resize the thumbnail one to a fixed size for homepage display
// Constraints
$thumb_width = 150;
$thumb_height = 112.5;
// Calculate stuff and resize image accordingly
$src_ratio = $width/$height;
$dst_ratio = $thumb_width/$thumb_height;
if($src_ratio < $dst_ratio) // trim top and bottom
{
$ratio = $width/$thumb_width;
$crop_height = $thumb_height*$ratio;
$src_y = round(($height-$crop_height)/2);
$crop_width = $width;
$src_x = 0;
}
else // trim left and right
{
$ratio = $height/$thumb_height;
$crop_width = $thumb_width*$ratio;
$src_x = round(($width-$crop_width)/2);
$crop_height = $height;
$src_y = 0;
}
$tmpSmall = imagecreatetruecolor( $thumb_width, $thumb_height );
imagecopyresampled($tmpSmall, $image, 0, 0, $src_x, $src_y, $thumb_width, $thumb_height, $crop_width, $crop_height);
switch ($image_type)
{
case 1: imagegif($tmpSmall,$SmallImage); break;
case 2: imagejpeg($tmpSmall,$SmallImage, 90); break;
case 3: imagepng($tmpSmall,$SmallImage, 0); break;
default: trigger_error('Failed resize image!', E_USER_WARNING); break;
}
// Destroy images to free memory
imagedestroy($image);
imagedestroy($tmpSmall);
jpg is 6.38MB , but to transform image, the internal representation used is the raw uncompressed one.
your image is 23.6 Mega Pixel
the uncompressed representation of it could be 32bit (4Bytes) per pixel, ie : 4*23.6MBytes = 94 MBytes.
So, i would say, do you need to have such big images to process ?
if yes, put memory_limit higher
if no , limit the uploadable image size to something more reasonable to process within your memory settings.
You probably need to give more hints to PHP on when the memory can be released. A simple $some_variable = null; is usually enough.
Once you're finished with an image (the main image and each of its thumbnails), set the referencing variable to null to help free up memory.
Otherwise, try printing out or logging the results of memory_get_usage() (http://www.php.net/manual/en/function.memory-get-usage.php) at the top of your script and in various places throughout your script to track down where memory is getting bogged down.
A 6143x3855 image will require AT LEAST 71,043,795 bytes of memory just for the raw pixel data (3 bytes per pixel). Then you create a series of other images to hold resized versions of the original, etc...
No wonder you're running out of memory.
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