I made a function to handle jpg and png files, but i get error when trying to upload a png file.
this is the function:
function createImg ($type, $src, $dst, $width, $height, $quality) {
$newImage = imagecreatetruecolor($width,$height);
if ($type == "jpg/jpeg") {
//imagecreatefromjpeg() returns an image identifier representing the image obtained from the given filename.
$source = imagecreatefromjpeg($src);
}
else if ($type == "png") {
//imagecreatefrompng() returns an image identifier representing the image obtained from the given filename.
$source = imagecreatefrompng($src);
}
imagecopyresampled($newImage,$source,0,0,0,0,$width,$height,getWidth($src),getHeight($src));
if ($type == "jpg/jpeg") {
//imagejpeg() creates a JPEG file from the given image.
imagejpeg($newImage,$dst,$quality);
}
else if ($type == "png") {
//imagepng() creates a PNG file from the given image.
imagepng($newImage,$dst,$quality);
}
return $dst;
}
works as it should with jpg, but with png i get this error msg:
Warning: imagepng() [function.imagepng]: gd-png: fatal libpng error: zlib failed to initialize compressor -- stream error in E:...\php\functions.upload.php on line 48
Warning: imagepng() [function.imagepng]: gd-png error: setjmp returns error condition in E:...\php\functions.upload.php on line 48
EDIT :
i just changed removed the imagepng(); and used only imagejpeg and it worked like this, i just want jpg files saved anyways. thanks!
The problem is because imagejpeg quality can be up to 100, whereas imagepng maximum quality is 9.
try this
else if ($type == "png") {
//imagepng() creates a PNG file from the given image.
$q=9/100;
$quality*=$q;
imagepng($newImage,$dst,$quality);
}
What value are you using for the quality setting? imagepng() uses values 0-9, whereas imagejpeg() uses 0-100.
Johnny Craig's answer is correct except one thing, it has inverse relationship. 9 - is the most possible compression, and 0 - no compression, so the most possible quality.
if ($type == 'png') {
$quality = round((100 - $quality) * 0.09);
}
Related
I am trying to compress & resize my images using the php GD library. Nearly every answer on SO and everywhere else is the same, but for my solution, the PNG's are not being correctly transformed, and some jpg's are giving bizarre results.
This is the code I am using:
public function resizeImages() {
ini_set('max_execution_time', 0);
//Initial settings, Just specify Source and Destination Image folder.
$ImagesDirectory = FCPATH . 'design/img/test/'; //Source Image Directory End with Slash
$DestImagesDirectory = FCPATH . 'design/img/test/thumb/'; //Destination Image Directory End with Slash
$NewImageWidth = 150; //New Width of Image
$NewImageHeight = 150; // New Height of Image
$Quality = 90; //Image Quality
//Open Source Image directory, loop through each Image and resize it.
if($dir = opendir($ImagesDirectory)){
while(($file = readdir($dir))!== false){
$imagePath = $ImagesDirectory.$file;
$destPath = $DestImagesDirectory.$file;
$checkValidImage = #getimagesize($imagePath);
if(file_exists($imagePath) && $checkValidImage) //Continue only if 2 given parameters are true
{
//Image looks valid, resize.
if (resize_image($imagePath,$destPath,$NewImageWidth,$NewImageHeight,$Quality))
{
echo $file.' resize Success!<br />';
/*
Now Image is resized, may be save information in database?
*/
} else {
echo $file.' resize Failed!<br />';
}
}
}
closedir($dir);
}
}
and the resize_image function looks like this:
function resize_image($SrcImage,$DestImage, $MaxWidth,$MaxHeight,$Quality)
{
list($iWidth,$iHeight,$type) = getimagesize($SrcImage);
$ImageScale = min($MaxWidth/$iWidth, $MaxHeight/$iHeight);
$NewWidth = ceil($ImageScale*$iWidth);
$NewHeight = ceil($ImageScale*$iHeight);
$NewCanves = imagecreatetruecolor($NewWidth, $NewHeight);
$imagetype = strtolower(image_type_to_mime_type($type));
switch($imagetype)
{
case 'image/jpeg':
$NewImage = imagecreatefromjpeg($SrcImage);
break;
case 'image/png':
$NewImage = imagecreatefrompng($SrcImage);
break;
default:
return false;
}
//allow transparency for pngs
imagealphablending($NewCanves, false);
imagesavealpha($NewCanves, true);
// Resize Image
if(imagecopyresampled($NewCanves, $NewImage,0, 0, 0, 0, $NewWidth, $NewHeight, $iWidth, $iHeight))
{
switch ($imagetype) {
case 'image/jpeg':
if(imagejpeg($NewCanves,$DestImage,$Quality))
{
imagedestroy($NewCanves);
}
break;
case 'image/png':
if(imagepng($NewCanves,$DestImage,$Quality))
{
imagedestroy($NewCanves);
}
break;
default:
return false;
}
return true;
}
}
Every single png is not working, it just returns a file with 0 bytes and "file type is not supported", even though the type is recognized as .PNG in Windows...
Some JPG's return a weird result as well, see the following screenshot which indicates my issues regarding png's and some jpg's:
1) Do not use getimagesize to verify that the file is a valid image, to mention the manual:
Do not use getimagesize() to check that a given file is a valid image. Use a purpose-built solution such as the Fileinfo extension instead.
$checkValidImage = exif_imagetype($imagePath);
if(file_exists($imagePath) && ($checkValidImage == IMAGETYPE_JPEG || $checkValidImage == IMAGETYPE_PNG))
2) While imagejpeg() accepts quality from 0 to 100, imagepng() wants values between 0 and 9, you could do something like that:
if(imagepng($NewCanves,$DestImage,round(($Quality/100)*9)))
3) Using readdir () you should skip the current directory . and the parent..
while(($file = readdir($dir))!== false){
if ($file == "." || $file == "..")
continue;
edit
Point 2 is particularly important, imagepng () accepts values greater than 9 but then often fails with error in zlib or libpng generating corrupt png files.
I tried resizing some png and jpeg and I didn't encounter any problems with these changes.
When running Page Speed in Google Chrome it suggests to optimize/compress the images. These images are mostly uploaded by users, so I would need to optimize them during uploading. What I find about optimizing jpeg images with php is something like using the following GD functions:
getimagesize()
imagecreatefromjpeg()
imagejpeg()
Since I am resizing the images after upload I'm already pulling the image through these functions and in addition I use imagecopyresampled() after imagecreatefromjpeg() to resize it.
But then, Page Speed is still telling me these images can be optimized. How can I accomplish this optimisation in a php script? Set the quality lower in imagejpeg() doesn't make a difference either.
The imagejpeg function is where you assign the quality. If you're already setting that to an appropriate value then there is little else you can do.
Page speed probably considers all images above a certain size to be "needing compression", perhaps just ensure they are all as small as reasonable (in terms of height/width) and compressed.
You can find more about page speed and it's compression suggestions on the pagespeed docs http://code.google.com/speed/page-speed/docs/payload.html#CompressImages which describes some of the techniques/tools to compress appropriately.
I've also just read the following:
Several tools are available that perform further, lossless compression on JPEG and PNG files, with no effect on image quality. For JPEG, we recommend jpegtran or jpegoptim (available on Linux only; run with the --strip-all option). For PNG, we recommend OptiPNG or PNGOUT.
So perhaps (if you really want to stick to Google's suggestions) you could use PHP's exec to run one of those tools on files as they are uploaded.
To compress with php you do the following (sounds like you are already doing this):
Where $source_url is the image, $destination_url is where to save and $quality is a number between 1 and 100 choosing how much jpeg compression to use.
function compressImage($source_url, $destination_url, $quality) {
$info = getimagesize($source_url);
if ($info['mime'] == 'image/jpeg') $image = imagecreatefromjpeg($source_url);
elseif ($info['mime'] == 'image/gif') $image = imagecreatefromgif($source_url);
elseif ($info['mime'] == 'image/png') $image = imagecreatefrompng($source_url);
//save file
imagejpeg($image, $destination_url, $quality);
//return destination file
return $destination_url;
}
Repaired function:
function compressImage($source_url, $destination_url, $quality) {
//$quality :: 0 - 100
if( $destination_url == NULL || $destination_url == "" ) $destination_url = $source_url;
$info = getimagesize($source_url);
if ($info['mime'] == 'image/jpeg' || $info['mime'] == 'image/jpg')
{
$image = imagecreatefromjpeg($source_url);
//save file
//ranges from 0 (worst quality, smaller file) to 100 (best quality, biggest file). The default is the default IJG quality value (about 75).
imagejpeg($image, $destination_url, $quality);
//Free up memory
imagedestroy($image);
}
elseif ($info['mime'] == 'image/png')
{
$image = imagecreatefrompng($source_url);
imageAlphaBlending($image, true);
imageSaveAlpha($image, true);
/* chang to png quality */
$png_quality = 9 - round(($quality / 100 ) * 9 );
imagePng($image, $destination_url, $png_quality);//Compression level: from 0 (no compression) to 9(full compression).
//Free up memory
imagedestroy($image);
}else
return FALSE;
return $destination_url;
}
You could use Imagick class for this. Consider following wrapper function:
<?php
function resizeImage($imagePath, $width, $height, $blur, $filterType = Imagick::FILTER_LANCZOS, $bestFit = false)
{
//The blur factor where > 1 is blurry, < 1 is sharp.
$img= new \Imagick(realpath($imagePath));
$img->setCompression(Imagick::COMPRESSION_JPEG);
$img->setCompressionQuality(40);
$img->stripImage();
$img->resizeImage($width, $height, $filterType, $blur, $bestFit);
$img->writeImage();
}
?>
Read more on how to resize images with Imagick at:
http://php.net/manual/en/class.imagick.php
http://php.net/manual/en/imagick.resizeimage.php
http://php.net/manual/en/imagick.constants.php#imagick.constants.filters
it is very important to optimize your images. Several CMS platforms out there have modules or plugins to preform this process. However if you are programming it yourself there is a complete php tutorial located at this page https://a1websitepro.com/optimize-images-with-php-in-a-directory-on-your-server/ You will be shown how to implement the imagecreatefromjpeg($SrcImage); and imagecreatefrompng($SrcImage); and imagecreatefromgif($SrcImage); There are written and video instruction on the page.
I'm making a website for fun but I cant seem to figure out why this piece of code wont work:
// error control
ini_set('display_errors', 'On');
error_reporting(E_ALL | E_STRICT);
// loading in the image.
$img = imagecreatefromjpeg(".\image\ons\Ons-foto\mayor.jpg");
if($img != null){
$width = imagesx($img);
$heigth = imagesy($img);
$calw = 134*7;
$calh = 122*7;
$newimg = null;
if($width != null && $heigth != null){
// a check to see if the image is the right size
if($width > $calw || $width < $calh || $heigth < $calh || $heigth > $calh)
{
// here i save the resized image into the variable $newimg
imagecopyresized($newimg, $img, 0,0,0,0, $calw, $calh, $width, $heigth);
} else {
$newimg = $img;
}
$tempimg = null;
// a nested loop to automatically cut the image into pieces
for($w = 0; $w < $calw; $w+134){
for($h = 0; $h < $calh; $h+122){
// taking a piece of the image and save it into $tempimg
imagecopy($tempimg, $newimg, 0, 0, $w, $h, 134, 122);
// showing the image on screen
echo '<div class="blokken" style="margin: 1px;">';
imagejpeg($tempimg);
echo '</div>';
}
}
}
}
what I am trying to do is:
load in the image and resize it to the right size.
cut it in pieces
show it piece by piece with a little bit of space between them (i do that in a .css file hence the div tag)
these are the errors that i get:
Warning: imagecopyresized(): supplied argument is not a valid Image resource in root\ons.php on line 52
Warning: imagecopy(): supplied argument is not a valid Image resource in root\ons.php on line 63
Warning: imagejpeg(): supplied argument is not a valid Image resource in root\ons.php on line 67
Warning: imagecopy(): supplied argument is not a valid Image resource in root\ons.php on line 63
I thought that these functions might want a path to the image so I have also tried to make the image that was resized and the ones that were cut to save in this map .\image\ons\Ons-foto\ but that didn't work either. it didn't save the images nor did it load them back in to display them on the screen.
What it also could be is that imagecreatefromjpeg() doesn't output what I think it outputs and saves in $img but fopen() didn't work either and gave the same error so I cant figure it out
Could someone take a look at this and tell me why it doesn't work?
to those who do, thank you
You need to create $newimg and $tempimg before you can copy into them. All the other errors are cascading from this problem.
I have following code
// load image and get image size
$img = imagecreatefrompng( "{$pathToImages}{$fname}" );
$width = imagesx( $img );
$height = imagesy( $img );
// calculate thumbnail size
$new_width = $imageWidth;
$new_height = 500;
// create a new temporary image
$tmp_img = imagecreatetruecolor( $new_width, $new_height );
// copy and resize old image into new image
imagecopyresized( $tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
It works fine with some images..but with certain images it shows an error like
Warning: imagecreatefromjpeg() [function.imagecreatefromjpeg]: gd-jpeg: JPEG library reports unrecoverable error:
Warning: imagesx() expects parameter 1 to be resource, boolean given
Warning: imagesy() expects parameter 1 to be resource, boolean given
I have also enabled
gd.jpeg_ignore_warning = 1
in php.ini
Any help appreciated.
According to a blog post from (Feb 2010) its a bug in the implementation of imagecreatefromjpeg which should return false but throws an error instead.
The solution is to check for the filetype of your image (I removed the duplicate call to imagecreatefromjpeg because its totally superfluous; we already check for right file type before and if an error occurs due to some other reason, imagecreatefromjpeg will return false correctly):
function imagecreatefromjpeg_if_correct($file_tempname) {
$file_dimensions = getimagesize($file_tempname);
$file_type = strtolower($file_dimensions['mime']);
if ($file_type == 'image/jpeg' || $file_type == 'image/pjpeg'){
$im = imagecreatefromjpeg($file_tempname);
return $im;
}
return false;
}
Then you can write your code like this:
$img = imagecreatefrompng_if_correct("{$pathToImages}{$fname}");
if ($img == false) {
// report some error
} else {
// enter all your other functions here, because everything is ok
}
Of course you can do the same for png, if you want to open a png file (like your code suggests). Actually, usually you will check which filetype your file really has and then call the correct function between the three (jpeg, png, gif).
Please see PHP Bug #39918 imagecreatefromjpeg doesn't work. The suggestion is to change the GD setting for jpeg image loading:
ini_set("gd.jpeg_ignore_warning", 1);
You then additionally need to check the return value from the imagecreatefromjpegDocs call:
$img = imagecreatefromjpeg($file);
if (!$img) {
printf("Failed to load jpeg image \"%s\".\n", $file);
die();
}
Also please see the potentially duplicate question:
the dreaded “Warning: imagecreatefromjpeg() : '/tmp/filename' is not a valid JPEG file in /phpfile.php on line xxx”
It has nearly the same error description like yours.
My solution for this issue: detect if imagecreatefromjpeg returns 'false' and in that case use imagecreatefromstring on file_get_contents instead.
Worked for me.
See code sample below:
$ind=0;
do{
if($mime == 'image/jpeg'){
$img = imagecreatefromjpeg($image_url_to_upload);
}elseif ($mime == 'image/png') {
$img = imagecreatefrompng($image_url_to_upload);
}
if ($img===false){
echo "imagecreatefromjpeg error!\n";
}
if ($img===false){
$img = imagecreatefromstring(file_get_contents($image_url_to_upload));
}
if ($img===false){
echo "imagecreatefromstring error!\n";
}
$ind++;
}while($img===false&&$ind<5);
Could you give any example of files that do / don't work?
According to http://www.php.net/manual/en/function.imagecreatefromjpeg.php#100338 blanks in remote filenamnes might cause issues.
In case you're using an URL as the source of the image, you will need to make sure the php setting allow_url_fopen is enabled.
I have a script to resize an uploaded image, but when I use it, it just returns a black square. All error messages are pointing at this function:
function resizeImage($image,$width,$height,$scale) {
$newImageWidth = ceil($width * $scale);
$newImageHeight = ceil($height * $scale);
$newImage = imagecreatetruecolor($newImageWidth,$newImageHeight);
$source = imagecreatefromjpeg($image);
imagecopyresampled($newImage,$source,0,0,0,0,$newImageWidth,$newImageHeight,$width,$height);
imagejpeg($newImage,$image,90);
chmod($image, 0777);
return $image;
}
My error logs:
PHP Warning: imagecreatefromjpeg() [<a href='function.imagecreatefromjpeg'>function.imagecreatefromjpeg</a>]: gd-jpeg: JPEG library reports unrecoverable error
PHP Warning: imagecreatefromjpeg() [<a href='function.imagecreatefromjpeg'>function.imagecreatefromjpeg</a>]: 'img/[hidden].jpg' is not a valid JPEG file
PHP Warning: imagecopyresampled(): supplied argument is not a valid Image resource
According to Marc B's answer you could probably make a check if the file is a JPG file. (JPEG, JPG, jpg, jpeg extensions).
it could be something like:
$file = explode(".", $_POST['file']);
$file_ext = $file[count($file)]; // Get the last thing in the array - in this way the filename can containg dots (.)
$allowed_ext = array('jpg', 'JPG', 'jpeg', 'jpg');
if( in_array($file_ext, $allowed_ext )
{
// The code for creating the image here.
}
Check if the imagecreatetruecolor succeeded. If the new image is "large" it could exceed the PHP memory_limit. This function returns FALSE if it failed for any reason.
Ditto with imagecreatefromjpeg(). The two individual images may fit within the memory limit but together could be too large. The source image may also not exist. This function returns FALSE if it failed for any reason
Check if the imagecopyresampled() failed - it also returns FALSE on failure.
Check if imagejpeg() failed - maybe you don't have write permissions on whatever file you're specifying in $image. And again, this function returns FALSE on failure.