The ThumbnailImage Class

In the following sections, you'll examine the entire ThumbnailImage class, interspersing the code with comments.

Data Members

As always, the data members are private. The variable $image holds the actual thumbnail image itself.

    private $image;
    private $quality = 100;
    private $mimetype;
    private $imageproperties = array();
    private $initialfilesize;

Since, in some cases, you may want to vary the quality of the thumbnail, you create the attribute $quality. For very large files (large in terms of byte count rather than just dimensions), you may need to reduce the quality of an image as well as its size. Give $quality a default value of 100 to indicate no reduction in quality, because in most cases, you will retain the quality of the original image.


Note:

The assignment of a value to $quality shows that data members may be initialized upon declaration, but they must be initialized with constant values. You could not, for instance, invoke a PHP function call or a method.


If you are going to output an image, you need to know whether it's a .jpeg,.gif, or .png file, hence the need for a MIME type attribute. Finally, add $imageproperties, principally to capture the dimensions of the original image. Initialize it as an array (although there is no requirement to do so), because doing so is a nice way to document the data type of this variable.


Note:

Knowing the MIME type makes it easier for the browser to display an image.


Deconstructing the Constructor

As you saw in Chapter 5, the constructor is a magic method that begins with a double underscore and is invoked whenever a new instance of a class is created. The constructor for the ThumbnailImage class is shown in Listing 6-1.

Listing 6-1. The constructor for the ThumbnailImage class
public function❺ __construct($file, $thumbnailsize = 100 ){
    //check file
    ❶is_file($file) or die ("File: $file doesn't exist.");
    $this->initialfilesize = filesize($file);
    $this->imageproperties = getimagesize($file) or die ("Incorrect file_ type.");
    // new function image_type_to_mime_type
    $this->mimetype = ❷image_type_to_mime_type($this->imageproperties[2]);
    //create image
    switch($this->imageproperties[2]){
        case IMAGETYPE_JPEG:
            $this->image = ❸imagecreatefromJPEG($file);
            break;
        case IMAGETYPE_GIF:
            $this->image = imagecreatefromGIF($file);
            break;
        case IMAGETYPE_PNG:
            $this->image = imagecreatefromPNG($file);
            break;
        default:
            die("Couldn't create image.");
    }
    ❹$this->createThumb($thumbnailsize);
}

The code first checks that ❶ the $file passed in is legitimate, and, if so, it retrieves the properties of the image. In addition to file dimensions, the built-in PHP function filesize returns a constant integer that indicates the file's MIME type. This PHP constant can be converted to a string value by using ❷ the image_type_to_mime_type function.


Note:

This function is new to PHP 5, so if you are working in PHP 4, the code needs to be different. This work has been done for you. Download the version 4 files of Chapter 6 to see how the same results are achieved by looking at file extensions. Knowing the MIME type will be necessary when you want to output your image.


The appropriate, image-specific imagecreatefrom function (❸) is called and a resource is returned. The actual thumbnail is created by manipulating this resource in ❹ the createThumb method.

Two parameters are passed to ❺ the constructor. The parameter $file is required; $thumbnailsize is optional because it has a default value. The $file variable tells your class where to find the image that is to be reduced, and $thumbnailsize indicates the dimension that it will be reduced to.

Two Ways to Construct an Object

When discussing constructors in Chapter 5, you saw how default values can be assigned to parameters, thus providing flexibility and improving ease of use. The assignment of the value 100 to the variable $thumbnailsize means that the default size of your thumbnail will be 100 pixels.

Because this variable has a default value, you can create a class instance in two different ways. To accept the default thumbnail size, create an object like so:

$thumb = new ThumbnailImage("graphics/My_Picture.jpg");

In this case, the maximum dimension of the thumbnail will be the default value.

To construct a thumbnail of different dimensions, do the following:

$thumb = new ThumbnailImage("graphics/My_Picture.jpg", 250);

Assigning a default value to an argument to the constructor is simply a convenience for users of your class.


Note:

When assigning default values to arguments to a method, you may have as many default values as you wish. However, arguments without a default value should not follow those that have a default value; in this particular class, the $path variable should not follow the $thumbnailsize variable.


