Beginning PHP4

This excerpt is from Wrox’s book Beginning PHP4. It covers the entirety of Chapter 16 – PHP graphics processing. Buy this book on Amazon.com now!

By now you will have a very good understanding not only of how PHP works but the flexibility and wide range of platforms and programming applications that you can interact with in PHP. You can confidently connect to databases and create textual output for the person browsing your web site to view, but sooner or later you are going to need to output that information in a graphical format. Sure you could fire up a graphics program and create a few good looking graphics for your site, but what about when your graphic is directly related to the data in your database?

PHP contains a range of functions that allow you to open, manipulate and output graphics to the web browser. During this chapter we will explore how these functions work and how we can apply them to display our data.

By the end of the chapter we will not only have seen how to create images on the fly, but will have built a practical application using these methods and concepts.

{mospagebreak title=Introduction} By now you will have a very good understanding not only of how PHP works but the flexibility and wide range of platforms and programming applications that you can interact with in PHP. You can confidently connect to databases and create textual output for the person browsing your web site to view, but sooner or later you are going to need to output that information in a graphical format. Sure you could fire up a graphics program and create a few good looking graphics for your site, but what about when your graphic is directly related to the data in your database?

PHP contains a range of functions that allow you to open, manipulate and output graphics to the web browser. During this chapter we will explore how these functions work and how we can apply them to display our data.

By the end of the chapter we will not only have seen how to create images on the fly, but will have built a practical application using these methods and concepts.

{mospagebreak title=Laying a Foundation} As with all things in life, we have to learn to walk before we can run – before we can jump in and start producing the goods, we have a few basics to get through. PHP uses the gd graphics library for all but its most basic image functions. Provided you have a recent version of the library, you can create and manipulate images in a number of different formats; the two most noteworthy are JPEG and PNG. These are both compressed file formats, which means that they use mathematical algorithms to reduce the amount of data required to completely describe the image. They therefore play a very important role in keeping your file sizes small and download times short!

It’s important to be able to recognize where you should use each format – they use quite different compression techniques, and most images will be better suited to one or the other.

The JPEG format uses lossy compression. What this means is that some of the data in the original image is lost during compression. The format is designed to work best with images like photographs (that’s where the “P” in “JPEG” comes from), where there’s a lot of subtle shading and not too much fine detail. It’s the format to use when a slight loss in quality won’t be too apparent to the viewer.

The PNG format on the other hand is compressed in a lossless fashion. It works best with images that contain lines and large blocks of color, cartoons for example. When the image is uncompressed, it will contain all of its original information. This means that sharp edges and straight lines (which suffer under JPEG compression) will be reproduced faithfully.

Early versions of gd (and thus PHP) contained support for GIF files, which are similar in many respects to PNG. However, Unisys holds a patent on the LZW compression algorithm used to create fully compressed GIFs, and consequently GIF support has been completely replaced by that for PNG files since gd version 1.6. All is far from lost though, as JPEG and the excellent PNG image encoding formats should be sufficient for all your graphics needs. Before we even look at the technicalities of creating the image, let’s go through the steps involved in getting PHP to create an image and display it in the browser:

This is effectively just a section of memory in which we define an image before outputting it to the browser or to disk.

Create an image canvas for PHP to work on – this is simply a reserved portion of server memory, onto which the script will “draw” (that is, write data) before outputting it to the browser or disk as an image.

Draw the picture on the image canvas.

Send the image to the browser.

Clean up memory by throwing away the image canvas.

{mospagebreak title=Creating an Image} As mentioned above, the first thing we need to do is create a blank image canvas for PHP to work on – a call to the ImageCreate() function does just this. The only two things we need to tell it are the width and height of the image we wish to create. ImageCreate() will then return an identifier that identifies that blank image in memory. All the subsequent image functions we use will have to refer to the image in memory by means of this identifier.

This identifier is similar to a file handle or database link ID, as we’ve used in recent chapters, but refers to the location of our image canvas in memory rather than an open file on the disk or an active database connection.


$image = ImageCreate(200,150);


We’ve now defined $image as the identifier referring to the new, blank canvas (200 pixels wide by 150 pixels high) that ImageCreate() has just created for us. Now that this 200 x 150 pixel image is in memory we can start drawing on it. First though, we need to know what color we’ll be drawing in.

