Use PHP to convert PNG to JPG with compression? - php

I have a bunch of high quality PNG files. I want to use PHP to convert them to JPG because of it's smaller file sizes while maintaining quality. I want to display the JPG files on the web.
Does PHP have functions/libraries to do this? Is the quality/compression any good?

Do this to convert safely a PNG to JPG with the transparency in white.
$image = imagecreatefrompng($filePath);
$bg = imagecreatetruecolor(imagesx($image), imagesy($image));
imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
imagealphablending($bg, TRUE);
imagecopy($bg, $image, 0, 0, 0, 0, imagesx($image), imagesy($image));
imagedestroy($image);
$quality = 50; // 0 = worst / smaller file, 100 = better / bigger file
imagejpeg($bg, $filePath . ".jpg", $quality);
imagedestroy($bg);

Be careful of what you want to convert. JPG doesn't support alpha-transparency while PNG does. You will lose that information.
To convert, you may use the following function:
// Quality is a number between 0 (best compression) and 100 (best quality)
function png2jpg($originalFile, $outputFile, $quality) {
$image = imagecreatefrompng($originalFile);
imagejpeg($image, $outputFile, $quality);
imagedestroy($image);
}
This function uses the imagecreatefrompng() and the imagejpeg() functions from the GD library.

This is a small example that will convert 'image.png' to 'image.jpg' at 70% image quality:
<?php
$image = imagecreatefrompng('image.png');
imagejpeg($image, 'image.jpg', 70);
imagedestroy($image);
?>
Hope that helps

<?php
function createThumbnail($imageDirectory, $imageName, $thumbDirectory, $thumbWidth) {
$explode = explode(".", $imageName);
$filetype = $explode[1];
if ($filetype == 'jpg') {
$srcImg = imagecreatefromjpeg("$imageDirectory/$imageName");
} else
if ($filetype == 'jpeg') {
$srcImg = imagecreatefromjpeg("$imageDirectory/$imageName");
} else
if ($filetype == 'png') {
$srcImg = imagecreatefrompng("$imageDirectory/$imageName");
} else
if ($filetype == 'gif') {
$srcImg = imagecreatefromgif("$imageDirectory/$imageName");
}
$origWidth = imagesx($srcImg);
$origHeight = imagesy($srcImg);
$ratio = $origWidth / $thumbWidth;
$thumbHeight = $origHeight / $ratio;
$thumbImg = imagecreatetruecolor($thumbWidth, $thumbHeight);
imagecopyresized($thumbImg, $srcImg, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $origWidth, $origHeight);
if ($filetype == 'jpg') {
imagejpeg($thumbImg, "$thumbDirectory/$imageName");
} else
if ($filetype == 'jpeg') {
imagejpeg($thumbImg, "$thumbDirectory/$imageName");
} else
if ($filetype == 'png') {
imagepng($thumbImg, "$thumbDirectory/$imageName");
} else
if ($filetype == 'gif') {
imagegif($thumbImg, "$thumbDirectory/$imageName");
}
}
?>
This is a very good thumbnail script =)
Here's an example:
$path = The path to the folder where the original picture is.
$name = The filename of the file you want to make a thumbnail of.
$thumbpath = The path to the directory where you want the thumbnail to be saved into.
$maxwidth = the maximum width of the thumbnail in PX eg. 100 (wich will be 100px).
createThumbnail($path, $name, $thumbpath, $maxwidth);

You might want to look into Image Magick, usually considered the de facto standard library for image processing. Does require an extra php module to be installed though, not sure if any/which are available in a default installation.
HTH.

PHP has some image processing functions along with the imagecreatefrompng and imagejpeg function. The first will create an internal representation of a PNG image file while the second is used to save that representation as JPEG image file.

See this list of php image libraries. Basically it's GD or Imagemagick.

