PIR is no longer under active development. PIR will continue to be available here and I will continue to answer email, but the project as a whole is in purely bugfix mode. I highly recommend using CSS's @font-face{} rule, as it is supported across every browser now, including IE6 and IE7. Also, check out Google's WebFont Directory, a free collection of a bunch of high-quality fonts in various styles. They even provide the CSS for you.

This page has been translated into Spanish language by Maria Ramos from Webhostinghub.com.

PHP Image Replacement

Simple, Tiny, Fast

Latest Update: 9 Apr, 2009

In the past, when one of my designs called for a heading in a fancy font that I couldn't count on people having installed, I had to manually produce an image with the desired text. This was unacceptable, so I borrowed a PHP script from A List Apart and (GREATLY) modified it to better conform to my needs. Well, that solved one issue (manually generating an image with fancy fonts), but I was still left with manually inserting images into my markup, and now they had ugly-as-sin URLs. In addition, if I wanted to make a change to the layout, such as altering the color or the size of the text, I had to go into the image and alter the URL, rather than controlling this properly through CSS.

There had to be a better way, and jQuery brought it to life. I produced this small plugin to allow me to just *write* my pages without worrying about replaced text, and then dynamically replace pieces of it with dynamically generated images. Dynamically.

As far as I can tell, this is by far the simplest iteration of this concept on the web. Many of the others don't rely on jquery, instead (badly) duplicating the selector code. The few that do use jQuery (jitr and jQIR were all I could find) don't seem to be nearly as 'smart' as mine, and are much larger over the wire.

By default it draws all relevant information (size, color, background-color, etc) automatically from the document, based on the CSS applied to the element being targetted. All you need to do is tell it what font to use. All of these options can be manually overridden, of course, if for some reason you decide you need to do so.

(And, of course, throughout all this accessibility is maintained. In the absence of javascript, you have ordinary text, styled to match with your document. In the absence of images, you *also* have ordinary text styled to match with your document, as the replaced text is inserted as the image's @alt text. In the absence of CSS, you still have a fancy-font heading, just in the browser's default size and colors for that element.)

And before you ask, yes, this is chainable. It wouldn't be a very good jQuery plugin if it wasn't.

Download the code.


This page is all the example necessary. The fancy-font headers here were all done with PIR. The code used is:

