title besides title

 
Showing posts with label PHP - Graphics. Show all posts
Showing posts with label PHP - Graphics. Show all posts

Tuesday, November 27, 2012

PHP : Graphics - [15.1] Introduction

With the assistance of the GD library, you can use PHP to create applications that use dynamic images to display stock quotes, reveal poll results, monitor system performance, and even create games. However it's not like using Photoshop or GIMP; you can't draw a line by moving your mouse. Instead, you need to precisely specify a shape's type, size, and position.
GD has an existing API, and PHP tries to follows its syntax and function-naming conventions. So, if you're familiar with GD from other languages, such as C or Perl, you can easily use GD with PHP. If GD is new to you, it may take a few minutes to figure it out, but soon you'll be drawing like Picasso.
The feature set of GD varies greatly depending on which version GD you're running and which features were enabled during configuration. Versions of GD up to 1.6 supported reading and writing GIFs, but this code was removed due to patent problems. Instead, newer versions of GD support JPEGs, PNGs, and WBMPs. Because PNGs are generally smaller than GIFs, allow you to use many more colors, have built-in gamma correction, and are supported by all major web browsers, the lack of GIF support is classified as a feature, not a bug. For more on PNG, go to http://www.libpng.org/pub/png/ or read Chapter 21, "PNG Format," of Web Design in a Nutshell written by Jennifer Niederst (O'Reilly).
Besides supporting multiple file formats, GD lets you draw pixels, lines, rectangles, polygons, arcs, ellipses, and circles in any color you want. Section 15.2 covers straight shapes, while Section 15.3 covers the curved ones. To fill shapes with a pattern instead of a solid color, see Section 15.4.
You can also draw text using a variety of font types, including built-in, TrueType, and PostScript Type 1 fonts. Section 15.5 shows the ins and outs of the three main text-drawing functions, and Section 15.6 shows how to center text within a canvas. These two recipes form the basis for Section 15.7, which combines an image template with real-time data to create dynamic images. GD also lets you make transparent GIFs and PNGs. Setting a color as transparent and using transparencies in patterns are discussed in Section 15.8.
Section 15.9 moves away from GD and shows how to securely serve images by restricting user access. Last, we provide an example application — taking poll results and producing a dynamic bar graph showing what percentage of users voted for each answer.
All these features work with GD 1.8.4, which is the latest stable version of the library. If you have an earlier version, you should not have a problem. However, if a particular recipe needs a specific version of GD, we note it in the recipe.
PHP also supports GD 2.x, which, as of this writing, is still in beta. Despite its beta status, the new version is relatively stable and has many new features. In particular, Version 2.x allows true-color images, which lets GD read in PNGs and JPEGs with almost no loss in quality. Also, GD 2.x supports PNG alpha channels, which allow you to specify a transparency level for each pixel.
Both versions of GD are available for download from the official GD site at http://www.boutell.com/gd/. The GD section of the online PHP Manual at http://www.php.net/image also lists the location of the additional libraries necessary to provide support for JPEGs and Type 1 fonts.
There are two easy ways to see which version, if any, of GD is installed on your server and how it's configured. One way is to call phpinfo( ) . You should see --with-gd at the top under "Configure Command"; further down the page there is also a section titled "gd" that has more information about which version of GD is installed and what features are enabled. The other option is to check the return value of function_exists('imagecreate'). If it returns true, GD is installed. The imagetypes( ) function returns a bit field indicating which graphics formats are available. See http://www.php.net/imagetypes for more on how to use this function. If you want to use a feature that isn't enabled, you need to rebuild PHP yourself or get your ISP to do so.
The basic image generation process has three steps: creating the image, adding graphics and text to the canvas, and displaying or saving the image. For example:
$image = ImageCreate(200, 50);
$background_color = ImageColorAllocate($image, 255, 255, 255); // white
$gray             = ImageColorAllocate($image, 204, 204, 204); // gray

ImageFilledRectangle($image, 50, 10, 150, 40, $gray);