I know it's not an exact answer to the OP, but as answers have already be given...
Do you really need to do this in PHP ?
What I mean is : if you need to convert a lot of images, doing it in PHP might not be the best way : you'll be confronted to memory_limit, max_execution_time, ...
I would also say GD might not get you the best quality/size ratio ; but not sure about that (if you do a comparison between GD and other solutions, I am very interested by the results ;-) )
Another approach, not using PHP, would be to use Image Magick via the command line (and not as a PHP extension like other people suggested)
You'd have to write a shell-script that goes through all .png files, and gives them to either
convert to create a new .jpg file for each .png file
or mogrify to directly work on the original file and override it.
As a sidenote : if you are doing this directly on your production server, you could put some sleep time between bunches of conversions, to let it cool down a bit sometimes ^^
I've use the shell script + convert/mogrify a few times (having them run for something like 10 hours one time), and they do the job really well :-)

Related

PHP: Generating PNG thumbnail images from PNG source crashes function based on PNG size

I've written this small function to generate thumbnail images of a larger jpg/jpeg/png source, and it works perfectly on jpg/jpeg images, but depending on the size of the png image, will crash the function at an indeterminate point. Small 300x200 images work, yet something like 2880x1800 will not.
Here's my (annotated) function:
function make_thumb($filename, $destination, $desired_width) {
$extension = pathinfo($filename, PATHINFO_EXTENSION);
// Read source image
if ($extension == 'jpg' || $extension == 'jpeg') {
$source_image = imagecreatefromjpeg($filename);
} else if ($extension == 'png') {
$source_image = imagecreatefrompng($filename); // I think the crash occurs here.
} else {
return 'error';
}
$width = imagesx($source_image);
$height = imagesy($source_image);
$img_ratio = floor($height / $width);
// Find the "desired height" of this thumbnail, relative to the desired width
$desired_height = floor($height * ($desired_width / $width));
// Create a new "virtual" image
$virtual_image = imagecreatetruecolor($desired_width, $desired_height);
// Copy source image at a resized size
imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
// Create the physical thumbnail image to its destination
if ($extension == 'jpg' || $extension == 'jpeg') {
$source_image = imagejpeg($virtual_image, $destination);
} else if ($extension == 'png') {
$source_image = imagepng($virtual_image, $destination, 1);
} else {
return 'another error';
}
}
The only documentation I found that mentioned similar issues to me was this. Is this my problem? Any solutions? Why does it do this?
You are most probably running out of memory. 2880 x 1800 in true color will need about 20 Megabyte.
Check your php.ini for memory_limit.
I'm an idiot. That or PHP is really bad at handling large PNG images. This comment from the PHP documentation here for imagepng() says:
My script was unable to complete: Fatal error: Allowed memory size of XX bytes exhausted (tried to allocate XX+n bytes).
I found out that PHP handles images in uncompressed format: my input image was 8768x4282#32 bit => ~150 MB per single in-memory copy.
As a solution, you can either check the dimensions and reject anything too big or, as I did, use ini_set('memory_limit','1024M'); on the page start (if your server has enough on board memory).
So, remember to increase your available memory limit using ini_set('memory_limit','1024M');!!!

Image cropping and thumb creation