Setting up Colors

Before we can tell PHP that we want to use a certain color on our canvas, we have to create that color. We do this in a similar fashion to that of creating the image canvas:

$gray = ImageColorAllocate($image,204,204,204);
$blue = ImageColorAllocate($image,0,0,255);



We’ve used the function ImageColorAllocate() to define two colors for our image: a gray and a blue. Each color is assigned a unique identifier and tied to an existing image canvas. As you can see, this function requires 4 pieces of information:

The first is the identifier of the image canvas with which this color will be used. This is the same identifier that we saw returned to us earlier from the ImageCreate() function.

The second, third and fourth things we need to tell ImageColorAllocate() are the respective values of red, green and blue components for that color, which must lie between 0 and 255.

Computers make up color by mixing different quantities of Red, Green and Blue. This is what is known as RGB mode color. Each of red, green and blue can range from 0 to 255. Setting each of red, green and blue to 0 will give us black (total absence of color), a value of 255 for all three will give us white. If we want to stick to web-safe colors, then we have to limit our values of red, green and blue to multiples of 51. That gives us 6 possible values for each of red, green and blue, for a total of 216 colors. $gray and $blue are now two new identifiers to the colors gray and blue. We created the former by specifying equal values of each color. Note that 204 was not a number we pulled from the hat, but a multiple of 51, and we’ve therefore defined a web-safe color. We defined $blue by telling ImageColorAllocate() that the red component was 0, the green component was 0 and that the blue component was 255.

The Image Coordinate System

While we’re dealing with theory here, we may as well take a look at how the image coordinate system works. It may sound like a mouthful but it’s simply a way for us to precisely describe points in the image.

If you’re familiar with creating graphs, you’ll probably be used to the x and y values radiating outwards from the bottom left hand corner. In PHP, all coordinates radiate outwards from the top left-hand corner of the image, as the image below shows:



With this in mind, let’s take a look at how our blank $image is laid out:



The x-y coordinates for the top left corner of $image are 0,0. This will be true for every image that you create. The x-coordinates extend to the right for 200 pixels and y-coordinates extend down for 150 pixels, so the bottom right-hand corner of the image has x-y coordinates of 199,149.

{mospagebreak title=Drawing on our Image} Now that we’ve seen how the coordinate system works and have two colors to draw with, we can start making pictures. But what about allocating a background color for our image? ImageCreate()didn’t have an argument that allowed us to specify the background color of the image.

As it happens, we don’t need to tell the image what its background color is explicitly; the first color we allocate to the image automatically becomes the background color. Looking back at the code that we’ve covered so far:



$image = ImageCreate(200,150);
$gray = ImageColorAllocate($image,204,204,204);
$blue = ImageColorAllocate($image,0,0,255);


we see that the first color allocated was $gray. Our background color for $image will therefore automatically be gray. We will use our pure blue $blue to draw the shapes on our image.

Lines

To draw a line, we use the ImageLine() function, using the following format:

ImageLine($image, 10,10, 150,30, $blue);

As usual, the first thing we have to tell the function is the identifier of the image canvas we’re working on. The next two arguments are the x and y coordinates of the start of the line, while the two after that are coordinates for the end of the line. The final argument is the identifier for the color in which we’ll be drawing the line. The example above draws a line that starts 10 pixels from the left and 10 pixels from the top of the image, and ends at x = 150, y = 30. The layout of the resulting image is shown in the diagram below:



Once the line has been drawn onto the image canvas, we need to either save the canvas to disk or send it to the browser. We’re going to do the latter, using a function. This only requires one piece of information: the identifier of the image canvas that we want to output:


ImageJPEG($image);

If we want to save the image to disk, we can specify a second argument, containing the filename we want to use:


ImageJPEG($image, “image.jpg”);

If we’re saving the image as a disk file, we can also specify a third argument. This must be an integer value between –1 and 100, which specifies the quality of the resulting JPEG image.

A value of 0 will generate a small file but consequently a very low quality image. On the other hand, a value of 100 will give you high quality but a larger file. The images below should gives you some idea of the trade-offs you’ll be looking at:

Line quality = -1


Line quality = 20