$(function() {
	$("h1").pir({font: "porytt.ttf", wrap: true});
	$("h2").pir({font: "Forte.ttf"});

No extra additional markup was used on the page - those are plain-jane <h1> and <h2> tags, with their size and color specified in CSS as normal. PIR automatically grabbed all the relevant information for them.


The following options can be supplied to the pir function (or set directly on the $.pir.options object if you want it to apply to *all* invocations of pir() on a page):


Using PIR is simplicity itself. Obviously, jQuery itself is required. As well, your server must have support for PHP and have the GD image creation library installed (Since PHP 4.3 this is true by default.), so that it can run the pir.php script.

You will also need to have a folder for your fonts. These fonts do not need to be specially prepared in any way; you can just grab them from your computer's Fonts folder and throw them on your webserver.

Modify pir.php so that the "$fonts_folder" variable (found on line 19) points to the folder you are storing your fonts, then upload pir.php as well.

Finally, you may wish to modify jquery.pir.js (and jquery.pir.min.js) to point to your pir.php file. By default, it assumes it to sit in the root directory of your website. You can also simply modify this within a page by directly modifying the $.pir.options.php variable before calling the pir() function (which is what I did in the example code), or by passing a "php" option with a url value when calling the pir() function.

Note: Some older versions of the GD Image Creation library do not handle unicode properly, and will render non-ASCII letters as boxes. From discussion with users and my own experience, it appears that 'bundled' versions of the library (check phpinfo() - you'll see a version number something like "bundled (2.0.34 compatible)") are bad, while a version of "2.0 or higher" is good.

Browser Compat

PIR is verified compatible with IE7, IE8, FF3, Opera 9, Chrome, and Safari 3 (Win and Mac). I see no reason why it wouldn't work in FF2.

PIR uses 32-bit PNGs, and thus is not out-of-the-box compatible with IE6. It does, however, degrade gracefully - IE6 users will instead get the alt-text for the images, giving them a presentation identical to if PIR wasn't used at all. If you need IE6 to have identical presentation, there are a number of jQuery plugins that will patch IE6's transparency handling. You may be using one of them already, which is why I didn't include any such functionality in PIR.

Future Expansion

Change Log

19 Feb, 2009
ENHANCEMENT: Added word-wrap functionality.
ENHANCEMENT: Made pir hide the targetted elements immediately, do its work, and then show them again. This somewhat helps prevents the flicker of unstyled content. Users browsing without images are not affected, as they still get the alt text from the images.
ENHANCEMENT: Added 'prettyprint' option for reverting to plain text when printing (as images which are clear on screen often show up blurry in printing).
25 Feb, 2009
BUGFIX: Safari reported transparent colors in an unfamiliar format. Color acceptor now recognizes this.
BUGFIX: Opera reported normal colors in a format that required url escaping. I just url-escape everything now.
BUGFIX: Fencepost error in image width calculation, resulting in rightmost pixel column being shaved off (visible only occasionally). Added 1 to the width calculation.
ENHANCEMENT: Upgraded to true 32-bit PNGs, for full transparency support. Feel free to use PIR headings over complex image backgrounds now. In any browser which supports rgba (Firefox 3, current versions of Safari), feel free to use transparent text colors as well! (Don't forget to specify a non-transparent color before the rgba() declaration, so that browsers which don't understand rgba still get approximately the color you want.)
ENHANCEMENT: Code cleanup/shrinkage. Minimal in such a small plugin, but every byte counts.
28 Feb, 2009
BUGFIX: String with single quotes are now escaped correctly (neither encodeURI nor encodeURIComponent escape single quotes, which somehow causes a problem when jQuery inserts text back into a DOM attribute).
BUGFIX: Runs of multiple contiguous spaces are ignored (previously, they would send an empty string as the 'text' to the server, causing it to report an error)
6 Mar, 2009
BUGFIX: A single dirty, stinking extra comma led me on a three-hour wild-goose chase trying to figure out why it didn't work in IE7, but did work everywhere else. It appears that all the other browsers (IE8 included) silently swallow a comma trailing the last entry in an object literal, but IE7 takes it as an opportunity to die with a cryptic error that doesn't even reference the correct file, let alone line number. Grr.
ENHANCEMENT: PIR now supports the full list of SVG color names, because IE will report those as the value of color if you specify it as such. That is, if you say "color:#00f", it returns a "#00f", but if you say "color:blue", it returns "blue", even though the two colors are equivalent.
23 Mar, 2009
BUGFIX: All generated images now get vertical-align:bottom applied automatically. This should make PIR actually usable on inline text (in small quantities, mind you!).
31 Mar, 2009
BUGFIX: Finally fixed the issues with many symbols staying encoded in the alt text, so text now shows correctly when images are disabled.
BUGFIX: Fixed a lingering issue due to an uninitialized variable that broke PIR if you had strict error reporting turned on in PHP.
BUGFIX: Explicitly removed support for background-color. This was only used previously for edge-blending because I used GIF-style transparency. With true 32-bit tranparent PNGs it did nothing except waste a few cycles in the PHP script and a few bytes in the JS script.
9 Mar, 2009
ENHANCEMENT: Made PIR aware of text-transform property. Hilarious coincidence: this morning I got an email from a user asking for this capability. This afternoon I received an email from an unrelated user saying they'd just *added* this capability to their own copy of PIR, and had attached the patched version for me to merge in! Sensing an opportunity to get acclaim while doing no work, I copied the code over.

Contact Me

My contact email is jackalmage@gmail.com. Please put "[PIR]" in the subject line of the email, or I may ignore it.


Since I live in America, PIR is automatically copyrighted no matter what I do. However, all code for PIR is released under the WTFPL. In other words, go crazy with it. I made it to be used, so use it!