Contents

Build a dynamic image

The final step in making our banner fully dynamic is to have TYPO3 generate the image itself. In TYPO3, this is done using the IMAGE cObject that we used to make the images in the previous parts of this tutorial.

As we saw in that tutorial, the principal property of the IMAGE cObject is the "file" property; we also learned that the file property's data type is "imgResource".

Screenshot from TSref
The data type of the IMAGE cObject's file property is 'imgResource'

And as we found in the TSref's Datatype reference properties with the imgResource datatype can accept a GIFBUILDER object as input.

To top

The GIFBUILDER object

The GIFBUILDER object is TYPO3's main tool for producing dynamic images. In spite of its name, GIFBUILDER can produce .gif, .jpg and .png images. Since GIFBUILDER is a very complex object, we should again start by planning the desired output—only this time, we should identify the components of the image itself, rather than the HTML markup we expect:

  • the image text
  • the image's white background
  • the grey border around the image

In addition, just to reinforce how the gettext datatype works, we'll make the image text dynamic and base it on the title of this site.

The www.typo3apprentice.com banner

To top

GIFBUILDER continued: the basics

Since we know in advance that only the contents of the file property of the IMAGE cObject will change for this version of the banner, we can simply re-use the rest of the code from an earlier example with just a few changes to the object's file property (lines 4-7):

  1. // Banner 8: Banner IMAGE cObject
  2. lib.samples.Banner_IMAGE.6 = IMAGE
  3. lib.samples.Banner_IMAGE.6 {
  4.   file = GIFBUILDER
  5.   file {
  6.     ???
  7.   }
  8.   altText = typo3apprentice.com banner image
  9.   titleText = www.typo3apprentice.com
  10.   stdWrap.typolink.parameter.data = leveluid:0
  11. }

GIFBUILDER is slightly different from other TS objects in that it has set of properties that belong to it directly—generally properties that pertain to the entire generated image—and an entire set of sub-objects that can only be used by GIFBUILDER objects. These sub-objects are used to create text, simple geometric objects and to apply image-processing effects to the whole. We'll start by creating the basic image and the border.

To top

GIFBUILDER properties

If we look over GIFBUILDER's properties on the TSref's Object Names in This Section page, it's not immediately obvious where to start. But given that we're going to build an image completely from scratch, it might be best to look for the properties we'd start with if we were using a conventional image-editing application to do the same job—in other words, we should start by looking for a way to set the image's size and background colour.

If we now return to the list of GIFBUILDER properties in the TSref, we find two properties that may fit our requirements:

  • backColor
  • XY

"backColor" seems straightforward enough—its datatype is given as "GraphicColor." Consulting the datatype reference again reveals that GIFBUILDER's "backColor" property can accept a 6-digit hexadecimal number of exactly the same sort as HTML and CSS documents. To begin with, we'll choose "#cccccc" as the value for the backColor property.

"XY" is less clear; the description ("Size of the gif-file") makes it quite clear that the property is what we're looking for, but the listed datatype—"x,y +calc"—is not listed in the datatype reference. Fortunately, the TSref's entry for XY shows the default value to be XY. So to begin with, we'll assume that the XY property expects to receive an x-dimension followed by a comma and a y-dimension where both dimensions are in pixels. Given this, we'll set the initial value of XY to 468,60—the size of our banner image.

Now that we have made preliminary decisions about what values to provide the GIFBUILDER object with, let's add them to our working code and check the output:

  1. // Banner 8: Banner GIFBUILDER image
  2. lib.samples.Banner_IMAGE.6 = IMAGE
  3. lib.samples.Banner_IMAGE.6 {
  4.   file = GIFBUILDER
  5.   file {
  6.     XY = 468,60
  7.     backColor = #cccccc
  8.   }
  9.   altText = typo3apprentice.com banner image
  10.   titleText = www.typo3apprentice.com
  11.   stdWrap.typolink.parameter.data = leveluid:0
  12. }
typo3apprentice.com banner image

It works! Of course the resulting image is not particularly interesting—it's simply a grey rectangle—but it is precisely the output we were expecting at this stage. And now that we have successfully created the image, let's move on to the next step—the use of one of GIFBUILDER's special objects.

To top

A border with 'BOX'

So far, we have managed only to create a basic image in a solid colour. Before we move on to the final and most interesting step where we use GIFBUILDER to create the image's text, we'll finish creating the 'frame' of the image.

