modperl-dynamic_image_generation

This is part of The Pile, a partial archive of some open source mailing lists and newsgroups.



Date: Wed, 8 May 2002 01:42:42 -0700
From: Michael A Nachbaur <mike@nachbaur.com>
To: modperl@apache.org
Subject: [RFC] Dynamic image generator handler

This is an request for comments.  If you don't care about dynamic image
generation with mod_perl, or don't care about offering or reading about
suggestions, you can safely ignore this.  Also, be forewarned, this was
written in StarOffice, and then copied/pasted into my email program, and
hand tweaked, so some things may not have made the transition properly.

Dynamic Image Manipulator
 -------------------------

*) Overview

This is a mod_perl handler, not directly tied in with my content
management system, but is/will be used extensively by it. The premise is
to dynamically generate images, cache them, and present them to browser
clients. The URI, as well as Apache configuration directives, is used to
determine what is to be generated.

*) Basic Uses

The most basic uses of this application will to dynamically generate TTF
text for titles, buttons, sidebars, etc. The current version of this
code does this, and quite well. Foreground and background colors, font
name (with bold/italic support), font size, image size (or automatically
detected based on the size of the text), and rotation.

The basic text support could be extended to allow for images to be
overlayed on the text (or placed under the text), or stretch images
similarly to how Enlightenment displays window manager themes.

Other uses planned would be to manipulate existing images. For instance,
if an image on a website needs a thumbnail, medium size and full-size
view, normally a person must make all versions by hand. If any
formatting needs to be done, like borders or drop-shadows, this
increases complexity. If a person could just drop an image in a
directory, and link to that image, the image could automatically be
resized, borders added, drop shadows put in place. The resulting image
would then be cached, and outputted.

*) URI Arguments

Information about what is to be done is passed through the URI. This
works for simple tasks like text display, but if anything more
complicated is to be done, external configuration files must be used.
We'll get to that in a bit.

Essentially, arguments are passed using the PATH_INFO HTTP header. We
want the browser to think this is an actual file, instead of a
dynamically generated image, so that the browser is more inclined to
cache the content. So, a typical query would be:

  http://localhost/genText/font=ArialBold;size=24;fgcolor=#ffffff;
  bgcolor=#000000;rotate=90;text=This+Is+The+Text

Resizing an image could be accomplished by doing:

  http://localhost/genImage/source=/images/ducks.jpg;scale-ratio=1:1;
  width=120;height=80;border-size:1px;border-color:#000000;
  shadow-color:#000000;shadow-angle:270;shadow-distance:5px

This would resize an image to the indicated width/height. The
"scale-ratio" argument would limit the width/height ratio, so the
maximum dimension would be used. The other attributes are obvious.

*) Configuration Files
Lets assume that we are going to scale an image, add borders to it which
consist of other images, and add text captions over the image. This
would result in such a long URI, that browsers would probably truncate
it. In addition, providing direct access to the browser opens up
possibilities for DoS attacks. Therefore, a configuration file should be
used. The config file must be flexible enough to allow a web page to
provide various input, but have certain defaults set, and restricted.

The proposed solution would be to have a config file that has preset
default templates that the input arguments augment. For instance:

<genimage>
  <preset name="thumbnail-image">
    <image>
      <style> 
        border-style: solid;
        border-color: #000000;
        border-width: 1px;
        shadow-distance: 5px;
        shadow-angle: 270; <!-- or something like 1.2rad -->
        shadow-color: #000000;
      </style>
      <content name="src"/>
    </image>
    <image>
      <style href="/css/watermark.css"/>
      <!-- The above-referenced file has the following contents:
        opacity: 80%;
        position: top;
      -->
      <content>/images/watermark.gif</content>
    </image>
    <text>
      <style>
        font-face: Arial;
        font-size: 10px;
        color: #000000;
        border-style: solid;
        border-color: #ffffff;
        opacity: 80%;
        text-align: right;
      </style>
      <content>Copyright &copy; 2002 Foo Bar Industries</content>
    </text>
    <text>
      <style>
        font-face: Arial;
        font-size: 14px;
        color: #ffffff;
        text-align: left;
        position: top;
      </style>
      <content name="date"/>
    </text>
  </preset>