Internal Behavior—Private Methods

So far you have seen only private data members, but here you encounter your first private method. Private methods relate to the internal workings of a class and can be invoked only from within the class itself. The method that performs the image reduction (see Listing 6-2) is a private method—createThumb—called from within the constructor.

Listing 6-2. The createThumb method
private function createThumb($thumbnailsize){
    //array elements for width and height
    $srcW = $this->imageproperties[0];
    $srcH = $this->imageproperties[1];
    //only adjust if larger than max
    if($srcW > $thumbnailsize || $srcH ❶> $thumbnailsize){
        $reduction = $this->calculateReduction($thumbnailsize);
        //get proportions
        $desW = $srcW/$reduction;
        $desH = $srcH/$reduction;
        $copy = imagecreatetruecolor($desW, $desH);
        imagecopyresampled($copy,$this->image,0,0,0,0,$desW, $desH, $srcW,
$srcH)  or die ("Image copy failed.");
        //destroy original
        imagedestroy($this->image);
        ❷$this->image = $copy;
    }
}

In this listing, createThumb checks the width and height of the image to determine whether ❶ it is greater than the targeted size. If it is, the method creates a reduced copy and ❷ overwrites the original image with the copy.

This private method for image reduction is called from the constructor and may only be invoked from within the class. By calling it from within the constructor, it need not be called directly, and the client programmer benefits by having a fully-formed and usable object immediately upon construction.

Must It Be Private?

Suppose for a moment, though, that your intention was to make a number of different-sized reductions of the same image, just as a photographer often makes different-sized copies of the same picture. In this case, it might make sense to save the original image and make the createThumb method public. As such, an image could be recreated at different sizes by repeatedly calling this method and passing the method different values.

In fact, with minimal change to the code and the interface, you could make your class accommodate this scenario and still fulfill its original intention.

A Helper Method

From within the createThumb method, you call another private method, calculateReduction, shown in Listing 6-3.

Listing 6-3. The calculateReduction method
private function calculateReduction($thumbnailsize){
    $srcW = $this->imageproperties[0];
    $srcH = $this->imageproperties[1];
    //adjust
    if($srcW < $srcH){
          $reduction = round($srcH/$thumbnailsize);
    }else{
          $reduction = round($srcW/$thumbnailsize);
    }
    return $reduction;
}

The calculateReduction method determines whether the height or width of the image is larger and then calculates the percentage reduction based on the targeted thumbnail size. In other words, it determines whether the image's orientation is landscape or portrait and reduces the image on the appropriate dimension.


Note:

Unlike the createThumb method, the calculateReduction method is inherently private. It is a helper method that returns the percentage reduction to the createThumb method.


Public Methods

Following the constructor is another public method with the name __destruct. This method is known as a destructor. The double underscore (__) in front of the function name indicates that this method, like the constructor, is another magic method. Again, it is a method newly introduced in PHP 5. (Recall from Chapter 5 that magic methods happen in the background, like magic.)

public function __destruct(){
    if(isset($this->image)){
        imagedestroy($this->image);
    }
}

While the use of destructors is new with PHP 5, anyone familiar with other OO languages has probably already come across them. As its name suggests, a destructor is the opposite of a constructor. A constructor initializes an object, while a destructor frees up resources that a class may have allocated. Generally, PHP does a good job of cleaning up after itself so destructors are often not strictly necessary. It's used here to ensure that the image resource is disposed of.

Garbage Collection

Like Java, PHP employs a garbage collector to automatically clean up resources. Because the programmer is not responsible for allocating and freeing memory (as he is in a language like C++, for example), an automated program must free up resources. The garbage collector determines when objects are no longer used and then disposes of them, for example, when they go out of scope. However, using destructors can act as a cue that speeds up garbage collection. In the case of the ThumbnailImage class, the destructor disposes of the reduced image copy by calling the imagedestroy function.

You can call the destructor directly but, as with other magic methods the destructor is designed to be invoked in the background without any intervention by the programmer.

Displaying the Image

