Images and Attachments


Lets start with the most simple thing, which is needed in almost every MMBase installation. Images are in MMBase just another form of content, so they can be stored in a builder (a.k.a. 'node manager'). This builder is named 'images' in the MMBase distribution, and can be installed by deploying the resources' application. Normally the image itself will be stored as a blob in the database, though mmbase can be configured to do it differently. Of course normally the image-builder will also feature the meta information about the image.

But there is more to it then this. There must e.g. be a way to present the image to the visitor of your web site. For the meta information about the image this is of course no problem, you can do that just as you would with other mmbase node fields. If you use the mmbase taglib you would for example list the related images like this:

<mm:relatednodes type="images">
   <img src="????" alt="<mm:field name="title" />" /><mm:field name="description" /><br />
</mm:relatednodes>

As you know, you cannot use the image blob on you HTML page, but you need an URL which presents it. So that is why in the previous example I just typed '????'. Let's explain now how this issue is solved in MMBase, how MMBase can provide this '????'.

The answer is that we have created a servlet for you to do this. This servlet takes a node-number as its argument. It can then retrieve the node from MMBase and searches for a field 'handle' in this node, and the content of this is used to response the http request. Other fields of the node, such as 'itype' and 'title' are used to decorate the http response with the right headers, such as the content-type (which for an image is something else then for an HTML-page) and the content-disposition header (to supply a nice suggestion for a file name).

In 'web.xml' it is configured which URLs correspond to this servlet. The suggestion of the distro is '/img.db' which means that then the image of node 123 is available on the url: http://yourhost/context/img.db?123. I like to map the image servlet to "/images/*", and then the image 123 is available on http://yourhost/context/images/123, which I find to look a bit better. 'yourhost' is the name of your webserver and 'context' is the application context you have started mmbase in (it can be empty, then mmbase is running in the 'root' context, but this is not generally true).

Well, you know that you do not need to know explicitly the hostname of your server when you make your html page, because you can refer to the image relatively in the 'img' tag. It is also not very convenient to use an url like <img src="/context/images/123" /> because 'context' can change (you can move the page to another mmbase instance in another context), and even the 'images/' part can vary between mmbase installations, because it can be configured to which URL the image-servlet is mapped by the application server.

That's why in MMBase there are functions to retrieve this information for you automatically. If you use the MMBase Taglib there is the 'image' tag for this:

<mm:relatednodes type="images">
   <img src="<mm:image />" alt="<mm:field name="title" />" /><mm:field name="description" /><br />
</mm:relatednodes>
So, this image tag finds out for you in which context your mmbase is running and to which URL's the servlet is mapped and it then produces the right URL.

If you do not use the MMBase taglib, then the same thing can be done. Here is an example using the 'bridge'.

NodeListIterator i = node.getRelatedNodes("images").nodeListIterator();
while(i.hasNext()) {
  Node image = i.nextNode();
  out.println("<img src=\"" + image.getFunctionValue("servletpath", null) + image getNumber() + "\"
      alt=\"" + image.getStringValue("title") + "\"/>" + image.getStringValue("description") +
      "/><br />");
}
This does about the same as the above taglib example.

Note

The taglib example is really a bit more advanced. For example it tries to add user information to the URL if necessary, and it tries to put a file name in the URL if that is possible for the servlet (which helps some browsers). I advice to use the image-tag if you can.

As mentioned, images can be converted to other images. This is a very useful feature, because you often need smaller versions of an image, or perhaps a version of the image which is re-styled in another way to fit in the look and feel of your web site. These things can be automated by MMBase to a large extend, which makes the life for content editors easier, because for images it suffices to provide one (high quality) image, and MMBase can handle the conversion of this image to versions needed on the web site.

Converted images are stored in a special builder named 'icaches' (cached images), so they are much the same as the source images, the only difference being that they are automatically generated.

So for the image servlet is does not make much difference if it has to serve a 'cached' image or an 'original' image.

But how does MMBase decide which 'icache' nodes must be created, and how can you know which are available, and to which original image they belong?

The answer is that there is a function in the images builder which accepts 'conversion commands', and returns the node number of the 'icache' node which is associated with this original image and those commands. If such a node cannot be found, it will be created.

The 'conversion commands' are passed in a string referred to as 'template'. This string contains the commands separated by the + character. The syntax of the individual commands is very similar to the command line options of the 'convert' command of ImageMagick, because that program is commonly plugged in to perform the actual conversion.

A very simple example of such a conversion template is "geometry(100x200)", which is the command to resize the image to fit into a rectangle of 100 x 200 pixels. So, the number of the icache node which is a conversion by this template of the image presented by the Node 'image' can be requested from the bridge like this:

Node image;
...
List arguments = new ArrayList();
argument.add("geometry(100x200)");
int iCacheNodeNumber = image.getFunctionValue("cache", arguments).intValue();
Of course this node number can then be feed to the image servlet, on precisely the same way as you would do for a normal image.

In the MMBase taglib this functionality is also present in the before-mentioned image tag, and can be triggered by using the 'template' attribute. Showing the '100x200' version of the related images therefore would look like this:

<mm:relatednodes type="images">
   <img src="<mm:image template="geometry(100x200)" />" alt="<mm:field name="title" />" /><mm:field name="description" /><br />
</mm:relatednodes>

Note

MMBase provides an abbreviation for this vastly used command 'geometry' which is simply 's' (for size), so normally you would encounter:

   <img src="<mm:image template="s(100x200)" />" alt="<mm:field name="title" />" /><mm:field name="description" /><br />
Which is precisely the same, only shorter.

Lets give also an example of a template which consists of more than one command, e.g. a 'size' command plus a rotate command:

<mm:image template="s(100x200)+r(90)" />
The order of the commands can be significant, and you can supply the same command more then once.

TODO: overview of MMBase specific commands. Fonts and Texts. JAI implementation.

We refer to the documentation of ImageMagick for a complete description of all commands. Also in the image tag entry of the MMBase taglib reference guide there are given some examples.


This is part of the MMBase documentation.

For questions and remarks about this documentation mail to: documentation@mmbase.org