</genimage>

As you can see, the above configuration file uses CSS. It makes sense to
leverage that, although I'm not certain how difficult it would be to
interface with CSS files. As far as I know, there are Perl CSS parsers,
but I have yet to use them. The configuration for a preset config
template would be layered, so the earlier the definition, the lower the
layer is. The real important part here, is the "name" attribute of any
element, as this identifies where input can be indicated. The above
preset could be used by invoking the following URI.

  http://localhost/genImage/preset=thumbnail-image;src=/images/ducks.jpg

As you can see, the preset is invoked by passing it's name as an
attribute, and any element that has a name attribute, it's value can be
provided on the URI. If an element has both a value and a name
attribute, the value in the config file can be used as a default.

*) Caching Schemes

A caching scheme similar to AxKit could be used. The current module
takes all the input arguments, sorts them (including all values that are
not provided, for completeness), and takes it's MD5 checksum. That
becomes the image's filename on the system. It is placed in a temporary
directory, and any further requests to that same URI, the file is pulled
from the filesystem without regenerating the image. Further, the code
has been blatantly ripped off from AxKit, which separates the directory
into two sub-levels, to prevent performance problems of having too many
files in one directory.

Note: To prevent the filesystem from filling up, due to DoS attacks, it
may be prudent to have a cron job periodically cull files that have the
oldest access time.

*) Image Manipulation Modules

My current code uses GD for text writing, and I'm quite happy with it.
It is extremely fast, and creates nice text output when compiled with a
TTF font engine. Looking forward however, it may not be as desirable if
things like drop shadows is to be done. GD can work with multiple
images, can resize them, etc, but the advanced features are still
unknown.

*) File Expiration Headers and Browser Caching

With my current code, it seems that browsers are reluctant to cache
these dynamically generated images. I have passed Expires: headers to
tell the browser to cache file file for a long period of time (2+
weeks), but I have been unsuccessful. I know the caching headers are
complex, and needs more than one simple header, but fixing this has
moved to the back-burner of my project. However, if more complicated
processing is to be done, and with more images, it will be crucial to
make browsers cache these images.

*) Current and Future Uses

Currently, the few production sites I have running my TTF text image
code, perform quite well, if a little slow on loading toolbar images and
the like; this should be improved with proper HTTP caching headers. It
has proven very convenient. I build sites for customers using XML and
XSL, with an XML configuration file describing the "sitemap" layout.
This way, a document can have a tag indicating which sitemap location it
occupies, and breadcrumb trails, sidebar sitemap trees, title bar text
and page titles all can be displayed without any per-page editing. The
addition of the TTF image code is wonderful, because now I can even have
section titles, often placed in toolbars or headers, generated
dynamically.

I have recently released version 1.0 of an all-XML content management
system (although it is not yet available for public use...sorry), and
this means people can edit their entire site, not just plain text. They
can completely change their sitemap structure interactively, and all
site images relating to the sitemap automagically change.

Looking forward, I would like to be able to use this for more than just
text. I'd like my customers to be able to select an image, set the
maximum size, check a few boxes or radio buttons to say what formatting
options they'd like, and the image is automagically resized without
wasting disk space or taking a long time to download. It also saves me,
as a web developer, from having to mess around with adding borders, drop
shadows, and other menial changes to an image every time the customer
gets it into their head to add a new picture.

I'm sure there are plenty of other uses for this, but I'll leave it at
this.

I have another, similar image module, which generates web-based graphs
using the same sort of URI structure, but it is severely limited. It is
a component of my content management system used to show a user how much
space of their quota is used (3D pie chart).

*) Summary

I have to make some subtle feature additions to this code within the
next few weeks (months?), and instead of just performing a knee-jerk
reaction and hacking on some cruft to my existing module, I wanted to
open this up to the mod_perl developer community as a whole, to see if
this is something others can use. If you like the idea, good for you. If
you have constructive suggestions, I'd like to hear them (no "Images
suck, use Lynx" comments please). If you would like to help, have the
time to help, and have the skills necessary, please let me know because
many eyes make all bugs shallow.


===

Date: Fri, 10 May 2002 08:32:55 +0200
From: Robert <robert@robert.cz>
To: Michael A Nachbaur <mike@nachbaur.com>
Subject: Re: [RFC] Dynamic image generator handler