Since GIFBUILDER's capabilities for creating raw geometric images are fairly modest, it's necessary to be a bit creative when building new images. Reviewing the list of GIFBUILDER's objects and properties, we will not find an 'outline' or 'border' object. We do, however, find an object named "BOX."

The TSref offers no description for what BOX actually does, but it seems reasonable to assume that it makes rectangles. If so, we should be able to use it to place a white rectangle 466 x 58 pixels precisely in the center of the existing grey rectangle—the effect will be of a white rectangle surrounded by a one pixel grey border.

Looking closely at the TSref, we learn that BOX has only three properties: "dimensions," "color" and "VHalign." Since we know for certain that our box will need a colour and dimensions, we'll start with those properties first.

The "Color" property has a datatype we've seen before—GraphicColor—so we can uncomplicatedly assign it the colour that we want to use for the main part of the graphic: #ffffff.

The "dimensions" property has a datatype of "x,y,w,h +calc". It turns out that +calc  isn't present in the datatype reference (though it is present in the Objects and Properties section of the TSref), but "x,y,w,h" is. The entry in the datatype is almost identical to the property's description under BOX. Apparently, this object expects four comma-separated values, where the first two indicate the offset of the top left corner of the current object from the top left corner of the parent object and where the second two values are the size of the current object.

The current object needs to be 468-2 pixels by 60-2pixels, and it needs to be offset by one pixel in the x direction and one pixel in the y direction. This gives us a value for the dimensions property of "1,1,466,58". We'll now add those values into our working code sample:

  1. // Banner 9: Banner GIFBUILDER image
  2. lib.samples.Banner_IMAGE.9 = IMAGE
  3. lib.samples.Banner_IMAGE.9 {
  4.   file = GIFBUILDER
  5.   file {
  6.     XY = 468,60
  7.     backColor = #cccccc
  8.    
  9.     5 = BOX
  10.     5 {
  11.       dimensions = 1,1,466,58
  12.       color = #ffffff
  13.     }
  14.   }
  15.   altText = typo3apprentice.com banner image
  16.   titleText = www.typo3apprentice.com
  17.   stdWrap.typolink.parameter.data = leveluid:0
  18. }

Our new code yields the following result:

typo3apprentice.com banner image

In other words, we've now achieved two out of three of our chief aims: we've created an image with a white background, and we've surrounded it with a one-pixel grey border. Now, we can move on to the most involved part of the banner—adding the text with GIFBUILDER's TEXT object.

To top

GIFBUILDER's TEXT object is not the TEXT cObject!

The single most important thing to understand about GIFBUILDER's TEXT object is that it is not the same as the TEXT cObject. A common mistake with the TEXT object in GIFBUILDER is to duplicate the syntax of a working TEXT cObject—which will not work.

The difference is in how GIFBUILDER's TEXT object and the TEXT cObject are supplied with content. The Text cObject, for example, is supplied with content either a) through its "value" property, or b) via .stdWrap properties and functions.

The GIFBUILDER TEXT object, on the other hand, is supplied with content via its 'text' property. In fact, the way the GIFBUILDER TEXT object works is more similar to the way the HTML cObject works—in that cObject, all value is supplied via the "value" property.

With the GIFBUILDER TEXT object, we can determine this using the TSref (though only by the process of elimination) by reading through the TEXT object's property list; none of the objects' property names (except .text) in any way suggests text-rendering. Moreover only the text property specifically mentions the output text string.

In theory, we ought to be able to determine this by consulting the various properties' datatypes, but in the TSref, the TEXT object's text property's datatype is given only as "stdWrap." This is correct as far as it goes, but is actually incomplete since the TEXT object's text property also accepts string input. Presumably, the TSref ought to give the text property's datatype as "string / stdWrap" or "HTML / stdWrap" as it does for the HTML object's nearly identical "value" property.

To further illustrate the subtle differences between GIFBUILDER TEXT, TEXT and HTML, the following code samples show how we could retrieve the title of a page in the website using the TEXT cObject, the HTML cObject, and the GIFBUILDER TEXT object:

Page title with TEXT cObject

  1. lib.page_title = TEXT
  2. lib.page_title {
  3.     data = page:title
  4. }

Page title with HTML cObject

  1. lib.page_title = HTML
  2. lib.page_title {
  3.     value {
  4.         data = page:title
  5.     }
  6. }