header('Content-type: image/png');
ImagePNG($image);
The output of this code, which prints a gray rectangle on a white background, is shown in Figure 15-1.
Figure 15-1. A gray rectangle on a white background
To begin, you create an image canvas. The ImageCreate( ) function doesn't return an actual image. Instead, it provides you with a handle to an image; it's not an actual graphic until you specifically tell PHP to write the image out. Using ImageCreate( ), you can juggle multiple images at the same time.
The parameters passed to ImageCreate( ) are the width and height of the graphic in pixels. In this case, it's 200 pixels across and 50 pixels high. Instead of creating a new image, you can also edit existing images. To open a graphic, call ImageCreateFromPNG( ) or a similarly named function to open a different file format. The filename is the only argument, and files can live locally or on remote servers:
// open a PNG from the local machine
$graph = ImageCreateFromPNG('/path/to/graph.png');

// open a JPEG from a remote server
$icon  = ImageCreateFromJPEG('http://www.example.com/images/icon.jpeg');
Once you have an editable canvas, you get access to drawing colors by calling ImageColorAllocate( ) :
$background_color = ImageColorAllocate($image, 255, 255, 255); // white
$gray             = ImageColorAllocate($image, 204, 204, 204); // gray
The ImageColorAllocate( ) function takes an image handle to allocate the color to and three integers. The three integers each range from 0 to 255 and specify the red, green, and blue components of the color. This is the same RGB color combination that is used in HTML to set a font or background color. So, white is 255, 255, 255; black is 0, 0, 0, and everything else is somewhere in between.
The first call to ImageAllocateColor( ) sets the background color. Additional calls allocate colors for drawing lines, shapes, or text. Therefore, set the background color to 255, 255, 255 and then grab a gray pen with ImageAllocateColor($image, 204, 204, 204). It may seem odd that the background color is determined by the order ImageAllocateColor() is called and not by a separate function. But, that's how things work in GD, so PHP respects the convention.
Call ImageFilledRectangle( ) to place a box onto the canvas. ImageFilledRectangle( ) takes many parameters: the image to draw on, the x and y coordinates of the upper left corner of the rectangle, the x and y coordinates of the lower right corner of the rectangle, and finally, the color to use to draw the shape. Tell ImageFilledRectangle( ) to draw a rectangle on $image, starting at (50,10) and going to (150,40), in the color gray:
ImageFilledRectangle($image, 50, 10, 150, 40, $gray);
Unlike a Cartesian graph, (0,0) is not in the lower left corner; instead, it's in the upper left corner. So, the vertical coordinate of the spot 10 pixels from the top of a 50 pixel high canvas is 10 because it's 10 pixels down from the top of the canvas. It's not 40, because you measure from the top down, not the bottom up. And it's not -10, because down is considered the positive direction, not the negative one.
Now that the image is all ready to go, you can serve it up. First, send a Content-type header to let the browser know what type of image you're sending. In this case, we display a PNG. Next, have PHP write the PNG image out using ImagePNG( ) . Once the image is sent, your task is over:
header('Content-Type: image/png');
ImagePNG($image);
To write the image to disk instead of sending it to the browser, provide a second argument to ImagePNG( ) with where to save the file:
ImagePng($image, '/path/to/your/new/image.png');
Since the file isn't going to the browser, there's no need to call header( ). Make sure to specify a path and an image name, and be sure PHP has permission to write to that location.
PHP cleans up the image when the script ends, but, if you wish to manually deallocate the memory used by the image, calling ImageDestroy($image) forces PHP to get rid of the image immediately.

PHP : Graphics - [15.2] Drawing Lines, Rectangles, and Polygons

15.2.1 Problem

You want to draw a line, rectangle, or polygon. You also want to be able to control if the rectangle or polygon is open or filled in. For example, you want to be able to draw bar charts or create graphs of stock quotes.

15.2.2 Solution