Take a look at Apache::ImageMagick

- Robert

(I'm using it to generate truetype titles and thumbnails at
http://www.jalta.cz/ and it works fine)


===

Date: Fri, 10 May 2002 10:52:31 +0100 (BST)
From: Mark Fowler <mark@twoshortplanks.com>
To: Michael A Nachbaur <mike@nachbaur.com>
Subject: Re: [RFC] Dynamic image generator handler

On Wed, 8 May 2002, Michael A Nachbaur wrote:

With regard to dynamic image creation

> The most basic uses of this application will to dynamically generate TTF
> text for titles, buttons, sidebars, etc. The current version of this
> code does this, and quite well. Foreground and background colors, font
> name (with bold/italic support), font size, image size (or automatically
> detected based on the size of the text), and rotation.

I've been working on something like this using GD. Mainly I've been 
thinking about the interface which (as always) seems to the hardest thing 
to do properly.

It's not an Apache module (though it is designed with mod_perl in mind.)  
Some form of wrapping module would have to go around it.

Hmm.  How about I upload the POD so you can see what I mean.

htpp://2shortplanks.com/temp/gdti/

Note that this is a work in progress.  This code doesn't work yet (though 
previous hacky versions did.)  Yours sounds much more advanced.

> The basic text support could be extended to allow for images to be
> overlayed on the text (or placed under the text), or stretch images
> similarly to how Enlightenment displays window manager themes.

Hmm, yes.  I have it so the image can be aligned in various ways.  It's 
not quite up to stretching it yet, but we shall see.

> Other uses planned would be to manipulate existing images. For instance,
> if an image on a website needs a thumbnail, medium size and full-size
> view, normally a person must make all versions by hand. If any
> formatting needs to be done, like borders or drop-shadows, this
> increases complexity. If a person could just drop an image in a
> directory, and link to that image, the image could automatically be
> resized, borders added, drop shadows put in place. The resulting image
> would then be cached, and outputted.

Hmm, getting a little complicated here.  My program outputs a GD::Image 
object when done.  The idea is that you can then use GD to implement any 
of the things you're missing.

Also, the stages where it draws the background, the border, the text, and 
so on are all different methods.  This allows you to override these 
methods with your own ones in subclasses, so you can intercept the image 
creation at various stages and step in to do things first (e.g. draw to 
the background before the bg image is drawn)

> *) URI Arguments
> 
> Information about what is to be done is passed through the URI. This
> works for simple tasks like text display, but if anything more
> complicated is to be done, external configuration files must be used.
> We'll get to that in a bit.

I was working on several different encoding schemes that you could use on 
the URL.  Primarily these were:

 * Base64 alike encoding

 * A scheme where " " was replaced with "_" and entities could be used

Primely I'm only concerned about the text that you want rendered.  
Everything else was going to be read from a config file/set in the 
httpd.conf.

I was also planning to implement Template Toolkit plugins to allow you to 
easily create these images.

> Essentially, arguments are passed using the PATH_INFO HTTP header. We
> want the browser to think this is an actual file, instead of a
> dynamically generated image, so that the browser is more inclined to
> cache the content. So, a typical query would be:
> 
>   http://localhost/genText/font=ArialBold;size=24;fgcolor=#ffffff;
>   bgcolor=#000000;rotate=90;text=This+Is+The+Text

This is indeed a key concept.  More importantly I designed my schemes so 
that they could actually be saved to disk with that filename.  One 
possible idea would be to place the image creation in an ErrorHandler 
which returns the image and writes it to the correct location on disk.  
Thus the next time the image is called the perl code is skipped all 
together and the image is simply sucked off of the disk.  I think Randal 
did a column on something like this a while back.

> *) Configuration Files

I was thinking of using a system accessible in the httpd.conf for the 
apache module.

> The real important part here, is the "name" attribute of any
> element, as this identifies where input can be indicated.

In my scheme each location was a different font.  So:

 http://twoshortplanks.com/f/xmason/1st.jpg

Is the image "1st" in the "xmason" style. (yes, that link works)

An important aspect is that styles in my system can be created from other
styles using the ->clone() method.

