using Programming;

A Blog about some of the intrinsics related to programming and how one can get the best out of various languages.

Getting Started with PHP: Part 5

Getting started with PHP: Part 5

We last went through some of the object-oriented features of PHP, specifically the basics of classes and function. In particular, we covered the following:

  • What are classes;
  • Basics of instance functions;
  • Basics of static functions;
  • Class variables;
  • Visibility modifiers;
  • Constructors;
  • Constants;
  • Including other PHP files via include, include_once, require and require_once;
  • Interfaces;

Today, we're going to start playing with another feature of PHP: GD.

What is GD?

GD, or "graphics draw", is a set of functions in PHP that allow developers to work with images. Reading, editing, drawing, loading and saving, in particular.

Any time you read an image to display it, GD is doing that work. The only exception is if you stream an image (as data) from one source to another. We'll actually look at that later on in this session.

At it's core, GD is the combination of all image functions in PHP: reading images, saving images, editing images, drawing shapes and so on.

What is an image?

It may seem silly, but before we work with GD we have to first talk about what an "image" is.

We're not going to talk about ways images are "encoded" or "stored", we're strictly going to talk about what make an image.

An image at it's most abstract is a visual representation of a graphical scene, but, we don't want to talk about the abstract: we want to talk about something more concrete.

In technology, an image is a sequence of points of various colors that represent a visual picture.

We typically represent colors with either an RGB, HSV, or HSL value, all with potential optional "alpha" components. We're going to look at the first two of these, starting with RGB, because it is perhaps the simplest to understand.

Note: there are other color representation methods, such as CMYK (often used in printing), but we typically deal with the three aforementioned the most in computing. We often use the others in specialized scenarios, but we won't be talking about those scenarios here.

What are Colors?

Let's talk about colors for a moment.

A "color" is just a way of representing the light spectrum: that is, how we "see" things. We can even "measure" colors with sensors that can identify the frequency and brightness of the light.

RGB Colors

At a basic level, we can think of a color as a mixture of red, green, and blue components. In school, you may have learned that red, green and blue are the three "true" primary colors. That is, any color can be created by mixing a different percentage of those three colors. For example, by mixing red and green we can create yellow, by mixing red, green and blue we can create "white". By not using any of the colors we create "black".

In computing systems we represent them in a few different ways, but for our work we'll be using values of 0 through 255 for each color component when we discuss them, in a "tuple" or comma-separated list in the order "red, green, blue": RGB(0, 0, 0) represents black, RGB(255, 255, 255) represents white, RGB(255, 255, 0) represents yellow, as discussed before.

HSV Colors

The next thing to discuss is "HSV" color representation, which is hue, saturation, value. In this representation, colors are represented with three properties:

  • "hue" which is the "frequency" of the light resembled by the color (typically 0 to 360);
  • "saturation" which is how much of the color vs. white is present (typically 0 to 1), a value of 0 means the white/hue balance is entirely on the white side, and a value of 1 means the white/hue balance is entirely on the hue side;
  • "value" which is how much of the color vs. black is present (typically 0 to 1), a value of 0 means the black/hue balance is entirely on the black side, and a value of 1 means the black/hue balance is entirely on the hue side;

Once again, when discussing these colors, we use a tuple of three numbers, in the order of the abbreviation: hue, then saturation, then value.

One interesting side-effect of HSV is that there are an infinite number of black values, and an infinite number of white values. This is because rather than working on a group of integers, it works on a group of floating-point values. The hue may range from 0 to 360, but it is actually an angle along a circle, and as a result is infinite (though, in practice, this is typically limited to integer values). This means that HSV(0, 0, 0) is black, as is HSV(120, 0, 0), and HSV(240, 0, 0).

While we will not be using HSV in our examples, it is important to know that RGB is not the only color theme out there.

Alpha Component

One additional thing to discuss is the "alpha" component, which is effectively a "transparency" component, in RGB ranging from 0 to 255 typically. A value of 0 means that the color is completely transparent, and a value of 255 means the color is completely opaque.

Transparency just means "how much of what is behind this color is visible". We often use it to draw one image over another and show part of the image beneath.

Opening Images

Right, so let's get started. Before we can play with images, we have to open them. We have to read them into our software.