Line quality = 100


A value of –1 tells the ImageJPEG() function that it should use default quality, which should be very close to optimal – in practice this is equivalent to a setting of around 70.

Something else that we need to bear in mind at this point is the Header() function. Whenever we send non-HTML data to the browser, we should let it know what it is, so that it can be properly processed. We use this function at the top of our example to produce a page header, and let the browser know what sort of file to expect:


Header(“Content-type: image/jpeg”);



Finally, we need to call the ImageDestroy() function with the image identifier. It will be no surprise to you that this function destroys the image canvas, freeing up the server memory it occupied.

Let’s take a look at our complete code at this point:


<?php
//draw1.php
Header(“Content-type: image/jpeg”);
$image = ImageCreate(200,150);
$gray = ImageColorAllocate($image,204,204,204);
$blue = ImageColorAllocate($image,0,0,255);
ImageLine($image,10,10,150,30,$blue);
ImageJPEG($image);
ImageDestroy($image);
?>

Which gives us:



Circles

To create an arc, circle or ellipse in PHP, we use a function called ImageArc() with the following syntax:



ImageArc(image_id, x, y, width, height, start, end, color_id);



As you can see this function takes quite a few arguments. The first is, as usual, the image identifier. Next are our x and y coordinates, and in this case they specify the center point of our arc. The width and height are the width and height of the circle or ellipse from which we take the arc.

Note we don’t use a radius, as this would limit us to using a perfect arc or circle. The option to have different height and width means that we can use this function to create ellipses. A circle is simply an ellipse whose height and width are equal.

Start and end points for the arc are measured clockwise in degrees from the right-hand horizontal radius (that is, three o’clock):



The slanted line we created earlier had one end at the position x = 150, y = 30. We’re now going to create a circle that’s 70 pixels across, the top of which touches this end of that line. The x value for the center of our circle will therefore be 150 again, but the y value must be greater than that of the line end by 35 (that is, half the width of the circle – remember we’re dealing with a width of 70, not a radius).

The y value for the end of the line is 30, the circle center must have y = 65. Since we are going to create a full circle, we must draw our arc through a complete 360 degrees: start = 0 and end = 360. We’ll draw the circle in blue as well.

Our code now looks like this:



<?php
//draw2.php
Header(“Content-type: image/jpeg”);
$image = ImageCreate(200,150);
$gray = ImageColorAllocate($image,204,204,204);
$blue = ImageColorAllocate($image,0,0,255);
ImageLine($image,10,10,150,30,$blue);
ImageArc($image,150,65,70,70,0,360,$blue);
ImageJPEG($image);
ImageDestroy($image);
?>



and produces this:



Rectangles

If you’ve picked up on any of the trends in this chapter, you’ll have guessed by now that the function to create a rectangle in PHP is ImageRectangle():



ImageRectangle(image_id, x1, y1, x2, y2, color_id);

The arguments correspond to the image identifier, the x and y coordinates of the top left-hand corner of the rectangle, the x and y coordinates of the bottom right-hand corner of the rectangle, and the identifier for the color we want it drawn in.



Pretty straightforward, right? Here’s the code, which now adds a box whose top right-hand corner is at x = 150, y = 65, the same as the center of the circle.



<?php
//draw3.php
Header(“Content-type: image/jpeg”);
$image = ImageCreate(200,150);
$gray = ImageColorAllocate($image,204,204,204);
$blue = ImageColorAllocate($image,0,0,255);
ImageLine($image,10,10,150,30,$blue);

ImageArc($image,150,65,70,70,0,360,$blue);
ImageRectangle($image,10,65,150,140,$blue);
ImageJPEG($image);
ImageDestroy($image);
?>



This now returns the following image:



{mospagebreak title=Putting it all Together} So far we’ve covered creating an image, outputting it to the browser and cleaning up after ourselves. Between creating the image and outputting it we also covered creating lines, circles and rectangles on our image.

PHP currently has no function that allows us to create a rectangle with rounded corners. In order to recap what we covered so far, we’re going to create a function that does just that. We’ll be able to pass this function the same information that you would pass to ImageRectangle(), but with an extra argument telling it the radius of the arc that we want to use for the corner. Our prototype will therefore be:



udImageRoundRect($image, $x1, $y1, $x2, $y2, $arcradius, $color)



We’ll never use $x1, $y1, $x2, or $y2 as actual points in any of the plots, but we will use them to work out where our arcs must be centered, as well as where our lines must start and end. In the image above, we know that ($x1, $y1) is where our rectangle would have started if it didn’t have a rounded corner. We can work out where the center of the arc must be by adding $arcradius to each of $x1 and $y1. Remember that we will only be adding to both x and y values in the top left-hand corner of the rectangle. In other corners we will have to subtract $arcradius from one or both of the values.

Let’s dive into the code and take a look. We’re going to define our function in an include file called roundrect.inc:


<?php
//roundrect.inc
function udImageRoundRect($image,$x1,$y1,$x2,$y2,$arcradius,$color) {

  $arcwidth = ($arcradius*2);

  // top left hand corner
  ImageArc($image, $x1+$arcradius, $y1+$arcradius,
                   $arcwidth,      $arcwidth,
                   180,            270,
           $color);



The first thing we do is to double $arcradius, giving us the width of the arc; we can pass this directly to ImageArc().

The next line draws the top left-hand corner arc. The center of the arc is at:

x = $x1 + $arcradius (just to the right of the corner of the rectangle), y = $y1 + $arcradius (just down from the same corner). The width and height of the arc are both equal to $arcwidth, since we want the corner to be rounded, not ellipsoid. We start the arc at 180° (9 o’clock) and end at 270° (12 o’clock) – a 90° arc. As we move around the corners our degrees will shift by 90° each time.


// top right hand corner
  ImageArc($image, $x2-$arcradius, $y1+$arcradius,
                   $arcwidth,      $arcwidth,
                   270,            360,            $color);



Now that we’re at the top right-hand corner we must use the $x2 value and this time subtract $arcradius – the center of the arc will be to the left of the rectangle corner. We are still working with $y1 and since it’s at the same horizontal level, we still use $y1 + $arcradius. As you can see in the diagram opposite, we also need to shift each of our degrees clockwise by 90 degrees.



Each of the bottom corners work in exactly the same way; you just have to remember whether to add or subtract, and which x and y values you should be working with:


// bottom right hand corner
  ImageArc($image, $x2-$arcradius, $y2-$arcradius,
                   $arcwidth,      $arcwidth,
                   0,              90,             $color);

 // bottom left hand corner
 ImageArc($image, $x1+$arcradius, $y2-$arcradius,
                  $arcwidth,      $arcwidth,
                  90,             180,             $color);

The last part of our script draws in the connecting lines between the rounded corners. Now if we were going to draw in our top line as if we weren’t using rounded corners, we would simply use ($x1, $y1) as our first coordinate and ($x2, $y1) as our second coordinate. Since we have to take the corners into account, we must adjust some of these coordinates by $arcradius:


  // top line
  ImageLine($image, $x1+$arcradius, $y1,
                    $x2-$arcradius, $y1, $color);
  // right line
  ImageLine($image, $x2, $y1+$arcradius,
                    $x2, $y2-$arcradius, $color);

  // bottom line
  ImageLine($image, $x1+$arcradius, $y2,
                    $x2-$arcradius, $y2, $color);
  // left line
  ImageLine($image, $x1, $y1+$arcradius,
                    $x1, $y2-$arcradius, $color);
}
?>

And that’s it for roundrect.inc. We can now write a PHP script like this:


<?php
//roundrect.php
Header(“Content-type: image/jpeg”);
include “roundrect.inc”;



$image = ImageCreate(200,150);
$gray = ImageColorAllocate($image,204,204,204);
$blue = ImageColorAllocate($image,0,0,255);
udImageRoundRect($image,10,10,190,140,30,$blue);
ImageJPEG($image);
ImageDestroy($image);
?>



The first line includes the roundrect.inc file created above, so we have access to our new user-defined function udImageRoundRect():



udImageRoundRect($image,10,10,190,140,30,$blue);

We start the rectangle at (10,10) and end it at (190,140); 10 pixels clear of each edge of the image. The radius of our corner arcs will be 30 pixels. If we run the script we get an image like this:



[gp-comments width="770" linklove="off" ]

chat