To draw a line, use ImageLine( ):
ImageLine($image, $x1, $y1, $x2, $y2, $color);
To draw an open rectangle, use ImageRectangle( ):
ImageRectangle($image, $x1, $y1, $x2, $y2, $color);
To draw a solid rectangle, use ImageFilledRectangle( ) :
ImageFilledRectangle($image, $x1, $y1, $x2, $y2, $color);
To draw an open polygon, use ImagePolygon( ):
$points = array($x1, $y1, $x2, $y2, $x3, $y3);
ImagePolygon($image, $points, count($points)/2, $color);
To draw a filled polygon, use ImageFilledPolygon( ):
$points = array($x1, $y1, $x2, $y2, $x3, $y3);
ImageFilledPolygon($image, $points, count($points)/2, $color);

15.2.3 Discussion

The prototypes for all five functions in the Solution are similar. The first parameter is the canvas to draw on. The next set of parameters are the x and y coordinates to specify where GD should draw the shape. In ImageLine( ), the four coordinates are the end points of the line, and in ImageRectangle( ), they're the opposite corners of the rectangle. For example, ImageLine($image, 0, 0, 100, 100, $color) produces a diagonal line. Passing the same parameters to ImageRectangle( ) produces a rectangle with corners at (0,0), (100,0), (0,100), and (100,100). Both shapes are shown in Figure 15-2.

Figure 15-2. A diagonal line and a square
The ImagePolygon( ) function is slightly different because it can accept a variable number of vertices. Therefore, the second parameter is an array of x and y coordinates. The function starts at the first set of points and draws lines from vertex to vertex before finally completing the figure by connecting back to the original point. You must have a minimum of three vertices in your polygon (for a total of six elements in the array). The third parameter is the number of vertices in the shape; since that's always half of the number of elements in the array of points, a flexible value for this is count($points) / 2 because it allows you to update the array of vertices without breaking the call to ImageLine().
Last, all the functions take a final parameter that specifies the drawing color. This is usually a value returned from ImageColorAllocate( ) but can also be the constants IMG_COLOR_STYLED or IMG_COLOR_STYLEDBRUSHED, if you want to draw nonsolid lines, as discussed in Section 15.4.
These functions all draw open shapes. To get GD to fill the region with the drawing color, use ImageFilledRectangle( ) and ImageFilledPolygon( ) with the identical set of arguments as their unfilled cousins.

PHP : Graphics - [15.3] Drawing Arcs, Ellipses, and Circles

15.3.1 Problem

You want to draw open or filled curves. For example, you want to draw a pie chart showing the results of a user poll.

15.3.2 Solution

To draw an arc, use ImageArc( ):
ImageArc($image, $x, $y, $width, $height, $start, $end, $color);
To draw an ellipse, use ImageArc( ) and set $start to 0 and $end to 360:
ImageArc($image, $x, $y, $width, $height, 0, 360, $color);
To draw a circle, use ImageArc( ), set $start to 0, set $end to 360, and use the same value for both $width and $height:
ImageArc($image, $x, $y, $diameter, $diameter, 0, 360, $color);

15.3.3 Discussion

Because the ImageArc( ) function is highly flexible, you can easily create common curves such as ellipses and circles by passing it the right values. Like many GD functions, the first parameter is the canvas. The next two parameters are the x and y coordinates for the center position of the arc. After that comes the arc width and height. Since a circle is an arc with the same width and height, to draw a circle, set both numbers to your circle's diameter.
The sixth and seventh parameters are the starting and ending angles, in degrees. A value of 0 is at 3 o'clock. The arc then moves clockwise, so 90 is at 6 o'clock, 180 is at 9 o'clock, and 270 is at the top of the hour. (Be careful, this behavior is not consistent among all GD functions. For example, when you rotate text, you turn in a counter-clockwise direction.) Since the arc's center is located at ($x,$y), if you draw a semicircle from 0 to 180, it doesn't start at ($x,$y); instead, it begins at ($x+($diameter/2),$y).
As usual, the last parameter is the arc color.
For example, this draws an open black circle with a diameter of 100 pixels centered on the canvas, as shown in left half of Figure 15-3:

PHP : Graphics - [15.4] Drawing with Patterned Lines

15.4.1 Problem

You want to draw shapes using line styles other than the default, a solid line.

15.4.2 Solution

To draw shapes with a patterned line, use ImageSetStyle( ) and pass in IMG_COLOR_STYLED as the image color:
$black = ImageColorAllocate($image,   0,   0,   0);
$white = ImageColorAllocate($image, 255, 255, 255);

