When I first set out to redesign my blog back in 2006, I was faced with the daunting prospect of going through and resizing all the images from my previous posts, fitting them into whatever new design I came up with. Thankfully, the images used in my previous design were small enough to fit inside the new column widths without issue. But what if someone with hundreds of posts suddenly decided to change their design, and all their old images would no longer fit the layout? I wasn’t prepared to face that in the future, so after a bit of hunting I found a future-proofing solution using PHP image-resizing and a little mod_rewrite goodness.
First, let’s take a look at a working example so you can see how this whole thing pans out. I’ve taken an existing image, in this case at the location “/projects/img-resizing/lightboxes.jpg” (see the original image). Using this single image, and linking to it using slightly different URL’s, I can output the following versions:
Notice a pattern there? Yep, according to the first section of the URL I can output one of three different sized versions of the one image (you can add as many as you want, but I’ve only chosen to define three)
The solution comes in two parts; the first is a PHP script that handles the resizing and caching of JPG images, and the second is a set of Apache mod_rewrite rules that load the script when a certain URL is used. For example, consider the following image link:
<img src="/img-large/myimages/my-image.jpg" alt=" " />
The “/img-large” part at the start of the src parameter is noticed by a mod_rewrite rule, which then passes the remaining part of the parameter, “/myimages/my-image.jpg”, to the PHP script along with a width value (pre-specified as a parameter on the mod_rewrite rule). The image at this location then gets resized on the fly, and the result is sent back to the browser.
The script originally came from Timothy Crowe’s post on veryraw.com about the same issue (which also included some mods made by Trent Davies). I took the script and added a few extras like antialiasing, sharpening, and the ability to reference images from any location in your site directory.
Use of the script carries a few pre-requisites. You’ll need to have mod_rewrite enabled on your server, be running PHP, and have access to edit your .htaccess file. Here we go!
In the root folder of your website, create a new folder called “cache”. This will be used to store cached versions of the images so they don’t need to get processed every time a call is made (Note: the image will get re-processed if it is newer than the cached version). You will need to set permissions on this folder to ‘777′ so that the script can write the cached copy.
Download a copy of the script file “images.php”, and place it in the root folder of your website. Download the script »
In the root folder of your website you should have a file called “.htaccess”, and this is where your mod_rewrite rules will go. It is a hidden file, so if you are using an FTP client to connect to your server, you may need to enable an option to ‘view hidden files’. Open this file in a text editor, and add the following code:
# BEGIN ImageResizing
<ifmodule mod_rewrite.c>
RewriteEngine on
RewriteBase /
# scaling small, medium, large
RewriteRule ^img-small/([A-Za-z0-9/_-]+).(jpg|gif|png)$ images.php?max_width=100&imgfile=$1.$2
RewriteRule ^img-medium/([A-Za-z0-9/_-]+).(jpg|gif|png)$ images.php?max_width=230&imgfile=$1.$2
RewriteRule ^img-large/([A-Za-z0-9/_-]+).(jpg|gif|png)$ images.php?max_width=470&imgfile=$1.$2
</ifmodule>
# END ImageResizing
In this example there are three rewrite rules specified, one for each image size demonstrated above. There are two important things to note here; Near the start of each rule is where the URL prefix is speciied (here I’ve used ‘img-small/’, ‘img-medium/’ and ‘img-large/’, but you can modify these to suit). This is the URL prefix you will add for any image links that you want dynamically resized. The second part to note is the “max_width” parameter near the end of each rule. This sets the maximum width for images that are resized using each URL. This is where you define how wide you want your images to end up after the resizing.
// Ratio cropping
$offsetX = 0;
$offsetY = 0;
if (isset($_GET['cropratio']))
{
$cropRatio = explode(':', (string) $_GET['cropratio']);
if (count($cropRatio) == 2)
{
$ratioComputed = $width / $height;
$cropRatioComputed = (float) $cropRatio[0] / (float) $cropRatio[1];
if ($ratioComputed < $cropRatioComputed)
{ // Image is too tall so we will crop the top and bottom
$origHeight = $height;
$height = $width / $cropRatioComputed;
$offsetY = ($origHeight - $height) / 2;
}
else if ($ratioComputed > $cropRatioComputed)
{ // Image is too wide so we will crop off the left and right sides
$origWidth = $width;
$width = $height * $cropRatioComputed;
$offsetX = ($origWidth - $width) / 2;
}
}
}
Note: You can add as many rules as you like here, to suit your requirements (e.g. you might want to add rules for URL prefixes such as ‘thumbnail/’ or ‘product-image/’)
Throw an image into your site somewhere and try browsing to it, adding one of the URL prefixes you defined in your .htaccess file at the start of the URL (e.g. http://yoursite.com/img-large/myimagepath/myimage.jpg)
You should get a nicely resized image in return. If all is well, you can use these references for either browsing directly to images (as you just tried) or within image tags (as in the examples above).
Now, I learn a lot of my programming through trial and error. The above solution is working very well for me, but I provide it as-is and without warranty. Try it out at your own risk! There are a couple of important notes to mention though:
I hope you find this as useful as I have. It will definitely be a time-saver for redesigns, but also has many other uses :)
Comments are no longer active, but I have left a copy of them here in case they prove useful to you.
Tim Crowe said: (on October 29th 2006, at 5:30 am)
Great additions to the script. I’m loving the access to the script from anywhere in your document structure. I have found when I use it that there are some quality issues. Thanks for the mention and the note about Trent’s awesome addition.
yi3artist said: (on November 26th 2006, at 10:44 pm)
My site has no gallery, nor does it even use that many images, but for a single area I needed images limited to variable dimensions. Having succesfully implemented this script will save a lot of resizing and uploading in the future. Thank you for compiling and explaining all this so beautifully.
BlueNC said: (on March 3rd 2007, at 8:45 pm)
I like the script very much, downloaded V2, and it’s fast. However I found that png images are converted to jpeg images even though the cache indicates img.png. I noticed it, when I tried to ‘resample’ png’s with transparent backgrounds. Is there a fix for it ? How can I fix it ?
Mike said: (on March 3rd 2007, at 9:23 pm)
Hi there BlueNC. As noted in the caveats above, the script is only really intended for use with JPG images (although in fact I’ve found the resizing will work on some others, as you mentioned). I’ve been learning this stuff as I go, and adapting to suit my needs, so unfortunately I don’t know off the top of my head whether there is a quick fix for transparent PNG’s. When I get some time I’ll try and Google it, and if I find anything I’ll post an update. No promises when that might be though sorry - got a lot on my plate at the moment!
BlueNC said: (on March 5th 2007, at 5:59 pm)
Mike,
Thanks for your reply, but I think I have the transparent png figured out, unfortunatly, I had to ‘hack’ your script completely and suppose the other formats are not 100% working. If interessted I can send you my hack, it works fine now. Since transparent png’s are not supported by ie 5 - 6, I am trying to hack it once more to create a canvas with a specified color and copy the transparent png over it (a second images.php) with htaccess setup. (Awesome script and great foundation, thanks)….
Mike said: (on March 5th 2007, at 9:57 pm)
Hi BlueNC. I’m glad you got something working in the end. I’d be keen to see the end result - if you ever want to post it somewhere online, then I’ll also link to it from here so that others can see how you did it :)
Frank said: (on April 7th 2007, at 10:57 am)
Thank you for this wonderful setup. Remarkable easy of use!
One note : I had to adjust the regular expression in the htaccess file because of errors in filenames with multiple ‘dots’ in it (e.g. ‘image10.2.jpg’):
[A-Za-z0-9/_-]
becomes
[A-Za-z0-9./_-]
I’m not really used to this level of programming but the above adjustment got the script working again for these images.
Alexey said: (on December 13th 2007, at 8:54 am)
Hello Mike,
Thank you for this solution.
Could you explain me how to increase qulity of generated images, for eample 85-90%
Mike said: (on December 13th 2007, at 5:54 pm)
@Alexey: I’ve noticed some variation in image quality too. There are a few things you can do: The first is to remove the anti-aliasing and sharpening, so that the image just resized straight. To do this, comment out line 89 and also remove the sharpening function on lines 94-104.
The other thing you can do is play with the numbers for the sharpening function to adjust how crisp the image becomes after antialiasing. You’d have to read up on this though, because even I can’t remember how that part works (it was a long time ago that I last poked around with this script).
Chances are that the first option will do what you want. The antialiasing/sharpening works OK for jpegs, but not so well for gifs with few clean lines and text etc. Also the size of the image seems to make a difference.
Hope that helps :)
Alexey said: (on December 13th 2007, at 6:54 pm)
Hi. I just solved it by adding parameter in createjpeg ()
Tate said: (on April 4th 2008, at 10:41 am)
Dude! This is so slick!
ap said: (on June 3rd 2008, at 3:46 am)
As much as I like it, I kinda miss the cropratio setting from the original script…
ap said: (on July 2nd 2008, at 9:24 am)
Well, got the cropratio thing working. I did it by inserting some code from the original script. For those of you interested, here’s how I did it:
Insert this code at line 37:
Next, modify the code at line 123:
Easy as pie! To Mike (and the original author), thanks for your work!
ap said: (on July 2nd 2008, at 9:29 am)
Whoops, the code got a bit mangled there… tinypaste.com to the rescue.
Insert this code at line 37:
http://tinypaste.com/64d4e
Next, modify the code at line 123:
http://tinypaste.com/6286d
flyboeing said: (on September 9th 2008, at 4:30 am)
I followed all the instructions above, but when i load my image (img-large/images/SP-LDK.jpg), i have got the following error:
Warning: getimagesize(SP-LDK.jpg) [function.getimagesize]: failed to open stream: No such file or directory in
When i place the file in my root, the image will be shown.
Is there a way i can put the image in “img-large/images/”?
flyboeing said: (on September 9th 2008, at 4:38 am)
never mind, it works now.
beatboxradio said: (on March 1st 2009, at 8:30 am)
for thoses who have some space in filename.
put this at line 33 :
great code by the way.