Using ImageMagick with WordPress 2.9.1
Update: I have updated the code below to remove the comment that was shown if the function had been disabled due to an upgrade. It caused a error in WordPress’ RSS feed if left. This hack/mod continues to work in version 2.9.2 of WordPress too.
Ok you might be thinking that I’m obsessed with ImageMagick, and who knows, maybe you’re right. However it, in my opinion, is the best image manipulation package for use on servers. It has a lot of options can composite things I never even considered & most importantly has a excellent memory management system which is great for those on low resource or shared servers.
One thing that bugged me about WordPress is that dispite how complex & how brilliant it is, it still hasn’t included any support what-so-ever for ImageMagick. I mean even phpBB & Gallery2/3 have ImageMagick support and they are open source applications. I can’t really complain though as WordPress is still the best blogging software out there & I couldn’t live without it. 😉
Anyway I have come up with a small fix hack that will make WordPress use ImageMagick. I would only advise doing this if you have a good knowledge of coding, and I will say this only once, back-up your database & your files just in case. Nothing should go wrong, if it does you can always just restore WordPress’ original source files, but have a back-up as it’s better to be safe than sorry.
Since the auto-updater was introduced modifying WP’s core files became dangerous as any changes are overwritten when you update. There are only two ways to get round this, one is not possible in PHP without the help of a PECL package such as ‘runkit’, the other is a little more complicated, but is the best thing available as PECL packages cannot always be installed on shared servers & the like. We are going to provide an alternate function for WordPress to use for resizing images, should the original it uses be missing. The easiest place to put this function, as it won’t be affected by auto updates, is the functions.php file of your theme. The function is this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
// Re-define image_resize() function to use ImageMagick. An evil, but necessary hack. if(!function_exists('image_resize')) { function image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) { $magic = 'path/to/convert'; //place full or symbolized unix file path to ImageMagick here... $size = @getimagesize( $file ); if ( !$size ) return new WP_Error('invalid_image', __('Could not read image size'), $file); list($orig_w, $orig_h, $orig_type) = $size; $dims = image_resize_dimensions($orig_w, $orig_h, $max_w, $max_h, $crop); if ( !$dims ) return $dims; list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims; // $suffix will be appended to the destination filename, just before the extension if ( !$suffix ) $suffix = "{$dst_w}x{$dst_h}"; $info = pathinfo($file); $dir = $info['dirname']; $ext = $info['extension']; $name = basename($file, ".{$ext}"); if ( !is_null($dest_path) and $_dest_path = realpath($dest_path) ) $dir = $_dest_path; $destfilename = "{$dir}/{$name}-{$suffix}.{$ext}"; if ( IMAGETYPE_GIF == $orig_type ) { $crop = ($crop) ? "^ -gravity center -extent {$dst_w}x{$dst_h}" : ""; exec($magic." -limit memory 50mb -limit map 128mb -size {$dst_w}x{$dst_h} '{$file}' -thumbnail {$dst_w}x{$dst_h}{$crop} '{$destfilename}'"); } elseif ( IMAGETYPE_PNG == $orig_type ) { $crop = ($crop) ? "^ -gravity center -extent {$dst_w}x{$dst_h}" : ""; exec($magic." -limit memory 50mb -limit map 128mb -size {$dst_w}x{$dst_h} '{$file}' -thumbnail {$dst_w}x{$dst_h}{$crop} '{$destfilename}'"); } else { // all other formats are converted to jpg $destfilename = "{$dir}/{$name}-{$suffix}.jpg"; $crop = ($crop) ? "^ -gravity center -extent {$dst_w}x{$dst_h}" : ""; exec($magic." -limit memory 50mb -limit map 128mb -size {$dst_w}x{$dst_h} '{$file}' -thumbnail {$dst_w}x{$dst_h}{$crop} '{$destfilename}'"); } // Set correct file permissions $stat = stat( dirname( $destfilename )); $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits @ chmod( $destfilename, $perms ); return $destfilename; } } ?> |
Again this is a dirty hack & I claim no resonsiblity for any problems it causes it is up to you whether or not you use it.
This is basically a copy of WordPress’ image resize function, but with all the GD image creation parts taken out and the final resize & save replaced with an exec with the equivalent ImageMagick code in. You may be wondering why I left the image type if
in. This is because if the image’s do not match the two types shown the destination file name gets changed to convert all others to a jpg. Conversion will be handled by ImageMagick, but the if
is there so that we don’t automatically convert all image types to jpg.
As far as I am aware it doesn’t create any security flaws as all info passed to image_resize()
by WordPress is normally checked by WP first. All you have to do now is comment out the image_resize()
function in the wp-includes/media.php
. The problem of course is that you will have to comment it out again after an upgrade, but at least you don’t have to paste in a function again or even write it again. If there was a filter, or hook to use so you could change the image_resize()
function it would be easier, but I haven’t been able to find one.
I hope that helps someone. Let me know should you find any errors or should anyone find any bug/flaws & I’ll try to fix them. 😉
43 Comments
VoIP
?? ????? ????? ?? ??????? ??????? ???? ???????????????? ???????? ??? ?? ???????????? ????, ??? ? ?? ?????????? ?????? ???????. ?? ????? ????? ????? ???????? ??????? ?? ????????????? ? ????? ???????.
Paul Robinson
Errrm… Okay! I’m not sure what’s going on here, but all I see is ‘?’s…
L.
Hey Paul!
I’ve been trying out your modification tonight, but can’t seem to get it to work properly.
I have added your function to my theme’s functions.php at the very end, and commented out image_resize() in media.php. All checked and double-checked so far.
However, when I now upload an image in WordPress, I get this error message after the crunching bit is done:
“Warning: Cannot modify header information – headers already sent by (output started at /home/xxx/xxx/wp-content/themes/dailynotes/functions.php:182) in /home/xxx/xxx/wp-admin/async-upload.php on line 26
Are you sure you want to do this?”
The full size image gets uploaded alright, but no resize versions are made.
Any ideas? I’d be happy to provide any other information.
I’m running WordPress 2.9.1 and haven’t tinkered with any files besides these two.
Thanks a lot man, I appreciate your work!
L.
L.
I’ll reply to myself here. I tried to simply comment out the image_resize function in media.php and insert your version below. This gives me another, and even more strange error message:
“Warning: getimagesize(/home/xxx/xxx/wp-content/uploads/2010/02/vfv-100×150.jpg) [function.getimagesize]: failed to open stream: No such file or directory in /home/xxx/xxx/wp-includes/media.php on line 484”
100×150? Where do it get those dimensions from? My thumbnail sizes are set at 150×150. Hmm, hmm.
I’ve got convert installed att /usr/local/bin/convert and it looks to be functioning on its own.
Strange, this.
Paul Robinson
Well I’ll assume you changed it but make sure you did change the
$magic
variable to the correct path for your ImageMagick install. Your error has nothing to do with that but thought I’d check anyway. 😆I’m not sure what is going on with the second error, but the first one is a little strange. Can you tell me what code is on line 182 of your functions file. It appears to be trying to change the pages file header after it has loaded, which you cannot do. I’m not sure if that is stopping thumbnail generation, but it could be by causing PHP to stop.
L.
Hi Paul, thanks for your reply. I figured out what was causing all my troubles. In the end it was my version of convert that didn’t like the “mb” after the specified memory amounts.
Changing “-limit memory 50mb -limit map 128mb” to “-limit memory 50 -limit map 128” worked magic!
Thanks so much for sharing this piece of code!
L.
Paul Robinson
Ahh. Yeah some versions don’t like that, please make sure to check that your convert is actually reading those as Megabytes though now that you have removed the mb.
On recent installs of ImageMagick if you leave that off I believe the value is in bytes, so you may have just said
-limit memory 50bytes - limit map 128bytes
which would be bad. 😮I can’t be certain though. If it starts to take an extrodinary amount of time to create thumbnails from larger images then it is probably in bytes. You could always take out the limit if you don’t need to worry about memory use. I’m on a shared server & so need to keep my memory usage in check. 😉
Paul Robinson
Oh an forgot to say, no problems. I just have this ‘thing’ about not liking GD. 😆
L.
Ah, thanks for the heads-up, I’ll look into it.
When it comes to GD – I hear ya man. It totally screws up the color (profiles) on processed images. That’s why I wanted ImageMagick so I could get some more control. Haven’t figured out the profiles yet, but at least I managed to crank up the saturation by 20% on resized images, which means they look at least somewhat like their original sized counterparts.
Good stuff man, good stuff. Thanks again!
L.
Paul Robinson
No problem & nice idea. Never really thought about using Imagemagick like that. 🙂
steve
Check this out:
http://www.catswhocode.com/blog/how-to-overwrite-wordpress-core-functions
No dirty hacks anymore 😉
Paul Robinson
Yes, I already know about
add_filter()
&add_action()
as I use them in both my plugins.Unfortunately though there needs to be a filter or action hook defined by WP in the function you want to override. If there isn’t one (which there isn’t for
image_resize()
) then using the filter or actions will do absolutely nothing.To show you what I mean here is the part in the core that allows you to override
bloginfo()
:That allows you to override the function. I hope that explains why, untill they add it to the core, we will have to keep editing the core file.
The good news is that someone (I believe) has taken up adding IM to the core as part of the Google Summer of Code that WP are taking part in.
Plautsplupler
excellent focus , search this from blogsearch plus good luck for you.just tally up the rss feed to my reader,keep update!
Jeff Ballweg
Thanks for the post, I’m working on a plugin for a client that needs to use ImageMagick… any thoughts/speculation on how this might change for WordPress 3.0? Have you found any new hooks in the betas?
Paul Robinson
I haven’t had a lot of time to check out any code changes to WP 3, but from what I’ve followed on the mailing lists, and from a quick scan of the media file, I don’t think so.
I believe someone is working on an ImageMagick patch for the WP GoogleCode projects (or at least it was purposed as a project).
I know focus on media has been shifted back to version 3.1 so we might see ImageMagick make an appearence then. We can hope. 🙂
Sebastian Castilho
Hi, thanks for this hack. I’ve tried using it. As I understand it, all I have to do is change the path to imagemagik in that code?
I am trying to use this in WordPress 3. No errors have occured but I’m not sure if it’s working. The outputted images are the same size and quality as if they were done with default WP resizer.
Paul Robinson
Yes you just need to change the Imagemagick path. If you are still seeing images being output then it’s probably working as it would error if it wasn’t.
If you really want to make sure it’s working though & you have SSH (shell) access to your server you can always run
top -c
and see if any convert processes appear when you are uploading some files.Seb
Hi, I tried changing the compression value from 90 to 20 and the outputted files still look the same and have the same file sizes. The path I’m using is definitely right as I’ve confirmed with my server admin.
Just to check, before this bulk of code, there should be only a < ?php (without spaces) right?
Paul Robinson
Yes, it should be in the functions file of your theme with an opening php tag at the start.
Without being able to check via SSH it’s difficult to know, but yes changing the compression should have changed the size. Are you sure you’ve commented out the normal resize function if the WordPress
media.php
file. If you don’t do that it won’t work & without that function WP should crash when uploading if Imagemagick isn’t working as it won’t be able to resize images.Seb
Hi, thanks for your help so far. The media file has quite a few lines relating to image resize functions, could you be a little more specific about which lines to comment out? Maybe tell me from which line to which line needs to be commented out? For reference, my current media file is the default WordPress 3.0 one and has 1399 lines.
Paul Robinson
It’s in the penultimate paragraph of the article:
I can’t remember what line it’s on, but just search for
image_resize
then comment it out using /* at the start and */ at the end. Be careful not to comment out the wrong function though it must just beimage_resize
and nothing else as there is a function named something very similar.Hopefully we’ll not have to do hacks like this soon as I believe Imagemagick support is planned for a future version of WP.
Seb
So this is the code that I should be looking at right?
function image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) {
I’ve tried commenting “image_resize”, tried commenting the whole line, tried commenting “function image_resize”, tried “image_resize
( …. )” and tried commenting “function” up to the end of the whole function.
All with varying results (either upload doesn’t go through successfully or whole site PHP errors).
Paul Robinson
You have to comment out the entire function that starts at
function image_resize
etc & ends with a curly brace ‘}’.Seb
Yep that is one of the things I tried. This appears in the upload results box:
Seb
The addition to the function file, setting the imagemagick path and the commenting in the media file are definitely the only things I need to do right?
Paul Robinson
I’m not sure what’s causing that as my media.php file (WP3) has a comment on the line the error is on?
Yes, those are the only things I have done to my install & it is working fine.
Seb
In my media file, line 485 is:
if ( !is_wp_error($resized_file) && $resized_file && $info = getimagesize($resized_file) ) {
Any suggestions?
Paul Robinson
What function is that line in?
Seb
function image_make_intermediate_size($file, $width, $height, $crop=false) {
if ( $width || $height ) {
$resized_file = image_resize($file, $width, $height, $crop);
if ( !is_wp_error($resized_file) && $resized_file && $info = getimagesize($resized_file) ) {
$resized_file = apply_filters('image_make_intermediate_size', $resized_file);
return array(
'file' => basename( $resized_file ),
'width' => $info[0],
'height' => $info[1],
);
}
}
return false;
}
My ISP support has also suggested the following:
“While yes, this is beyond our scope of support, I would suggest updating the part of the script that generates the file name for that function. You may want to replace that with this PHP variable (depending on how it works):
$_SERVER[“DOCUMENT_ROOT”]
The value of that is simply /xxxx/xxxxx/xxxxxx/sebcastilho.com/html to which you can append wp-content and etc. Beyond that, I’m not sure, but you may want to toy with that function to see if you can get it to work at all on the (gs) Grid-Service.”
Could you just clarify which part he means the replace?
Paul Robinson
I’m not sure what he means as the same functions used to create the thumbnails before you switched to imagemagick are being used.
It looks as if it’s trying to find the resized images & can’t which would mean (to me at least) that Imagemagick isn’t creating thumbnails. Check to see if the image files that the previous errors gave you exist as Imagemagick doesn’t return errors if it can’t resize images, it just continues on with the script.
Seb
Nope the thumbnails indeed do not exist; i.e. the uploaded image isn’t being resized.
Does this mean that the scripting IS able to reach imagemagick, but for some reason the resizing isn’t working?
Paul Robinson
Well not always. The first thing to do would be to make sure that the path to imagemagick is correct by using shell access to try and run convert yourself. It’s the only (quick & easy) way to positively identify if the path is okay.
If it is correct then yes for some reason the resizing isn’t working. If your servers imagemagick is below version 6 the carrot (^) flag for square cropping thumbnails will not work, but that shouldn’t stop it from at least creating non square cropped thumbnails.
Bryan
Does this work with WordPress 3.0.1 ? I put the code in my theme’s functions.php but I’m still getting memory errors. I’ll do some troubleshooting tomorrow.
Paul Robinson
Hey Bryan,
As far as I know, yes it still works. It is possible to still get memory errors while using ImageMagick depending on your host, although less likely than with GD.
The tricky part is finding out if IM is generating the thumbnails, as if all works well you shouldn’t really be able to tell the difference (other than larger files shouldn’t cause memory errors).
One way you could test if it is reading the function in your theme file is to comment out the line that runs the IM command & see if you get an error from WordPress when uploading an image. If you do, it’s working. If not, somehow it’s still reading the original image resizing function.
Jamesalexx
What about the tags?
I mean how i use the tags to generate a custom image? by weight and heigh?
thanks
jamesalexx
i mean width lol
Paul Robinson
Hi Jamesalexx,
I’m not sure what you mean by that. Can you explain a little bit more about what you are trying to do?
tobiasmay
hey paul,
found your article on my research for replacing the whole gd_lib with imagick on wp3.0.1 – cause my server guys won’t run the bundled gd version which i need for cropping.
tried it xour way but i get an upload error saying that it couldn’t move the file in the uploads folder. any idea on this one?
and you might have a look at this wp-plugin: http://wordpress.org/extend/plugins/imagemagick-engine/
gretings,
tobi.
tobiasmay
Replying to myself and correcting.. the upload error i mentioned was because my chmod on the monthly upload folder changed somehow. but now i get the same error as Seb on wp 3.0.1 but i have a slight guess:
a) the path to imagick is wrong:
i located mine with system(“whereis convert”); and verifyed with my server admin. but when inserting this path ex. in the ImageMagick Engine Plugin mentioned above it won’t find it there.
b) since your hack is not completly replacing all gd functions from the core, Seb (aswell as i) is still depending on the gd_lib. i figured out that Debian Servers only include gd_lib >2.0 in the non bundled version. there are just some components missing, ex. the crop to thumbnail function.
to solve that problem we would need to change the whole gd lib from the core..
at least that’s my guess
Paul Robinson
I thought maybe the resize function had changed but I’ve just taken a scan of the file & it doesn’t seem like it.
I would say it sounds like a permissions problem, but I’ve never come across it before. 🙁
If it works I would say try the plugin, from a quick scan of it looks as if it’s a comprehensive and very well written plugin.
tobiasmay
damn you’re fast 🙂
the plugin is neither working for me since it doesn’t replace all gd functions. i have to change my provider for this project – or rewrite the media.php 🙂
Paul Robinson
Although it doesn’t replace the GD functions in the image resize function, it renders them inert as you are overriding them. So not having the bundle version of GD shouldn’t matter I don’t think.
I would check that ImageMagick is in the location shown by ‘whereis’ by trying to resize and image manually using Shell access. If it works I’m not entirely sure what is going on… 🙁