Opening and reading images in PHP is relatively straightforward. The GD API provides a bunch of imagecreatefrom<x> functions that work on specific file types. I've detailed a couple below:

  • imagecreatefrombmp: creates an image from a bitmap / .bmp file;
  • imagecreatefromgif: creates an image from a graphics interchange format / .gif file;
  • imagecreatefromjpeg: creates an image from a JPEG (joint photographic experts group) format / .jpeg, .jpg, .jpe, .jfi, .jfif, .jif file;
  • imagecreatefrompng: creates an image from a portable network format / .png file;

There are others, and if you have time I recommend exploring them. For the sake of our work, we'll only be dealing with those throughout the process.

Using all of these functions are basically the same, and relatively easy. Each one takes a single parameter which is the name of the file to open. If certain PHP extensions and features are enabled you can also provide a URL instead of a file name.

To make an image, we just pull it into a variable like normal:

$image = @imagecreatefromjpg($filename);

You may notice the at-sign (@) is new, we use @<function call> to suppress errors from the function. It's similar to a try / catch, but with an empty catch.

Error suppression

It's not often recommended, but we can use error-suppression on function calls to make life a bit easier. Instead of needing a bulky try / catch block, we simply use the @ to suppress the error.

The method behind the @ suppression operator is relatively tricky, but it basically sets the error-reporting level to 0 for that call. We've never discussed the error-reporting level before, but the basics are that PHP has several "levels" of errors. Some errors are considered 'fatal' and will stop script execution, some just print unpleasant output to our response.

Back to Opening Images

We use error suppression in our imagecreatefromjpg to ensure that if the image fails to load we can handle that specifically. Typically, we would do something like:

$image = @imagecreatefromjpg($filename);
if (!$image) { // test that the `$image` variable is set, in this case prove it's not set
    // the image failed to load, so we should display an error to the user
} else {
    // do something with the loaded image

Generally speaking, if the image fails to load we just assume that the file doesn't exist. There are other reasons it might fail to load, such as faulty permissions, but most of the time it's just not there.

Once we've opened the image, it will be a "resource" and we can start workign with it. But before we do that, we want to save it again to make sure that we can see our changes once we start making some.

Saving Images

To save images we use functions that, quite literally, do the opposite of opening them. Conveniently, they are named the following:

  • imagebmp: saves an image as a BMP;
  • imagegif: saves an image as a GIF;
  • imagejpeg: saves an image as a JPG/JPEG;
  • imagepng: saves an image as a PNG;

Now, these functions can do more than just save images to a file, these functions can also send images to a stream or output them to the browser.

To start with, we'll just save images back to a file. With each of these we just pass the image, then the filename to save to:

$result = @imagejpg($image, $filename);

All four functions have the same first two parameters, but imagejpg and imagepng take additional parameters that determine how the image should be compressed and other options. We won't worry about those for now, we're just going to pass the $image and a $filename.

Creating Blank Images

The last boring bit to talk about is creating images in PHP. Obviously it's not always the case that we have an image to start with, sometimes we want to "create" a new image from scratch.

Creating an image in PHP happens primarily with the use of two functions:

  • imagecreate: creates a "palette" based image;
  • imagecreatetruecolor: creates a true-color based image;

A "palette" based image has a fixed list of colors available, i.e. a "palette", and can only draw colors from that list. No other colors can be drawn to the screen. A true-color image can draw any color, whether it's in the palette or not.

There are also two functions for converting between the two:

  • imagepalettetotruecolor: converts a palette image to true-color;
  • imagetruecolortopalette: converts a true-color image to palette;

We're only going to look at true-color images, created via the imagecreatetruecolor function.

To create an image, we just supply imagecreatetruecolor with a $width and $height, which are integers that represent how wide and high the image is (the dimensions):

$image = imagecreatetruecolor(800, 600); // creates an 800x600 image, i.e. one of the older VGA resolutions

Much like before, we can manipulate and save this image.

Manipulating Images

Right, so on to the fun part. Let's start drawing on images!

Images are just a bunch of points, sometimes making shapes. PHP has a bunch of GD functions that make drawing shapes and text really easy. We're going to talk about them and see examples of how they work.

Fortunately, if we want to draw shapes, PHP has a bunch of GD functions that make doing so easy.

To begin, we have to create an image and create some colors for the image. I simply made red, green and blue as follows:

$image = imagecreatetruecolor(100, 100);
$color1 = imagecolorallocate($image, 255, 0, 0);
$color2 = imagecolorallocate($image, 0, 255, 0);
$color3 = imagecolorallocate($image, 0, 0, 255);

We're going to use this image for all of our tests, and we can imagepng it to a file to see how it looks.

Image Coordinates

The final thing to discuss briefly before we play with images is the coordinate system, or how points are represented.

In PHP GD, the top-left corner of an image is the coordinate (0, 0) ($x, $y). Going right, the $x value increases, going down the $y value increases. The bottom-right corner of our 100, 100 image will be (99, 99).

Coloring a single pixel

Before we draw shapes, let's learn how to draw a single pixel. (A pixel is just a point in the image.)

The PHP GD API has two functions we might care about here:

  • imagesetpixel: alters the color of a single pixel on the image;
  • imagecolorat: gets the color of a single pixel on the image;

If we wanted to set the middle-pixel in our 100, 100 image red, we would do something like the following:

imagesetpixel($image, 50, 50, $color1);

Drawing Shapes: Rectangles

The first, basic function to discuss is imagerectangle, which simply draws a rectangle shape on an image.

The function has 6 parameters: the first is the $image, the next two are the first corner of the rectangle ($x, and $y), the next two are the second corner of the rectangle ($x, $y), the last parameter is the color.

As an example, the following draws a red rectangle from the top-left corner of the image to the middle of the image:

imagerectangle($image, 0, 0, 50, 50, $color1);

In addition to imagerectangle, there is also an imagefilledrectangle which does the same, but fills the inside of the rectangle with the color as well. The previous function only draws the outline of a rectangle. If we wanted the same red rectangle, but wanted it filled internally, we would just use imagefilledrectangle instead:

imagefilledrectangle($image, 0, 0, 50, 50, $color1);

Drawing Shapes: Ellipses

Next, we can look at drawing ellipses / ovals. Like rectangle,s there are two functions. One draws a hollow ellipse, the other draws a solid ellipse.

To draw an ellipse, need to know three things: where is the center, how "wide" is it, how "tall" is it.

We then use the imageellipse function like the imagerectangle one:

imageellipse($image, 50, 50, 25, 25, $color1);

That draws a red ellipse at the center of our image spanning 25 pixels across and 25 pixels high, aka a circle with a radius of 12.5 pixels centered in our image.

To fill it, we use the imagefilledellipse function the same way:

imagefilledellipse($image, 50, 50, 25, 25, $color1);

Drawing Shapes: Polygons

Along with rectangles and ellipses, PHP GD also has the ability to draw polygons, or irregular / free-form shapes. As you may have guessed by now, we will start with the function to draw a hollow polygon:

imagepolygon($image, $points, size($points) / 2, $color1);

Unlikes the rectangle and ellipses functions, this one takes an array of points and an integer which is the number of points in the array. The points array is an array of each $x and $y coordinate of all the points.

The $points array is defined rather simply:

$points = [
    10, 10,
    10, 90,
    90, 90,
    90, 10

This defines a rectangle originating at (10, 10) in our image, moving to (10, 90), then (90, 90), then (90, 10). The shape will be closed by drawing a line from the last point to the first, which is convenient because that finishes our rectangle.

As expected, there is also a function to draw a filled polygon:

imagefilledpolygon($image, $points, size($points) / 2, $color1);

Drawing Shapes: Arcs

This next shape is a bit interesting: the arc.

An arc is just a curved line, but trying to draw one can be a bit complicated. In PHP, we solve this by having three main components of an arc:

  1. The center ($x, $y) of the arc;
  2. The size ($width, $height) of the arc;
  3. The sweep angle ($start, $end) of the arc;

The sweep angle of an arc is a value of 0 to 360, and represents the angle, in degress, of that position. The sweep angles need not be in order of low-to-high, as the arc drawing will start from the $start angle in the circle, and move clockwise to the $end angle of the circle.

Additionally, the 0 degree angle is the "three-o-clock" position, or due-right from the center, and as the angle increases it moves clockwise, to 360 being the same position again.

To imagine how an arc is drawn, imagine we begin to draw an ellipse with the center and size, then we only actually drew the angle from the start to end positions.

We draw an arc with the imagearc function, as follows:

imagearc($image, 50, 50, 50, 50, 0, 120, $color1);

This draws a red arc oriented around the center of our screen, with a radius of 25, beginning from angle 0 (the three-o-clock position) and ending at angle 120 (the seven-o-clock position).

As you might expect, there is also an imagefilledarc function, but it has an additional parameter after the $color that we must provide, which is the "style" of arc.

Because there are many ways we can close an arc, PHP defines several styles:

  1. IMG_ARC_PIE: this fills the arc by drawing lines to the center of the arc radius;
  2. IMG_ARC_CHORD: this closes and fills the arc by drawing lines to the center, and drawing a straight line between the arc ends, then discarding the curved portion of the arc;
  3. IMG_ARC_EDGED: this closes and fills the arc by drawing lines to the center of the arc radius;
  4. IMG_ARC_NOFILL: this only closes the arc when combined with any of the above, and does not fill the center of the shape;

It may seem unintuitive, but the IMG_ARC_NOFILL actually makes a lot of sense when you start drawing with IMG_ARC_CHORD or IMG_ARC_EDGED, as both of those "close" the polygon, whereas IMG_ARC_PIE only fills the inner area. I recommend experimenting with them, I've dropped a few different combinations below:

imagefilledarc($image, 25, 25, 50, 50, 0, 120, $color1, IMG_ARC_PIE);
imagefilledarc($image, 25, 25, 50, 50, 120, 240, $color2, IMG_ARC_CHORD);
imagefilledarc($image, 25, 25, 50, 50, 240, 360, $color3, IMG_ARC_EDGED);
imagefilledarc($image, 25, 75, 50, 50, 0, 120, $color1, IMG_ARC_PIE | IMG_ARC_NOFILL);
imagefilledarc($image, 25, 75, 50, 50, 120, 240, $color2, IMG_ARC_CHORD | IMG_ARC_NOFILL);
imagefilledarc($image, 25, 75, 50, 50, 240, 360, $color3, IMG_ARC_EDGED | IMG_ARC_NOFILL);
imagefilledarc($image, 75, 75, 50, 50, 0, 120, $color1, IMG_ARC_PIE | IMG_ARC_EDGED | IMG_ARC_NOFILL);
imagefilledarc($image, 75, 75, 50, 50, 120, 240, $color2, IMG_ARC_CHORD | IMG_ARC_EDGED | IMG_ARC_NOFILL);

These combinations can be drawn on our (100, 100) image, and show how the different arc filling techniques can have interesting effects.

Filling Regions

The next thing to talk about is 'filling' an image.

PHP uses a technique called "flood fill" to fill regions with certain colors. This allows you to specify a starting point, then PHP will start replacing the color it finds at that point in the image with the provided color, working adjacent pixels until the entire contiguous region is filled.

For example, the following will draw a red rectangle, then fill the inside of the rectangle with green:

imagerectangle($image, 25, 25, 75, 75, $color1);
imagefill($image, 50, 50, $color2);

There is also imagefilltoborder, which takes a border color as the first color argument, and will fill any color until it reaches the border color.

As an example, the following draws our red/green square, then fills the entire square with blue, as we set our $border_color to the RGB(0, 0, 0) background color:

$background = imagecolorallocate($image, 0, 0, 0);
imagerectangle($image, 25, 25, 75, 75, $color1);
imagefill($image, 50, 50, $color2);
imagefilltoborder($image, 50, 50, $background, $color3);

In Conclusion

We're going to stop here, because we've reached my target character limit. We still have a couple more GD items to cover, as GD is a huge API surface. We'll be wrapping the main points of GD up in the next article, and then doing some more object-oriented programming, including defining classes that handle a lot of our GD work.

I know I ended this post rather abruptly, and it didn't flow quite as well as my normal writing does...there are a bunch of reasons for that, but the root is that I'm in a mental rut right now. Our society (at least, here in the U.S.) has always been a bit of a travesty, but lately we're seeing that our society truly is as deplorable, racist, sexist, homophobic, xenophobic and downright disgusting as it's been made out to be. For a while I lived my life thinking we were "the greatest country", but lately I've realized we're not even close.

I'm saying all this because it's important that we acknowledge that, as a society, we have a lot of work to do. I truly hope more people can open their eyes and see the mistakes we've made, and work to correct them. We truly can change things if we work for it, but we all have to work for it. We can't give up...

With that said, please keep safe, and help us beat COVID-19 and the systemic injustice and failings of our "Justice" system. #BlackLivesMatter