So for example, to create heading2 you could use:

my $heading2 
  = $heading1->clone(text_size => ($heading1->text_size() * 0.8));

All the other attributes would stay the same (colour, background image
etc, etc.)

The configuration file should reflect that.

> *) Caching Schemes

I hadn't really considered caching systems.  Sounds good.

> Note: To prevent the filesystem from filling up, due to DoS attacks, it
> may be prudent to have a cron job periodically cull files that have the
> oldest access time.

Or have the handler do it itself after it's returned an image.  You'd also 
want the handler to keep a scoreboard of how many images have been 
generated in the last x minutes to stop generating for things like runaway
spiders (though OTOH, this could probably be better handled by another 
module somewhere else in the chain)
 
> My current code uses GD for text writing

As does mine.  TBH, the hardest thing I had was designing the interface 
and doing the maths to work out where everything goes when you've got 
several competing criteria manipulating the image.  The underlying image 
system wasn't that important.

I'd considered renaming GD::TextImage to TextImage::GD should 
TextImage::ImageMagick etc should happen.

> *) File Expiration Headers and Browser Caching

Not even considered.
 
> *) Current and Future Uses

> I have recently released version 1.0 of an all-XML content management
> system (although it is not yet available for public use...sorry), and
> this means people can edit their entire site, not just plain text. They
> can completely change their sitemap structure interactively, and all
> site images relating to the sitemap automagically change.

I was planning to do something similar with Template Toolkit and the 
XML::XPath plugin.

> Looking forward, I would like to be able to use this for more than just
> text. I'd like my customers to be able to select an image, set the
> maximum size, check a few boxes or radio buttons to say what formatting
> options they'd like, and the image is automagically resized without
> wasting disk space or taking a long time to download.

Disk space cheap, CPU cycles expensive.

> I'm sure there are plenty of other uses for this, but I'll leave it at
> this.

I'm warey of creating a all too powerful module.  It's taken me an age to 
come up with an interface that I think (IMHO) that has a sensible user 
interface.  I wouldn't want to create something too powerful.

I've left hooks in my code.  That's all I can do.

> I have to make some subtle feature additions to this code within the
> next few weeks (months?), and instead of just performing a knee-jerk
> reaction and hacking on some cruft to my existing module, I wanted to
> open this up to the mod_perl developer community as a whole, to see if
> this is something others can use.

It sounds good to me.

Later.

Mark. 

-- 
s''  Mark Fowler                                     London.pm   Bath.pm
     http://www.twoshortplanks.com/              mark@twoshortplanks.com
';use Term'Cap;$t=Tgetent Term'Cap{};print$t->Tputs(cl);for$w(split/  +/
){for(0..30){$|=print$t->Tgoto(cm,$_,$y)." $w";select$k,$k,$k,.03}$y+=2}



===

To: Michael A Nachbaur <mike@nachbaur.com>
Cc: modperl@apache.org
Subject: Re: [RFC] Dynamic image generator handler
From: merlyn@stonehenge.com (Randal L. Schwartz)
Date: 10 May 2002 06:39:47 -0700

>>>>> "Michael" == Michael A Nachbaur <mike@nachbaur.com> writes:

Michael> This is a mod_perl handler, not directly tied in with my
Michael> content management system, but is/will be used extensively by
Michael> it. The premise is to dynamically generate images, cache
Michael> them, and present them to browser clients. The URI, as well
Michael> as Apache configuration directives, is used to determine what
Michael> is to be generated.

Like <http://www.stonehenge.com/merlyn/LinuxMag/col33.html>
perhaps?  Been there, Done that.  Feel free to steal the code.


===

Date: Fri, 10 May 2002 10:46:11 -0700
From: Michael A Nachbaur <mike@nachbaur.com>
To: Robert <robert@robert.cz>
Cc: modperl@apache.org
Subject: Re: [RFC] Dynamic image generator handler

On Fri, 10 May 2002 08:32:55 +0200
Robert <robert@robert.cz> wrote:

> Take a look at Apache::ImageMagick

In my benchmarks I ran, ImageMagick was way slower than GD.  I wrote a
little test, rendering a little text image of 120x30.  With ImageMagick,
I was getting 0.3 rps, and under GD with similar circumstances I was
getting 1.5rps.  I'm sure I could've optimized the ImageMagick one a bit
further, but that quick test settled it for me.