// make a two-pixel thick black and white dashed line
$style = array($black, $black, $white, $white);
ImageSetStyle($image, $style);

ImageLine($image, 0, 0, 50, 50, IMG_COLOR_STYLED);
ImageFilledRectangle($image, 50, 50, 100, 100, IMG_COLOR_STYLED);

15.4.3 Discussion

The line pattern is defined by an array of colors. Each element in the array is another pixel in the brush. It's often useful to repeat the same color in successive elements, as this increases the size of the stripes in the pattern.
For instance, here is code for a square drawn with alternating white and black pixels, as shown in left side of Figure 15-4:
$style = array($white, $black);
ImageSetStyle($image, $style);
ImageFilledRectangle($image, 0, 0, 49, 49, IMG_COLOR_STYLED);
This is the same square, but drawn with a style of five white pixels followed by five black ones, as shown in the middle of Figure 15-4:
$style = array($white, $white, $white, $white, $white, 
               $black, $black, $black, $black, $black);
ImageSetStyle($image, $style);
ImageFilledRectangle($image, 0, 0, 49, 49, IMG_COLOR_STYLED);
Figure 15-4. Three squares with alternating white and black pixels

PHP : Graphics - [15.5] Drawing Text

15.5.1 Problem

You want to draw text as a graphic. This allows you to make dynamic buttons or hit counters.

15.5.2 Solution

For built-in GD fonts, use ImageString( ):
ImageString($image, 1, $x, $y, 'I love PHP Cookbook', $text_color);
For TrueType fonts, use ImageTTFText( ):
ImageTTFText($image, $size, 0, $x, $y, $text_color, '/path/to/font.ttf', 
             'I love PHP Cookbook');
For PostScript Type 1 fonts, use ImagePSLoadFont( ) and ImagePSText( ):
$font = ImagePSLoadFont('/path/to/font.pfb');
ImageString($image, 'I love PHP Cookbook', $font, $size, 
            $text_color, $background_color, $x, $y);

15.5.3 Discussion

Call ImageString( ) to place text onto the canvas. Like other GD drawing functions, ImageString( ) needs many inputs: the image to draw on, the font number, the x and y coordinates of the upper right position of the first characters, the text string to display, and finally, the color to use to draw the string.
With ImageString( ), there are five possible font choices, from 1 to 5. Font number 1 is the smallest, while font 5 is the largest, as shown in Figure 15-5. Anything above or below that range generates a size equivalent to the closest legal number.
Figure 15-5. Built-in GD font sizes
To draw text vertically instead of horizontally, use the function ImageStringUp( ) instead. Figure 15-6 shows the output.
ImageStringUp($image, 1, $x, $y, 'I love PHP Cookbook', $text_color);
Figure 15-6. Vertical text
figs/phpc_1506.gif
To use TrueType fonts, you must also install the FreeType library and configure PHP during installation to use FreeType. The FreeType main site is http://www.freetype.org. To enable FreeType 1.x support, use --with-ttf and for FreeType 2.x, pass --with-freetype-dir=DIR.
Like ImageString( ), ImageTTFText( ) prints a string to a canvas, but it takes slightly different options and needs them in a different order:
ImageTTFText($image, $size, $angle, $x, $y, $text_color, '/path/to/font.ttf', 
             $text);
The $size argument is the font size in pixels; $angle is an angle of rotation, in degrees going counter-clockwise; and /path/to/font.ttf is the pathname to TrueType font file. Unlike ImageString( ), ($x,$y) are the lower left coordinates of the baseline for the first character. (The baseline is where the bottom of most characters sit. Characters such as "g" and "j" extend below the baseline; "a" and "z" sit on the baseline.)
PostScript Type 1 fonts require t1lib to be installed. It can be downloaded from ftp://sunsite.unc.edu/pub/Linux/libs/graphics/ and built into PHP using --with-t1lib.
Again, the syntax for printing text is similar but not the same:
$font = ImagePSLoadFont('/path/to/font.pfb');
ImagePSText($image, $text, $font, $size, $text_color, $background_color, $x, $y);
ImagePSFreeFont($font);