I need to help a friend to make his own artistic gallery.
I already have all done, but I need a tool/plugin/script to make him independent from me in uploading his own images. My gallery needs two images: a cropped one of a certain proportion (so i need him to crop by himself in an uploading page) and a thumb one (I want this be done automatically).
Do you know an easy way to do this? What would you do?
Thanks.
Personally i use this in all of my projects - http://www.verot.net/php_class_upload.htm
Works perfectly with upload files and with files that's already on the system.
Can do many things convert, resize and work on uploaded images in many ways, apply effects, add labels, watermarks and reflections and other image editing features.
Easy to work with.
If you're not going to be having heavy traffic to start - look at http://phpthumb.sourceforge.net/ which can create your resized images on the fly.
You need only GD library, function imagecopyresampled will suit you. PHP manual has really good example code for thumbnail creation http://php.net/manual/en/function.imagecopyresampled.php
You will need just to create exceptions for different file formats
function create_jpeg_thumbnail($thumbImageName,$imgSrc,$thumbDirectory,$thumbnail_width,$thumbnail_height) { //$imgSrc is a FILE - Returns an image resource.
$thumbDirectory = trim($thumbDirectory);
$imageSourceExploded = explode('/', $imgSrc);
$imageName = $imageSourceExploded[count($imageSourceExploded)-1];
$imageDirectory = str_replace($imageName, '', $imgSrc);
$filetype = explode('.',$imageName);
$filetype = strtolower($filetype[count($filetype)-1]);
//getting the image dimensions
list($width_orig, $height_orig) = getimagesize($imgSrc);
//$myImage = imagecreatefromjpeg($imgSrc);
if ($filetype == 'jpg') {
$myImage = imagecreatefromjpeg("$imageDirectory/$imageName");
} else
if ($filetype == 'jpeg') {
$myImage = imagecreatefromjpeg("$imageDirectory/$imageName");
} else
if ($filetype == 'png') {
$myImage = imagecreatefrompng("$imageDirectory/$imageName");
} else
if ($filetype == 'gif') {
$myImage = imagecreatefromgif("$imageDirectory/$imageName");
}
$ratio_orig = $width_orig/$height_orig;
if ($thumbnail_width/$thumbnail_height > $ratio_orig) {
$new_height = $thumbnail_width/$ratio_orig;
$new_width = $thumbnail_width;
} else {
$new_width = $thumbnail_height*$ratio_orig;
$new_height = $thumbnail_height;
}
$x_mid = $new_width/2; //horizontal middle
$y_mid = $new_height/2; //vertical middle
$process = imagecreatetruecolor(round($new_width), round($new_height));
imagecopyresampled($process, $myImage, 0, 0, 0, 0, $new_width, $new_height, $width_orig, $height_orig);
$thumb = imagecreatetruecolor($thumbnail_width, $thumbnail_height);
imagecopyresampled($thumb, $process, 0, 0, 0, 0, $thumbnail_width, $thumbnail_height, $thumbnail_width, $thumbnail_height);
//$thumbImageName = 'thumb_'.get_random_no().'.jpeg';
$destination = $thumbDirectory=='' ? $thumbImageName : $thumbDirectory."/".$thumbImageName;
imagejpeg($thumb, $destination, 100);
return $thumbImageName;
}

Black result image problem on BMP image resize using PHP

I have a PHP script to re size image file as below;
$file = "test.bmp";
$ext = pathinfo($file, PATHINFO_EXTENSION);
$info = pathinfo($file);
$file_name = basename($file,'.'.$info['extension']);
$thumbname = "thumb/".$file_name.".".$ext;
$maxh = 200;
$maxw = 200;
$quality = 100;
list($width,$height)=getimagesize($file);
$src = imagecreatefromwbmp($file);
$tmp = imagecreatetruecolor($maxw,$maxh);
imagecopyresampled($tmp,$src,0,0,0,0,200,200,$width,$height);
imagejpeg($tmp,$thumbname,$quality);
imagedestroy($tmp);
The script is suppose to resize a Windows bitmap image to 200x200 thumbnail. But instead, I am getting a black 200x200 image. I am using PHP with Apache in Windows PC. How can I fix this?
.bmp and wbmp are VERY, VERY different file types.
Note the content-type headers:
Content-Type: image/x-xbitmap
Content-Type: image/vnd.wap.wbmp
Calling imagecreatefromwbmp($file) where $file is a .bmp will fail every time.
See this thread for info on how to load a .bmp file. It's not pretty.
As pointed out in PHP imagecopyresampled() docs:
Note:
There is a problem due to palette image limitations (255+1 colors). Resampling or filtering an image commonly needs more colors than 255, a kind of approximation is used to calculate the new resampled pixel and its color. With a palette image we try to allocate a new color, if that failed, we choose the closest (in theory) computed color. This is not always the closest visual color. That may produce a weird result, like blank (or visually blank) images. To skip this problem, please use a truecolor image as a destination image, such as one created by imagecreatetruecolor().
To see if it's the case you can use imageistruecolor() and copy the contents to a new truecolor image before "copyresampling" it:
if( !imageistruecolor($src) ){
$newim = imagecreatetruecolor( $width, $height );
imagecopy( $newim, $src, 0, 0, 0, 0, $width, $height );
imagedestroy($src);
$src = $newim;
}
There is a new opensource project on Github that allows reading and saving of BMP files (and other file formats) in PHP.
The project is called PHP Image Magician.
<?php
//Create New 'Thumbnail' Image
$newImageWidth = 200;
$newImageHeight = 200;
$newImage = imagecreatetruecolor($newImageWidth, $newImageHeight);
$newImageFile = 'output.jpg';
$newImageQuality = 100;
//Load old Image(bmp, jpg, gif, png, etc)
$oldImageFile = "test.jpg";
//Specific function
$oldImage = imagecreatefromjpeg($oldImageFile);
//Non-Specific function
//$oldImageContent = file_get_contents($oldImageFile);
//$oldImage = imagecreatefromstring($oldImageContent);
//Get old Image's details
$oldImageWidth = imagesx($oldImage);
$oldImageHeight = imagesy($oldImage);
//Copy to new Image
imagecopyresampled($newImage, $oldImage, 0, 0, 0, 0, $newImageWidth, $newImageHeight, $oldImageWidth, $oldImageHeight);
//Output to file
imagejpeg($newImage, $newImageFile, $newImageQuality);