I looked at Apache::ImageMagick last night however, and although it
seems pretty usefull, it doesn't really address what I want to do with
my module.



===

Date: Fri, 10 May 2002 11:07:31 -0700
From: Michael A Nachbaur <mike@nachbaur.com>
To: Mark Fowler <mark@twoshortplanks.com>
Cc: modperl@apache.org
Subject: Re: [RFC] Dynamic image generator handler

On Fri, 10 May 2002 10:52:31 +0100 (BST)
Mark Fowler <mark@twoshortplanks.com> wrote:
> > The basic text support could be extended to allow for images to be
> > overlayed on the text (or placed under the text), or stretch images
> > similarly to how Enlightenment displays window manager themes.
> 
> Hmm, yes.  I have it so the image can be aligned in various ways. 
> It's not quite up to stretching it yet, but we shall see.

I'm not either, all my module supports currently is text.

> > Essentially, arguments are passed using the PATH_INFO HTTP header.
> > We want the browser to think this is an actual file, instead of a
> > dynamically generated image, so that the browser is more inclined to
> > cache the content. So, a typical query would be:
> > 
> >   http://localhost/genText/font=ArialBold;size=24;fgcolor=#ffffff;
> >   bgcolor=#000000;rotate=90;text=This+Is+The+Text
> 
> This is indeed a key concept.  More importantly I designed my schemes
> so that they could actually be saved to disk with that filename.  One 
> possible idea would be to place the image creation in an ErrorHandler 
> which returns the image and writes it to the correct location on disk.
>  Thus the next time the image is called the perl code is skipped all 
> together and the image is simply sucked off of the disk.  I think
> Randal did a column on something like this a while back.

Yes, like I say in my caching section, I sort the arguments and then MD5
them, and thats the name of the file on disk. So
/tmp/Imagecache/0/1/A/098FAD9 etc.

I actually do this process in the URI Transformation phase.  I intercept
a request, check to see if the given arguments already has a cache entry
on disk, and if so, I change $r->filename() to that location on disk. 
Otherwise, I generate it, and again point to that filename...I then let
Apache serve the file.

> > *) Configuration Files
> 
> I was thinking of using a system accessible in the httpd.conf for the 
> apache module.

I want to stay away from httpd.conf-based config files.  Although great
for most things, the configuration of different image styles can be very
site-specific, so I wouldn't want to have to reboot every time someone
makes a change.  In addition to this, I would like image styles to be
editable through my Content Management System; if it's based in the
httpd.conf (or even an .htaccess file), that means I'm giving a customer
access to the control of the webserver, and that makes the hair stand up
on the back of my neck.

Rather, I could define an XML configuration file, and use a directive in
the httpd.conf (or .htaccess) to point to the relevant configuration
file for that site/location.

> > *) Caching Schemes
> 
> I hadn't really considered caching systems.  Sounds good.
> 
> > Note: To prevent the filesystem from filling up, due to DoS attacks,
> > it may be prudent to have a cron job periodically cull files that
> > have the oldest access time.
> 
> Or have the handler do it itself after it's returned an image.  You'd
> also want the handler to keep a scoreboard of how many images have
> been generated in the last x minutes to stop generating for things
> like runaway spiders (though OTOH, this could probably be better
> handled by another module somewhere else in the chain)

I'm trying to keep from tying up the httpd processes unnecessarily.  I
just want to generate an image, and then pass it off to apache as fast
as possible.  If I have to disk scan (or even maintain a scoreboard in
memory), I'm not sure how that would affect performance.  It might not
be a bad idea to add a scoreboard, but I don't want it to have to do too
much.

> > Looking forward, I would like to be able to use this for more than
> > just text. I'd like my customers to be able to select an image, set
> > the maximum size, check a few boxes or radio buttons to say what
> > formatting options they'd like, and the image is automagically
> > resized without wasting disk space or taking a long time to
> > download.
> 
> Disk space cheap, CPU cycles expensive.

Disk space cheap, CPU cycles expensive, web developer time *really*
expensive.  So, auto-generate, and load from disk cache.