PHP : Graphics - [15.6] Drawing Centered Text

15.6.1 Problem

You want to draw text in the center of an image.

15.6.2 Solution

Find the size of the image and the bounding box of the text. Using those coordinates, compute the correct spot to draw the text.
For built-in GD fonts, use the pc_ImageStringCenter( ) function shown in Example 15-1.
Example 15-1. pc_ImageStringCenter( )
function pc_ImageStringCenter($image, $text, $font) {
    
    // font sizes
    $width  = array(1 => 5, 6, 7, 8, 9);
    $height = array(1 => 6, 8, 13, 15, 15);

    // find the size of the image
    $xi = ImageSX($image);
    $yi = ImageSY($image);

    // find the size of the text
    $xr = $width[$font] * strlen($text);
    $yr = $height[$font];

    // compute centering
    $x = intval(($xi - $xr) / 2);
    $y = intval(($yi - $yr) / 2);

    return array($x, $y);
}
For example:
list($x, $y) = pc_ImageStringCenter($image, $text, $font);
ImageString($image, $font, $x, $y, $text, $fore);
For PostScript fonts, use the pc_ImagePSCenter( ) function shown in Example 15-2.
Example 15-2. pc_ImagePSCenter( )
function pc_ImagePSCenter($image, $text, $font, $size, $space = 0,
                           $tightness = 0, $angle = 0) {

    // find the size of the image
    $xi = ImageSX($image);
    $yi = ImageSY($image);

    // find the size of the text
    list($xl, $yl, $xr, $yr) = ImagePSBBox($text, $font, $size,
                                     $space, $tightness, $angle);

    // compute centering
    $x = intval(($xi - $xr) / 2);
    $y = intval(($yi + $yr) / 2);

    return array($x, $y);
}
For example:
list($x, $y) = pc_ImagePSCenter($image, $text, $font, $size);
ImagePSText($image, $text, $font, $size, $fore, $back, $x, $y);
For TrueType fonts, use the pc_ImageTTFCenter( ) function shown in Example 15-3.
Example 15-3. pc_ImageTTFCenter( )
function pc_ImageTTFCenter($image, $text, $font, $size) {

    // find the size of the image
    $xi = ImageSX($image);
    $yi = ImageSY($image);

    // find the size of the text
    $box = ImageTTFBBox($size, $angle, $font, $text);

    $xr = abs(max($box[2], $box[4]));
    $yr = abs(max($box[5], $box[7]));

    // compute centering
    $x = intval(($xi - $xr) / 2);
    $y = intval(($yi + $yr) / 2);

    return array($x, $y);
}
For example:
list($x, $y) = pc_ImageTTFCenter($image, $text, $font, $size);
ImageTTFText($image, $size, $angle, $x, $y, $fore, $font, $text);

15.6.3 Discussion

PHP : Graphics - [15.7] Building Dynamic Images

15.7.1 Problem

You want to create an image based on a existing image template and dynamic data (typically text). For instance, you want to create a hit counter.

15.7.2 Solution

Load the template image, find the correct position to properly center your text, add the text to the canvas, and send the image to the browser:
// Configuration settings
$image    = ImageCreateFromPNG('button.png');
$text     = $_GET['text'];
$font     = ImagePSLoadFont('Times');
$size     = 24;
$color    = ImageColorAllocate($image,   0,   0,   0); // black
$bg_color = ImageColorAllocate($image, 255, 255, 255); // white

// Print centered text
list($x, $y) = pc_ImagePSCenter($image, $text, $font, $size);
ImagePSText($image, $text, $font, $size, $color, $bg_color, $x, $y);

// Send image
header('Content-type: image/png');
ImagePNG($image);

// Clean up
ImagePSFreeFont($font);
ImageDestroy($image);

15.7.3 Discussion