Page title with GIFBULDER TEXT object

  1. lib.page_title = GIFBUILDER
  2. lib.page_title {
  3.     XY = 468,60
  4.     backColor = #ffffff
  5.  
  6.     5 = TEXT
  7.     5 {
  8.         text {
  9.             data = page:title
  10.             align = center
  11.             offset - 0,20
  12.         }
  13.     }
  14. }

To top

Add TEXT to GIFBUILDER

The text object is involved enough that we should here repeat our strategy of listing the properties of the output we need to achieve. For our banner we need to text to have the following characteristics:

  • font: Share Monospace (the official TYPO3 font) in black, about 30px high
  • position: centered horizontally and vertically in the banner
  • text: the name of this site: www.typo3apprentice.com

Since we've already seen TS samples for retrieving the page title, let's start with the last item.

Retrieve the site title

In our content-retrieving examples above, we used the .stdWrap property ".data"—which has the datatype "getText"—to retrieve the title of the current page using the "page:title". This method, while very useful, is not appropriate in this instance since it will always retrieve the title of the current page.

But if we return to our previous examples, we'll see that we've already used at least one property that could be used to retrieve information from a page according to the page's level in the page tree: "leveluid". If we now revisit the getText section of the datatype reference, we'll find that there is also a property called "leveltitle" which returns the title of the page of a given level. Since the root page is usually at level zero, we should be able to use "leveltitle:0" in our TS.

In this case, since the root page of the website is currently called "TYPO3apprentice" but the banner is meant to read "www.typo3apprentice.com," we'll need to see we can manipulate the title using .stdWrap functions.

First of all we'll need to change the case of the page title to lower case—and for this kind of job, we should always consult the stdWrap section of the TSref. In the stdWrap section, we find that there is a a property called "case" that exists specifically for converting the case of text in TS objects.

Secondly, we need to add "www." to the beginnig of the page title and ".com" to the end. This is a perfect job for the property that stdWrap is named after: "wrap".

Between .data, .case and .wrap, we should have everything we need to create the graphic text, but there is one important factor that we should always consider when using multiple stdWrap properties: "stdWrap properties are executed in the order they appear."

This means that any time we use multiple .stdWrap properties we have to ensure that they're processed in an order that makes sense for the requirements of the current TS object. In this case, we retrieve the information with .data, change the case with .case, and finally wrap the object with .wrap. In the .stdWrap table, we find that .data is processed first, followed by .case and .wrap, so we should have no trouble. At this point, our TS code looks like this:

  1. // Banner 10: Banner GIFBUILDER image
  2. lib.samples.Banner_IMAGE.10 = IMAGE
  3. lib.samples.Banner_IMAGE.10 {
  4.   file = GIFBUILDER
  5.   file {
  6.     XY = 468,60
  7.     backColor = #cccccc
  8.    
  9.     5 = BOX
  10.     5 {
  11.       dimensions = 1,1,466,58
  12.       color = #ffffff
  13.     }
  14.    
  15.     10 = TEXT
  16.     10 {
  17.       text {
  18.         data = leveltitle:0
  19.         case = lower
  20.         wrap = www.|.com
  21.       }
  22.     }
  23.   }
  24.   altText = typo3apprentice.com banner image
  25.   titleText = www.typo3apprentice.com
  26.   stdWrap.typolink.parameter.data = leveluid:0
  27. }

Style and position the text

At this point, we're completely finished the basic banner except for the styling of the text—even though if you view the output of the code sample above, there will be no txt visible.

This is because GIFBUILDER's TEXT object includes properties used for correctly positioning the text in the overall graphic, but we haven't used them at this point, so our text is not visible. These properties, and in fact all the remaining properties of the TEXT object are quite straightforward. As there are only four of them that we'll actually need to use, we will simply list their names, the values we give them, and what they actually do:

  • align: this property is used to position the text horizontally with respect to the boundaries of the GIFBUILDER object as a whole. Datatype: align
  • offset: this property is used to position the TEXT object within the GIFBUILDER object. When used in conjunction with the align property (see above), the x-coordinate value can often be set to zero. Datatype: x,y +calc
  • fontSize: the font size in pixels; note that the results of this property can be confusing depending on the value of the configuration variable $TYPO3_CONF_VARS[GFX][TTFdpi] in localconf.php. Datatype: posint
  • fontFile: this is the path to the font file (usually .ttf) used to render the text in the gifbuilder object. Datatype: resource