php says php made png is invalid

So I have a function that turns a jpeg into a png image resizes it then saves it. Then a bit later i come back to it and use the image in a rotate function. I keep getting errors though. It says uploads/image.png isnt a valid PNG file. The weird thing is that it only does then on php edited png files. If i delete image.png and download a png from the internet name is image.png is works fine as long as i dont run it through the first resize script.
function load($filename) {
$image_info = getimagesize($filename);
$this->image_type = $image_info[2];
if( $this->image_type == IMAGETYPE_JPEG ) {
$imagecreated = imagecreatefromjpeg($filename);
$this->image = $imagecreated;
$extention = pathinfo($filename, PATHINFO_EXTENSION);
$basename = basename($filename, ".".$extention);
$newname = "uploads/".$basename;
imagepng($imagecreated, $newname.".png", 0);
// ....???
function resize($width,$height) {
$new_image = imagecreatetruecolor($width, $height);
imagecopyresampled($new_image, $this->image, 0, 0, 0, 0, $width, $height,
$this->getWidth(), $this->getHeight());
$this->image = $new_image;
}
Then i save the file with just a simple
imagepng(etc etc);
I go to the uploads folder and it looks fine. its resized and everything. I also noticed photoshop wont open the edited png either.
Also the line of code that produces the error is here..
$image = imagecreatefrompng('uploads/image.png');
Possible fix is to add a NULL for your filters parameter (the last parameter in imagepng)
ie.
imagepng($image,$file_location,0,NULL);
I can't say this should be needed, but I read a similar case where someone noted they had to do this, may be dependant on the version of libpng or gd lib.

How do I resize and convert an uploaded image to a PNG using GD?

I want to allow users to upload avatar-type images in a variety of formats (GIF, JPEG, and PNG at least), but to save them all as PNG database BLOBs. If the images are oversized, pixelwise, I want to resize them before DB-insertion.
What is the best way to use GD to do the resizing and PNG conversion?
Edit: Sadly, only GD is available on the server I need to use, no ImageMagick.
<?php
/*
Resizes an image and converts it to PNG returning the PNG data as a string
*/
function imageToPng($srcFile, $maxSize = 100) {
list($width_orig, $height_orig, $type) = getimagesize($srcFile);
// Get the aspect ratio
$ratio_orig = $width_orig / $height_orig;
$width = $maxSize;
$height = $maxSize;
// resize to height (orig is portrait)
if ($ratio_orig < 1) {
$width = $height * $ratio_orig;
}
// resize to width (orig is landscape)
else {
$height = $width / $ratio_orig;
}
// Temporarily increase the memory limit to allow for larger images
ini_set('memory_limit', '32M');
switch ($type)
{
case IMAGETYPE_GIF:
$image = imagecreatefromgif($srcFile);
break;
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($srcFile);
break;
case IMAGETYPE_PNG:
$image = imagecreatefrompng($srcFile);
break;
default:
throw new Exception('Unrecognized image type ' . $type);
}
// create a new blank image
$newImage = imagecreatetruecolor($width, $height);
// Copy the old image to the new image
imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
// Output to a temp file
$destFile = tempnam();
imagepng($newImage, $destFile);
// Free memory
imagedestroy($newImage);
if ( is_file($destFile) ) {
$f = fopen($destFile, 'rb');
$data = fread($f);
fclose($f);
// Remove the tempfile
unlink($destFile);
return $data;
}
throw new Exception('Image conversion failed.');
}
Your process steps should look like this:
Verify the filetype
Load the image if it is a supported filetype into GD using imagecreatefrom*
Resizing using imagecopyresize or imagecopyresampled
Save the image using imagepng($handle, 'filename.png', $quality, $filters)
ImageMagick is faster, generates better images, is more configurable, and finally is (IMO) much easier to code for.
#ceejayoz Just wait for the new GD - it's OOP like MySQLi and it's actually not bad :)
If you want to use gdlib, use gdlib 2 or higher. It has a function called imagecopyresampled(), which will interpolate pixels while resizing and look much better.
Also, I've always heard noted around the net that storing images in the database is bad form:
It's slower to access than the disk
Your server will need to run a script to get to the image instead
of simply serving a file
Your script now is responsible for a lot of stuff the web server used
to handle:
Setting the proper Content-Type header
Setting the proper caching/timeout/E-tag headers, so clients can properly cache the image. If do not do this properly, the image serving script will be hit on every request, increasing the load on the server even more.
The only advantage I can see is that you don't need to keep your database and image files synchronized. I would still recommend against it though.
Are you sure you have no ImageMagick on server?
I guest you use PHP (question is tagged with PHP). Hosting company which I use has no ImageMagick extension turned on according to phpinfo().
But when I asked them about they said here is the list of ImageMagick programs available from PHP code. So simply -- there are no IM interface in PHP, but I can call IM programs directly from PHP.
I hope you have the same option.
And I strongly agree -- storing images in database is not good idea.
Something like this, perhaps:
<?php
//Input file
$file = "myImage.png";
$img = ImageCreateFromPNG($file);
//Dimensions
$width = imagesx($img);
$height = imagesy($img);
$max_width = 300;
$max_height = 300;
$percentage = 1;
//Image scaling calculations
if ( $width > $max_width ) {
$percentage = ($height / ($width / $max_width)) > $max_height ?
$height / $max_height :
$width / $max_width;
}
elseif ( $height > $max_height) {
$percentage = ($width / ($height / $max_height)) > $max_width ?
$width / $max_width :
$height / $max_height;
}
$new_width = $width / $percentage;
$new_height = $height / $percentage;
//scaled image
$out = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($out, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
//output image
imagepng($out);
?>
I haven't tested the code so there might be some syntax errors, however it should give you a fair presentation on how it could be done. Also, I assumed a PNG file. You might want to have some kind of switch statement to determine the file type.
Is GD absolutely required? ImageMagick is faster, generates better images, is more configurable, and finally is (IMO) much easier to code for.
This article seems like it would fit what you want. You'll need to change the saving imagejpeg() function to imagepng() and have it save the file to a string rather than output it to the page, but other than that it should be easy copy/paste into your existing code.
I think this page is a good starting point. It uses imagecreatefrom(jpeg/gif/png) and resize and converts the image and then outputs to the browser. Instead of outputting the browser you could output to a BLOB in a DB without many minuttes of code-rewrite.
phpThumb is a high-level abstraction that may be worth looking at.

Categories