Next to the constructor, getImage (see Listing 6-4) is the most important method in the ThumbnailImage class, because it actually sends a reduced image to the browser. Its logic is simple: A header is sent to the browser announcing what to expect, followed by the appropriate content.

Listing 6-4. The getImage method
public function getImage(){
    header("Content-type: $this->mimetype");
    switch($this->imageproperties[2]){
        case IMAGETYPE_JPEG:
            imagejpeg($this->image, "", ❶$this->quality);
            break;
        case IMAGETYPE_GIF:
            imagegif($this->image);
            break;
        case IMAGETYPE_PNG:
            imagepng($this->image, "", ❶$this->quality);
            break;
        default:
            die("Couldn't create image.");
    }
}

Because.png and .jpeg image types support a reduction in quality, ❶ the quality argument is included when the images are output. The proper MIME type is sent to the browser first, and subsequently the image is sent in binary format.

Get and Set Methods

Chapter 5 introduced the concept of private data members and discussed how they create a need for accessor methods (also referred to as get and set methods), which retrieve and change the value of data members. The getMimeType method retrieves the MIME type of your thumbnail image. (Recall that the value returned is a copy and not the original.)

public function getMimeType(){
    return $this->mimetype;
}

You need to retrieve the value of the private variable mimetype when you display your thumbnail. Merely retrieving the MIME type can do no harm, but the same cannot be said of setting this value. The MIME type is set in the constructor by looking at an image's properties. Since this information can be determined programmatically and since an image's MIME type does not change, there is no need to set this value. Hence, there is no set method to match the get method. To say the same thing in another way, $mimetype is a read-only value and having only a get method contributes to data protection.

Image Quality

On the other hand, it makes sense to have both a set and get method for image quality. The quality property of a ThumbnailImage object is quite different from an image's MIME type and is not something that must remain fixed. In fact, getting and setting the quality of an image is one of the requirements that you set out to achieve when you designed this class. Let's first look at the method that sets image quality in Listing 6-5.

Listing 6-5. The setQuality method
public function setQuality($quality){
    if❶($quality > 100 || $quality  <  1){
        $quality = 75;
         ❷if($this->imageproperties[2] == IMAGETYPE_JPEG || $this->imageproperties[2]
== IMAGETYPE_PNG){
    $this->quality = $quality;
    }
}

As you can see in this listing, ❶ negative values and values greater than 100 are prohibited because they are not valid values for image quality. Furthermore, .gif images don't support alterations of the image quality, so ❷ the second if statement checks for the appropriate image type before changing the quality. A set method is superior to direct access to an object's properties because values can be tested and rejected, if need be, before they are assigned. A set method allows you to restrict how the variable quality is changed by screening out illegal values.

While the need to control the way in which object properties are changed is somewhat obvious, retrieving object properties through an accessor method is also superior to directly accessing a public data member. Because you can't alter the quality of a GIF, there is no need to retrieve it, and the getQuality method (see Listing 6-6) reflects this.

Listing 6-6. The getQuality method
public function getQuality(){
    $quality = null;
    if($this->imageproperties[2] == ❶IMAGETYPE_JPEG || $this->imageproperties[2] ==
IMAGETYPE_PNG){
        $quality = $this->quality;
    }
    return $quality;
}

Just as the setQuality method restricted changes to the quality of a .gif image, the getQuality method only returns a legitimate value if ❶ the image is a .jpeg or .png. Otherwise, null is returned.

Accessor methods are superior to direct access to public data members because they restrict how a variable is changed and how it is retrieved. They help ensure the integrity of your data and the functionality of the class as a whole. Get and set methods allow you to ignore the fact that .gif images don't support a quality attribute in a way that unfettered public access cannot.

When to Change the Quality

In order to determine if the quality of an image needs reducing, it's helpful to know a bit more about the image. The getInitialFileSize function returns the image's original size in bytes. This information helps you decide whether to reduce the quality of an image and, if so, by how much.

public function getInitialFileSize(){
    return $this->initialfilesize;
}

The code in this chapter doesn't actually call this method, but you can imagine the circumstances in which it might be useful.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.154.151