In the following code sample, we set the following values:

  • align = center
  • offset = 0,39
  • fontSize = 32
  • fontFile = fileadmin/templates/typo3apprentice.com/fonts/Share-TechMono.ttf

The resulting GIFBUILDER image is shown below:

  1. // Banner 11: Banner GIFBUILDER image
  2. lib.samples.Banner_IMAGE.11 = IMAGE
  3. lib.samples.Banner_IMAGE.11 {
  4.   file = GIFBUILDER
  5.   file {
  6.     XY = 468,60
  7.     backColor = #cccccc
  8.    
  9.     5 = BOX
  10.     5 {
  11.       dimensions = 1,1,466,58
  12.       color = #ffffff
  13.     }
  14.    
  15.     10 = TEXT
  16.     10 {
  17.       text {
  18.         data = leveltitle:0
  19.         case = lower
  20.         wrap = www.|.com
  21.       }
  22.       offset = 0,39
  23.       fontFile = fileadmin/templates/typo3apprentice.com/fonts/Share-TechMono.ttf
  24.       align = center
  25.       fontSize = 32
  26.     }
  27.   }
  28.   altText = typo3apprentice.com banner image
  29.   titleText = www.typo3apprentice.com
  30.   stdWrap.typolink.parameter.data = leveluid:0
  31. }
typo3apprentice.com banner image

To top

Success! (+advanced topics)

It worked! The above image is nearly a pixel by pixel duplicate of the original Photoshop image. However, there are still a few lingering details that can be touched up with TS. Firstly, depending on the font used, GIFBUILDER images can appear slightly 'jagged'. Secondly, the alt and title text are not dynamically generated but rely on 'hardcoded' strings in the TS object itself. Finally, as a banner, our image is a bit lacklustre.

In this case, none of the issues is a severe problem; the text is of adequate quality, the alt and title attributes need not change since this image is only used in this tutorial, and we had no intention of creating a design masterpiece. But the basic elements of the solution are presented below (complete with code and output) as topics for further study:

Fix jagged text

To fix jagged GIFBUILDER text, we can create the object at double or quadruple the final size, and use GIFBUILDER's SCALE object to scale the object back to the desired size.

Make alt and title attributes dynamic

stdWrap has a very interesting and useful property called 'cObject'. This property allows the output of a cObject to be included in any TS object with stdWrap capability (i.e. with a stdWrap datatype).

Add a 'subtitle' to the image

Lastlyif we realize that the GIFBUILDER object accepts an array of GIFBUILDER objects in exactly the same way that the COA cObject accepts an array of cObjects, we can easily add another line of text to the image—see object 15 in the GIFBUILDER code below to see how.

  1. // Banner 12: Banner GIFBUILDER image--final iteration
  2. lib.samples.Banner_IMAGE.12 = IMAGE
  3. lib.samples.Banner_IMAGE.12 {
  4.   file = GIFBUILDER
  5.   file {
  6.     XY = 936,120
  7.     backColor = #cccccc
  8.    
  9.     5 = BOX
  10.     5 {
  11.       dimensions = 2,2,932,116
  12.       color = #ffffff
  13.     }
  14.    
  15.     10 = TEXT
  16.     10 {
  17.       text {
  18.         data = leveltitle:0
  19.         case = lower
  20.         wrap = www.|.com:
  21.       }
  22.       offset = 60,76
  23.       fontFile = fileadmin/templates/typo3apprentice.com/fonts/Share-TechMono.ttf
  24.       align = left
  25.       fontSize = 42
  26.     }
  27.    
  28.     15 < .10
  29.     15 {
  30.       text >
  31.       text = howto/rtfm/
  32.       offset = [10.w]+80,76
  33.       fontColor = #69a550
  34.     }
  35.    
  36.     20 = SCALE
  37.     20 {
  38.       width = 468
  39.       height = 60
  40.     }
  41.   }
  42.   titleText.stdWrap.cObject = HTML
  43.   titleText.stdWrap.cObject {
  44.     value {
  45.       data = leveltitle:0
  46.       case = lower
  47.       wrap = www.|.com
  48.     }
  49.   }
  50.   altText < .titleText
  51.   altText {
  52.     noTrimWrap = || banner image|
  53.   }
  54.   stdWrap.typolink.parameter.data = leveluid:0
  55. }
Download this file: banner_image_complete.txt
www.typo3apprentice.com banner image

To top

Contents