I've got a script which caches images from an external feed and stores them in a directory on my server when the image is viewed on site.
At the moment it is working great - storing the original image on my server and also creating two additional thumbnails, with their widths re-sized at 300px and 150px.
I'd like to change this slightly so that the following occurs:
However, is it possible, so that once the image width/height is resized, the additional canvas width/height is then added to make it completely square? I guess one of the issues here is determining if the image is a 'portrait' or 'landscape' first?
Also, currently I'm getting a black background with transparent PNG images. Is there any way to overcome this and fill the background with white instead?
Thank you very much for any help!! :)
Here is the code which is doing the resizing (imageCache.php):
<?php
function cacheFetch($url,$size,$age)
{
// directory in which to store cached files, must be writable by PHP
$cacheDir = "cache/";
// cache filename constructed from MD5 hash of URL
$filename = $cacheDir.md5($url);
// append size to filename if not 0
if ($size) $filename .= "_".$size;
// default to fetch the file
$fetch = true;
// but if the file exists, don't fetch if it is recent enough
if (file_exists($filename))
{
$fetch = (filemtime($filename) < (time()-$age));
}
// fetch the file if required
if ($fetch)
{
if (substr($url,0,4)=="http")
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
$data = curl_exec($ch);
curl_close($ch);
if (strlen($data))
{
$fp = fopen($filename,"w");
fwrite($fp,$data);
fclose($fp);
$error = false;
}
else
{
$error = true;
}
}
else
{
copy($url,$filename);
$error = false;
}
}
// return the filename only if wget did not fail
if (!$error)
{
if ($size)
{
$src = file_get_contents($filename);
$oldImage = imagecreatefromstring($src);
$oldX = imagesx($oldImage);
$oldY = imagesy($oldImage);
if ($oldX && $oldY)
{
$newX = $size;
$xFactor = ($newX / $oldX);
$newY = intval($oldY * $xFactor);
$newImage = imagecreatetruecolor($newX,$newY);
imagecopyresized($newImage, $oldImage, 0,0,0,0, $newX, $newY, $oldX, $oldY);
imagejpeg($newImage,$filename);
}
}
return $filename;
}
else
{
// as an error occured, delete the empty file so it is retried next time
unlink($filename);
// return false
return false;
}
}
require("includes/common.php");
$id = $_GET["id"];
$size = $_GET["size"];
$sql = "SELECT image_url FROM `".$config_databaseTablePrefix."products` WHERE id='".database_safe($id)."'";
if (database_querySelect($sql,$rows))
{
$src = $rows[0]["image_url"];
$src = cacheFetch($src,$size,604800);
$img = file_get_contents($src);
header("Content-Type: image");
print $img;
}
?>
and here is the .htaccess bit with sizes:
RewriteRule ^fullimage/(.*).jpg$ imageCache.php?id=$1&size=0 [L]
RewriteRule ^smallimage/(.*).jpg$ imageCache.php?id=$1&size=150 [L]
RewriteRule ^mediumimage/(.*).jpg$ imageCache.php?id=$1&size=300 [L]
EDIT: Re-worked code:
if ($size)
{
$src = file_get_contents($filename);
$oldImage = imagecreatefromstring($src);
$oldX = imagesx($oldImage);
$oldY = imagesy($oldImage);
if ($oldX && $oldY)
{
$color = imagecolorallocate($newImage, 255,255,255); //The three parameters are R,G,B
imagefilledrectangle ($newImage, 0, 0, $newX, $newY,$color);
$size = max($newX,$newY);
$newImage = imagecreatetruecolor($newX,$newY);
imagecopyresized($newImage, $oldImage, ($size-$newX)/2,($size-$newY)/2,0,0, $newX, $newY, $oldX, $oldY); //Just the coordinates was changed
imagejpeg($newImage,$filename);
Sorry, I will not add my sugestions to your code, because its is too complicated. SO just the hints.
Obviously, we must create square of size of bigger dimension of original image. Here I assume the image has already been resized.
$resized = /*We hae resized image downloaded from the site [note1]*/;
$size = max(imagesx($resized), imagesy($resized)); //Make the square so the thumbnail fits in it
$thumbNail = imagecreate($size, $size); //Square.
imagecopy($thumbNail,
($size-imagesx($resized))/2, //Put the image in the middle of the square
($size-imagesy($resized))/2,
0,
0,
imagesx($resized),
imagesy($resized)
);
[note1] Alternativelly, you can just compute dimensions to make $size and copyresize image on the square. This will be faster, but is more complicated to make pseudocode for it.
This is no real mystery - you just draw rectangle over whole image:
$color = imagecolorallocate($thumbNail, 255,255,255);
imagefilledrectangle ($thumbNail, 0, 0, imagesx($thumbNail), imagesy($thumbNail),$color);
You can even have a transparent background:
$color = imagecolorallocatealpha($thumbNail, 255,255,255,127);
imagealphablending($thumbNail, false); //[note2]
imagefilledrectangle ($thumbNail, 0, 0, imagesx($thumbNail), imagesy($thumbNail),$color);
imagealphablending($thumbNail, true); //If you use it
[note2] Turn off blending, because transparent
+black
= black
again
First the resizing, copying. In the original code, we have the computed new height and width in $newX
and $newY
. I will use theese as of the new image sizes.
$size = max($newX,$newY);
$newImage = imagecreatetruecolor($size, $size);
imagecopyresized($newImage, $oldImage, ($size-$newX)/2,($size-$newY)/2,0,0, $newX, $newY, $oldX, $oldY); //Just the coordinates was changed
Then he background. Obviously, you should firs set the background, then copy the image. However, I'm separating theese steps so you can see what function does what.
$newImage = imagecreatetruecolor($newX,$newY);
$color = imagecolorallocate($newImage, 255,255,255); //The three parameters are R,G,B
imagefilledrectangle ($newImage, 0, 0, $newX, $newY,$color);