Building dynamic images with GD is easy; all you need to do is combine a few recipes together. At the top of the code in the Solution, we load in an image from a stock template button; it acts as the background on which we overlay the text. We define the text to come directly from the query string. Alternatively, we can pull the string from a database (in the case of access counters) or a remote server (stock quotes or weather report icons).
After that, we continue with the other settings: loading a font and specifying its size, color, and background color. Before printing the text, however, we need to compute its position; pc_ImagePSCenter( ) from Section 15.7 nicely solves this task. Last, we serve the image, and deallocate the font and image from memory.
For example, the following code generates a page of HTML and image tags using dynamic buttons, as shown in Figure 15-9:
<?php
if (isset($_GET['button'])) {

    // Configuration settings
    $image    = ImageCreateFromPNG('button.png');
    $text     = $_GET['button'];      // dynamically generated text
    $font     = ImagePSLoadFont('Times');
    $size     = 24;
    $color    = ImageColorAllocate($image,   0,   0,   0); // black
    $bg_color = ImageColorAllocate($image, 255, 255, 255); // white

    // Print centered text
    list($x, $y) = pc_ImagePSCenter($image, $text, $font, $size);
    ImagePSText($image, $text, $font, $size, $color, $bg_color, $x, $y);

    // Send image
    header('Content-type: image/png');
    ImagePNG($image);

    // Clean up
    ImagePSFreeFont($font);
    ImageDestroy($image);

} else {
?>
<html>
<head>
    <title>Sample Button Page</title>
</head>
<body>
    <img src="<?php echo $_SERVER['PHP_SELF']; ?>?button=Previous" 
         alt="Previous" width="132" height="46">
    <img src="<?php echo $_SERVER['PHP_SELF']; ?>?button=Next" 
         alt="Next"     width="132" height="46">
</body>
</html>
<?php
}
?>

PHP : Graphics - [15.8] Getting and Setting a Transparent Color

15.8.1 Problem

You want to set one of an image's colors as transparent. When the image is overlayed on a background, the background shows through the transparent section of the image.

15.8.2 Solution

Use ImageColorTransparent( ):
$color = ImageColorAllocate($image, $red, $green, $blue);
ImageColorTransparent($image, $color);

15.8.3 Discussion

Both GIFs and PNGs support transparencies; JPEGs, however, do not. To refer to the transparent color within GD, use the constant IMG_COLOR_TRANSPARENT. For example, here's how to make a dashed line that alternates between black and transparent:
// make a two-pixel thick black and white dashed line
$style = array($black, $black, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT);
ImageSetStyle($image, $style);
To find the current transparency setting, take the return value of ImageColorTransparent( ) and pass it to ImageColorsForIndex( ):
$transparent = ImageColorsForIndex($image, ImageColorTransparent($image));
print_r($transparent);
Array
(
    [red] => 255
    [green] => 255
    [blue] => 255
)
The ImageColorsForIndex( ) function returns an array with the red, green, and blue values. In this case, the transparent color is white.

PHP : Graphics - [15.9] Serving Images Securely

15.9.1 Problem

You want to control who can view a set of images.

15.9.2 Solution

Don't keep the images in your document root, but store them elsewhere. To deliver a file, manually open it and send it to the browser:
header('Content-Type: image/png');
readfile('/path/to/graphic.png');

15.9.3 Discussion

The first line in the Solution sends the Content-type header to the browser, so the browser knows what type of object is coming and displays it accordingly. The second opens a file off a disk (or from a remote URL) for reading, reads it in, dumps it directly to the browser, and closes the file.
The typical way to serve up an image is to use an <img> tag and set the src attribute to point to a file on your web site. If you want to protect those images, you probably should use some form of password authentication. One method is HTTP Basic Authentication, which is covered in Section 8.10.
The typical way, however, may not always be the best. First, what happens if you want to restrict the files people can view, but you don't want to make things complex by using usernames and passwords? One option is to link only to the files; if users can't click on the link, they can't view the file. They might, however, bookmark old files, or they may also try and guess other filenames based on your naming scheme and manually enter the URL into the browser.
If your content is embargoed, you don't want people to be able to guess your naming scheme and view images. When information is embargoed, a select group of people, usually reporters, are given a preview release, so they can write stories about the topic or be ready to distribute it the moment the embargo is lifted. You can fix this by making sure only legal content is under the document root, but this requires a lot of file shuffling back and forth from directory to directory. Instead, you can keep all the files in one constant place, and deliver only files that pass a check inside your code.
For example, let's say you have a contract with a publishing corporation to redistribute one of their comics on your web site. However, they don't want you to create a virtual archive, so you agree to let your users view only the last two weeks worth of strips. For everything else, they'll need to go to the official site. Also, you may get comics in advance of their publication date, but you don't want to let people get a free preview; you want them to keep coming back to your site on a daily basis.
Here's the solution. Files arrive named by date, so it's easy to identify which files belong to which day. Now, to lock out strips outside the rolling 14-day window, use code like this:
// display a comic if it's less than 14 days old and not in the future