> > I'm sure there are plenty of other uses for this, but I'll leave it
> > at this.
> 
> I'm warey of creating a all too powerful module.  It's taken me an age
> to come up with an interface that I think (IMHO) that has a sensible
> user interface.  I wouldn't want to create something too powerful.

Unfortunately for me, I need to add these fancy-dancy features.  The
reason I'm coming back to this module of mine is because I need to have
background images behind text, semi-transparency of multi-layered
images, and resizing/scaling of images with borders and shadows, etc.

===

Date: Fri, 10 May 2002 11:11:53 -0700
From: Michael A Nachbaur <mike@nachbaur.com>
To: merlyn@stonehenge.com (Randal L. Schwartz)
Cc: modperl@apache.org
Subject: Re: [RFC] Dynamic image generator handler

On 10 May 2002 06:39:47 -0700
merlyn@stonehenge.com (Randal L. Schwartz) wrote:

> Like <http://www.stonehenge.com/merlyn/LinuxMag/col33.html>
> perhaps?  Been there, Done that.  Feel free to steal the code.

Like that, but a bit more so.  And I'd like to avoid ImageMagick like
the plague.

===

Date: Fri, 10 May 2002 14:45:19 -0500
From: Ed <entropic@fldna.net>
To: Michael A Nachbaur <mike@nachbaur.com>
Cc: modperl@perl.apache.org
Subject: Re: [RFC] Dynamic image generator handler

On Fri, May 10, 2002 at 10:46:11AM -0700, Michael A Nachbaur wrote:
> On Fri, 10 May 2002 08:32:55 +0200
> Robert <robert@robert.cz> wrote:
> 
> > Take a look at Apache::ImageMagick
> 
> In my benchmarks I ran, ImageMagick was way slower than GD.  I wrote a
> little test, rendering a little text image of 120x30.  With ImageMagick,
> I was getting 0.3 rps, and under GD with similar circumstances I was
> getting 1.5rps.  I'm sure I could've optimized the ImageMagick one a bit
> further, but that quick test settled it for me.
> 
> I looked at Apache::ImageMagick last night however, and although it
> seems pretty usefull, it doesn't really address what I want to do with
> my module.

I'm using Imlib2 w/ the c interface (http://freshmeat.net/projects/imlib2perl/)