// calculate the current date
list($now_m,$now_d,$now_y) = explode(',',date('m,d,Y'));
$now = mktime(0,0,0,$now_m,$now_d,$now_y);

// two hour boundary on either side to account for dst
$min_ok = $now - 14*86400 - 7200; // 14 days ago
$max_ok = $now + 7200;            // today

// find the time stamp of the requested comic
$asked_for = mktime(0,0,0,$_REQUEST['mo'],$_REQUEST['dy'],$_REQUEST['yr']);

// compare the dates
if (($min_ok > $asked_for) || ($max_ok < $asked_for)) {
    echo 'You are not allowed to view the comic for that day.';
} else {
    header('Content-type: image/png');
    readfile("/www/comics/$_REQUEST['mo']$_REQUEST['dy'] $_REQUEST['yr'].png");
}

PHP : Graphics - [15.10] Program: Generating Bar Charts from Poll Results

When displaying the results of a poll, it can be more effective to generate a colorful bar chart instead of just printing the results as text. The function shown in Example 15-4 uses GD to create an image that displays the cumulative responses to a poll question.

Example 15-4. Graphical bar charts
function pc_bar_chart($question, $answers) {

    // define colors to draw the bars
    $colors = array(array(255,102,0), array(0,153,0),
                    array(51,51,204), array(255,0,51),
                    array(255,255,0), array(102,255,255), 
                    array(153,0,204));

    $total = array_sum($answers['votes']);
    
    // define some spacing values and other magic numbers
    $padding = 5;
    $line_width = 20;
    $scale = $line_width * 7.5;
    $bar_height = 10;

    $x = $y = $padding;

    // allocate a large palette for drawing, since we don't know
    // the image length ahead of time
    $image = ImageCreate(150, 500);
    $bg_color = ImageColorAllocate($image, 224, 224, 224);
    $black = ImageColorAllocate($image, 0, 0, 0);

    // print the question
    $wrapped = explode("\n", wordwrap($question, $line_width));
    foreach ($wrapped as $line) {
        ImageString($image, 3, $x, $y , $line, $black);
        $y += 12;
    }

    $y += $padding;

    // print the answers
    for ($i = 0; $i < count($answers['answer']); $i++) { 

        // format percentage
        $percent = sprintf('%1.1f', 100*$answers['votes'][$i]/$total);
        $bar = sprintf('%d', $scale*$answers['votes'][$i]/$total);

        // grab color
        $c = $i % count($colors); // handle cases with more bars than colors
        $text_color = ImageColorAllocate($image, $colors[$c][0], 
                                 $colors[$c][1], $colors[$c][2]);

        // draw bar and percentage numbers
        ImageFilledRectangle($image, $x, $y, $x + $bar,
                             $y + $bar_height, $text_color);
        ImageString($image, 3, $x + $bar + $padding, $y, 
                    "$percent%", $black);

         $y += 12;

         // print answer
         $wrapped = explode("\n", wordwrap($answers['answer'][$i], $line_width));
         foreach ($wrapped as $line) {
             ImageString($image, 2, $x, $y, $line, $black);
             $y += 12;
         }

         $y += 7;
     }

     // crop image by copying it
     $chart = ImageCreate(150, $y);
     ImageCopy($chart, $image, 0, 0, 0, 0, 150, $y);

     // deliver image
     header ('Content-type: image/png');
     ImagePNG($chart);

     // clean up
     ImageDestroy($image);
     ImageDestroy($chart);
}