I needed antialias lines, alpha's etc.  I modified my app to use a 'dbi' like
interface for potentially any media driver.  The diferent 'media drivers',
gd, imlib2, *pdf/*tex etc all have different ideas how to draw a line, circle,
polygon, text, add colors etc. Now all I have to do to use diffent libraries
such as Media->new(Driver => 'imlib2'), or Media->new(Driver => 'gd'),
Media->new(Driver => 'svg'), Media->new(Driver => 'pdflib') etc.

There are may libraries out there, gd, imlib, imlib2, libart, povray, gdk,
flash, pdfAPI2, pdflib, tex, latex, svg, imager, imagemagic, ...

There are may good reasons to be able to 'just drop in' a driver ... just
look at why the unified interface 'DBI' was developed for RDBM's .

Ed

===

Date: Fri, 10 May 2002 15:50:08 -0500
From: Ed <entropic@fldna.net>
To: Michael A Nachbaur <mike@nachbaur.com>
Cc: modperl@perl.apache.org
Subject: Re: [RFC] Dynamic image generator handler

On Wed, May 08, 2002 at 01:42:42AM -0700, Michael A Nachbaur wrote:
> This is an request for comments.  If you don't care about dynamic image
> generation with mod_perl, or don't care about offering or reading about
> suggestions, you can safely ignore this.  Also, be forewarned, this was
> written in StarOffice, and then copied/pasted into my email program, and
> hand tweaked, so some things may not have made the transition properly.
> 
> Dynamic Image Manipulator
> -------------------------
> 
> *) Overview
> 
> This is a mod_perl handler, not directly tied in with my content
> management system, but is/will be used extensively by it. The premise is
> to dynamically generate images, cache them, and present them to browser
> clients. The URI, as well as Apache configuration directives, is used to
> determine what is to be generated.
> 
> *) Basic Uses
> 
> The most basic uses of this application will to dynamically generate TTF
> text for titles, buttons, sidebars, etc. The current version of this
> code does this, and quite well. Foreground and background colors, font
> name (with bold/italic support), font size, image size (or automatically
> detected based on the size of the text), and rotation.
> 
> The basic text support could be extended to allow for images to be
> overlayed on the text (or placed under the text), or stretch images
> similarly to how Enlightenment displays window manager themes.
> 
> Other uses planned would be to manipulate existing images. For instance,
> if an image on a website needs a thumbnail, medium size and full-size
> view, normally a person must make all versions by hand. If any
> formatting needs to be done, like borders or drop-shadows, this
> increases complexity. If a person could just drop an image in a
> directory, and link to that image, the image could automatically be
> resized, borders added, drop shadows put in place. The resulting image
> would then be cached, and outputted.
> 
> *) URI Arguments
> 
> Information about what is to be done is passed through the URI. This
> works for simple tasks like text display, but if anything more
> complicated is to be done, external configuration files must be used.
> We'll get to that in a bit.
> 
> Essentially, arguments are passed using the PATH_INFO HTTP header. We
> want the browser to think this is an actual file, instead of a
> dynamically generated image, so that the browser is more inclined to
> cache the content. So, a typical query would be:
> 
>   http://localhost/genText/font=ArialBold;size=24;fgcolor=#ffffff;
>   bgcolor=#000000;rotate=90;text=This+Is+The+Text
> 
> Resizing an image could be accomplished by doing:
> 
>   http://localhost/genImage/source=/images/ducks.jpg;scale-ratio=1:1;
>   width=120;height=80;border-size:1px;border-color:#000000;
>   shadow-color:#000000;shadow-angle:270;shadow-distance:5px
> 
> This would resize an image to the indicated width/height. The
> "scale-ratio" argument would limit the width/height ratio, so the
> maximum dimension would be used. The other attributes are obvious.
> 
> *) Configuration Files
> Lets assume that we are going to scale an image, add borders to it which
> consist of other images, and add text captions over the image. This
> would result in such a long URI, that browsers would probably truncate
> it. In addition, providing direct access to the browser opens up
> possibilities for DoS attacks. Therefore, a configuration file should be
> used. The config file must be flexible enough to allow a web page to
> provide various input, but have certain defaults set, and restricted.
> 
> The proposed solution would be to have a config file that has preset
> default templates that the input arguments augment. For instance:
> 
> <genimage>
>   <preset name="thumbnail-image">
>     <image>
>       <style> 
>         border-style: solid;
>         border-color: #000000;
>         border-width: 1px;
>         shadow-distance: 5px;
>         shadow-angle: 270; <!-- or something like 1.2rad -->
>         shadow-color: #000000;
>       </style>
>       <content name="src"/>
>     </image>
>     <image>
>       <style href="/css/watermark.css"/>
>       <!-- The above-referenced file has the following contents:
>         opacity: 80%;
>         position: top;
>       -->
>       <content>/images/watermark.gif</content>
>     </image>
>     <text>
>       <style>
>         font-face: Arial;
>         font-size: 10px;
>         color: #000000;
>         border-style: solid;
>         border-color: #ffffff;
>         opacity: 80%;
>         text-align: right;
>       </style>
>       <content>Copyright &copy; 2002 Foo Bar Industries</content>
>     </text>
>     <text>
>       <style>
>         font-face: Arial;
>         font-size: 14px;
>         color: #ffffff;
>         text-align: left;
>         position: top;
>       </style>
>       <content name="date"/>
>     </text>
>   </preset>
> </genimage>
> 
> As you can see, the above configuration file uses CSS. It makes sense to
> leverage that, although I'm not certain how difficult it would be to
> interface with CSS files. As far as I know, there are Perl CSS parsers,
> but I have yet to use them. The configuration for a preset config
> template would be layered, so the earlier the definition, the lower the
> layer is. The real important part here, is the "name" attribute of any
> element, as this identifies where input can be indicated. The above
> preset could be used by invoking the following URI.


I used CSS.pm for a bit but it was too fat w/ Parse::RecDecent. To unify my
app and the browser I use axkit to 'generate' the css from an xml file.

<css>
 <selector name="back">
    <color>black</color>
    <font-family>geneva</font-family>
    <font-family>arial</font-family>
    <font-size>7px</font-size>
    <background-color>white</background-color>
 </selector>
</css>

.back {
    color: black;
    font-family: geneva, arial;
    font-size: 7px;
    background-color: white;
}

Creating complicated css files are difficult but my drawing app can load its
info from the uri, an xml file, a rdbm , Config::General, inifiles or whatever
and use different output methods such as axkit's providers to parse the 
'color config' to render the *.css file to the browser.

This way the document, style, skin and images are all unified.

Graphics::ColorNames works wonderfully to help handle all the different color
needs.

> 
>   http://localhost/genImage/preset=thumbnail-image;src=/images/ducks.jpg
> 
> As you can see, the preset is invoked by passing it's name as an
> attribute, and any element that has a name attribute, it's value can be
> provided on the URI. If an element has both a value and a name
> attribute, the value in the config file can be used as a default.
> 
> *) Caching Schemes
> 
> A caching scheme similar to AxKit could be used. The current module
> takes all the input arguments, sorts them (including all values that are
> not provided, for completeness), and takes it's MD5 checksum. That
> becomes the image's filename on the system. It is placed in a temporary
> directory, and any further requests to that same URI, the file is pulled
> from the filesystem without regenerating the image. Further, the code
> has been blatantly ripped off from AxKit, which separates the directory
> into two sub-levels, to prevent performance problems of having too many
> files in one directory.
> 
> Note: To prevent the filesystem from filling up, due to DoS attacks, it
> may be prudent to have a cron job periodically cull files that have the
> oldest access time.


Cache::Cache is appropriate here ... 



> 
> *) Image Manipulation Modules
> 
> My current code uses GD for text writing, and I'm quite happy with it.
> It is extremely fast, and creates nice text output when compiled with a
> TTF font engine. Looking forward however, it may not be as desirable if
> things like drop shadows is to be done. GD can work with multiple
> images, can resize them, etc, but the advanced features are still
> unknown.
> 
> *) File Expiration Headers and Browser Caching
> 
> With my current code, it seems that browsers are reluctant to cache
> these dynamically generated images. I have passed Expires: headers to
> tell the browser to cache file file for a long period of time (2+
> weeks), but I have been unsuccessful. I know the caching headers are
> complex, and needs more than one simple header, but fixing this has
> moved to the back-burner of my project. However, if more complicated
> processing is to be done, and with more images, it will be crucial to
> make browsers cache these images.


I create a digest w/ MD5 or SHA1 for the image/pdf and use it as the filename
and the Cache::Cache key.

The cache is easily invalidated if the source image file failes a -e test.
I also use cron to delete stale image files.

The generated now static image is redirected-to or referenced in the html.  
I found that it is important to complete the  processing of the images before 
the referencing html document gets served, ... rather than having the html 
document initiate dynamic imbeded links to create the image.  Letting apache 
serve images as static image-files has proved rock solid for me 
... (note keep-alives).  There is nothing worse than to pull a page and have
to wait for each of the images to show up.

Browsers, proxies and users are all real pains to deal w/ when the uri has
a query string.  Digest's are ugly but they play much better w/ everybody.

014d1c89fc3da6e15e0069000dfa381e44239af71021057594.png

Ed



===

Date: Thu, 9 May 2002 12:39:38 -0700
From: Michael A Nachbaur <mike@nachbaur.com>
To: modperl@apache.org
Subject: [RFC] Dynamic image generator handler

This is an request for comments.  If you don't care about dynamic image
generation with mod_perl, or don't care about offering or reading about
suggestions, you can safely ignore this.  Also, be forewarned, this was
written in StarOffice, and then copied/pasted into my email program, and
hand tweaked, so some things may not have made the transition properly.

http://nachbaur.com/software/writing/rfc-imagegen.xhtml

Just a note, I originally posted a text-version of this RFC to the
mailing list (tried twice) but it never got through apparently.  I'm
guessing the mailing list blocked it since it was too big.  Anyway, if
anyone would prefer the text version, and you know why I wasn't able to
post, let me know and I'll repost it.

===

the rest of The Pile (a partial mailing list archive)

doom@kzsu.stanford.edu