f41b982009-05-07Martin Stjernholm // This is a roxen module. Copyright © 1999 - 2009, Roxen IS.
2e0a351999-12-09Martin Nilsson //
37bdda1999-05-18Per Hedbor #include <module.h> inherit "module";
3b85e91999-11-15Per Hedbor constant thread_safe=1;
37bdda1999-05-18Per Hedbor  roxen.ImageCache the_cache;
0917d32013-03-04Anders Johansson constant cvs_version = "$Id$";
b3281f2000-09-10Martin Nilsson constant module_type = MODULE_TAG;
bc0fa02001-03-08Per Hedbor constant module_name = "Graphics: Image converter";
7390582000-06-01Martin Nilsson constant module_doc = "Provides the tag <tt>&lt;cimg&gt;</tt> that can be used " "to convert images between different image formats.";
2fafd22000-05-18Kenneth Johansson 
4b3fc02001-03-12Johan Sundström mapping tagdocumentation() {
7390582000-06-01Martin Nilsson  Stdio.File file=Stdio.File(); if(!file->open(__FILE__,"r")) return 0;
b996582004-06-21Martin Stjernholm  mapping doc = compile_string("#define manual\n"+file->read(), __FILE__)->tagdoc;
4b3fc02001-03-12Johan Sundström  foreach(({ "cimg", "cimg-url" }), string tag) doc[tag] += the_cache->documentation(tag + " src='/internal-roxen-testimage'");
7390582000-06-01Martin Nilsson  return doc; }
2fafd22000-05-18Kenneth Johansson 
7390582000-06-01Martin Nilsson #ifdef manual
9b03652001-03-07Kenneth Johansson constant tagdoc=(["cimg":#"<desc tag='tag'><p><short> Manipulates and converts images between different image formats.</short> Provides the tag <tag>cimg</tag> that makes it is possible to convert, resize, crop and in other ways transform
7209722012-05-09Jenny Dalenius  images. It is possible to pass attributes, such as the alt attribute, to the resulting tag by including them in the cimg tag. </p>
9b03652001-03-07Kenneth Johansson </desc>
2fafd22000-05-18Kenneth Johansson 
4b3fc02001-03-12Johan Sundström <attr name='src' value='url' required='required'><p>
9b03652001-03-07Kenneth Johansson  The path to the indata file.</p>
2fafd22000-05-18Kenneth Johansson 
4b3fc02001-03-12Johan Sundström <ex><cimg src='/internal-roxen-testimage'/></ex>
2fafd22000-05-18Kenneth Johansson </attr>
e449062008-10-29 Erik Dahl <attr name='filename' value='string'><p> Append the filename value to the path. Recommended is not to append file suffix to the filename since there are settings for handling that automatically through this module settings.
97bb932009-12-08Jonas Wallden </p><p>This is useful if you want to have images indexed, since many search engines
e449062008-10-29 Erik Dahl uses the filename as a description of the image.</p> <ex><cimg-url src='/internal-roxen-testimage' filename='Roxen Test Image'/></ex> </attr>
9b03652001-03-07Kenneth Johansson <attr name='data' value='imagedata'><p>
2fafd22000-05-18Kenneth Johansson  Insert images from other sources, e.g. databases through entities or
9b03652001-03-07Kenneth Johansson  variables.</p>
cba1fa2001-08-30Johan Sundström <ex-box><emit source='sql' query='select imagedata from images where id=37'>
79f3f12003-09-08Anders Johansson <cimg data='&sql.imagedata:none;'/>
cba1fa2001-08-30Johan Sundström </emit></ex-box>
ce011f2003-09-19Jonas Wallden </attr> <attr name='process-all-layers'><p>Set this flag to make all image layers visible regardless of their original state.</p> </attr> <attr name='include-layers' value='layer-glob-list'><p>Comma-separated list of glob expressions which is matched against layer names. All matching layers are made visible regardless of their original state.</p> </attr> <attr name='exclude-layers' value='layer-glob-list'><p>Comma-separated list of glob expressions which is matched against layer names. All matching layers are hidden regardless of their original state.</p>
922ef62005-10-06Anders Johansson </attr> <attr name='exclude-invisible-layers'><p>Set this flag to automatically exclude layers that are not shown in the original image. This is only useful in combination with the 'process-all-layers' attribute.</p> </attr>
5adc582009-11-30Henrik Grubbström (Grubba)  <h1>Timeout</h1> <p>The generated image will by default never expire, but in some circumstances it may be pertinent to limit the time the image and its associated data is kept. Its possible to set an (advisory) timeout on the image data using the following attributes.</p> <attr name='unix-time' value='number'><p> Set the base expiry time to this absolute time.</p><p> If left out, the other attributes are relative to current time.</p> </attr> <attr name='years' value='number'><p> Add this number of years to the time this entry is valid.</p> </attr> <attr name='months' value='number'><p> Add this number of months to the time this entry is valid.</p> </attr> <attr name='weeks' value='number'><p> Add this number of weeks to the time this entry is valid.</p> </attr> <attr name='days' value='number'><p> Add this number of days to the time this entry is valid.</p> </attr> <attr name='hours' value='number'><p> Add this number of hours to the time this entry is valid.</p> </attr> <attr name='beats' value='number'><p> Add this number of beats to the time this entry is valid.</p> </attr> <attr name='minutes' value='number'><p> Add this number of minutes to the time this entry is valid.</p> </attr> <attr name='seconds' value='number'><p> Add this number of seconds to the time this entry is valid.</p> </attr>
922ef62005-10-06Anders Johansson ",
2fafd22000-05-18Kenneth Johansson 
9b03652001-03-07Kenneth Johansson "cimg-url":#"<desc tag='tag'><p><short>
4b3fc02001-03-12Johan Sundström  This tag generates an URL to the manipulated picture.</short>
9b03652001-03-07Kenneth Johansson  <tag>cimg-url</tag> takes the same attributes as <xref href='cimg.tag' />, including the image cache attributes. The use for
4b3fc02001-03-12Johan Sundström  the tag is to insert image-URLs into various places, e.g. a
9b03652001-03-07Kenneth Johansson  submit-box.</p>
2fafd22000-05-18Kenneth Johansson </desc>
4b3fc02001-03-12Johan Sundström <attr name='src' value='url' required='required'><p>
9b03652001-03-07Kenneth Johansson  The path to the indata file.</p>
2fafd22000-05-18Kenneth Johansson 
4b3fc02001-03-12Johan Sundström <ex><cimg-url src='/internal-roxen-testimage'/></ex>
2fafd22000-05-18Kenneth Johansson </attr>
9b03652001-03-07Kenneth Johansson <attr name='data' value='imagedata'><p>
2fafd22000-05-18Kenneth Johansson  Insert images from other sources, e.g. databases through entities or
9b03652001-03-07Kenneth Johansson  variables.</p>
cba1fa2001-08-30Johan Sundström <ex-box><emit source='sql' query='select imagedata from images where id=37'> <cimg-url data='&sql.imagedata;'/> </emit></ex-box>
5adc582009-11-30Henrik Grubbström (Grubba) </attr> <h1>Timeout</h1> <p>The generated image will by default never expire, but in some circumstances it may be pertinent to limit the time the image and its associated data is kept. Its possible to set an (advisory) timeout on the image data using the following attributes.</p> <attr name='unix-time' value='number'><p> Set the base expiry time to this absolute time.</p><p> If left out, the other attributes are relative to current time.</p> </attr> <attr name='years' value='number'><p> Add this number of years to the time this entry is valid.</p> </attr> <attr name='months' value='number'><p> Add this number of months to the time this entry is valid.</p> </attr> <attr name='weeks' value='number'><p> Add this number of weeks to the time this entry is valid.</p> </attr> <attr name='days' value='number'><p> Add this number of days to the time this entry is valid.</p> </attr> <attr name='hours' value='number'><p> Add this number of hours to the time this entry is valid.</p> </attr> <attr name='beats' value='number'><p> Add this number of beats to the time this entry is valid.</p> </attr> <attr name='minutes' value='number'><p> Add this number of minutes to the time this entry is valid.</p> </attr> <attr name='seconds' value='number'><p> Add this number of seconds to the time this entry is valid.</p>
7390582000-06-01Martin Nilsson </attr>",
0783ea2000-08-29Kenneth Johansson 
ce8fb02001-09-21Johan Sundström "emit#cimg":({ #"<desc type='plugin'><p><short>
9b03652001-03-07Kenneth Johansson  Entitybased version of <xref href='../graphics/cimg.tag' />.</short> Takes the same attributes as <tag>cimg</tag>.</p>
a0909c2004-10-27Jonas Wallden </desc> <attr name='nodata' value='yes | no'><p> Controls suppression of <ent>_.data</ent> in the output. Useful for reducing memory consumption in cached emit tags. The default value
c0f5522005-01-27Anders Johansson  is 'no'.</p> </attr>",
0783ea2000-08-29Kenneth Johansson  ([
ce8fb02001-09-21Johan Sundström "&_.type;":#"<desc type='entity'><p>
9b03652001-03-07Kenneth Johansson  Returns the image's content-type.</p>
0783ea2000-08-29Kenneth Johansson </desc>",
ce8fb02001-09-21Johan Sundström "&_.src;":#"<desc type='entity'><p>
9b03652001-03-07Kenneth Johansson  Returns the path to the indata file.</p>
0783ea2000-08-29Kenneth Johansson </desc>",
ce8fb02001-09-21Johan Sundström "&_.file-size;":#"<desc type='entity'><p>
9b03652001-03-07Kenneth Johansson  Returns the image's file size.</p>
0783ea2000-08-29Kenneth Johansson </desc>",
ce8fb02001-09-21Johan Sundström "&_.xsize;":#"<desc type='entity'><p>
9b03652001-03-07Kenneth Johansson  Returns the width of the image.</p>
0783ea2000-08-29Kenneth Johansson </desc>",
ce8fb02001-09-21Johan Sundström "&_.ysize;":#"<desc type='entity'><p>
9b03652001-03-07Kenneth Johansson  Returns the height of the image.</p>
0783ea2000-08-29Kenneth Johansson </desc>",
ce8fb02001-09-21Johan Sundström "&_.data;":#"<desc type='entity'><p>
08b5672000-09-19Kenneth Johansson  Returns the imagedata given through other sources, like databases
9b03652001-03-07Kenneth Johansson  through entities.</p>
0783ea2000-08-29Kenneth Johansson </desc>" ]) }),
7390582000-06-01Martin Nilsson ]);
2e0a351999-12-09Martin Nilsson #endif
4afee22001-04-03Per Hedbor int do_ext;
fe32ad2001-03-30Johan Sundström void create() { defvar("ext", Variable.Flag(0, VAR_MORE, "Append format to generated images", "Append the image format (.gif, .png, " ".jpg, etc) to the generated images. " "This is not necessary, but might seem " "nicer, especially to people who try " "to mirror your site.")); }
7390582000-06-01Martin Nilsson 
37bdda1999-05-18Per Hedbor void start() {
1c06512007-01-17Jonas Wallden  // Reuse previous cache object if possible if (the_cache) { // Update reference to callback function in case we've been reloaded the_cache->set_draw_function(generate_image); } else { the_cache = roxen.ImageCache( "cimg", generate_image ); }
4afee22001-04-03Per Hedbor  do_ext = query("ext");
37bdda1999-05-18Per Hedbor }
1c06512007-01-17Jonas Wallden void stop() { // Force cache object to be recreated in start()
c7ba992010-04-27Henrik Grubbström (Grubba)  destruct(the_cache);
1c06512007-01-17Jonas Wallden }
2fa8d52000-06-02Martin Nilsson mapping(string:function) query_action_buttons() {
da43042005-12-16Jonas Wallden  return ([ "Clear Cache":flush_cache ]);
5f13d52000-06-03Martin Nilsson } void flush_cache() { the_cache->flush();
3cca1c2004-05-21Jonas Wallden  // It's possible that user code contains a number of stale URLs in // e.g. <cache> blocks so we can just as well flush the RAM cache to // reduce the risk of broken images. cache.flush_memory_cache();
2fa8d52000-06-02Martin Nilsson } string status() { array s=the_cache->status();
482ba72000-12-30Per Hedbor  return sprintf("<b>Images in cache:</b> %d images<br />\n" "<b>Cache size:</b> %s", s[0], Roxen.sizetostring(s[1]));
2fa8d52000-06-02Martin Nilsson }
6a613a2002-06-17Anders Johansson array(Image.Layer)|mapping generate_image( mapping args, RequestID id )
37bdda1999-05-18Per Hedbor {
689f3a2000-11-21Per Hedbor  array layers;
13b35c2003-07-04Jonas Wallden  // Photoshop layers: don't let individual layers expand the image // beyond the bounds of the overall image. mapping opts = ([ "crop_to_bounds" : 1 ]);
689f3a2000-11-21Per Hedbor  if( args["process-all-layers"] ) opts->draw_all_layers = 1;
bd2fd02001-08-15Per Hedbor  if( args["jpeg-shrink" ] ) { opts->scale_denom = (int)args["jpeg-shrink" ]; opts->scale_num = 1; }
34a9b81999-08-06Peter Bortas  if( args->data )
689f3a2000-11-21Per Hedbor  layers = roxen.decode_layers( args->data, opts );
34a9b81999-08-06Peter Bortas  else
6a613a2002-06-17Anders Johansson  {
5ae0a32002-10-24Jonas Wallden  mixed tmp;
192e362013-11-26Anders Johansson #if constant(Sitebuilder) && constant(Sitebuilder.sb_start_use_imagecache)
5ae0a32002-10-24Jonas Wallden  // Let SiteBuilder get a chance to decode its argument data if (Sitebuilder.sb_start_use_imagecache) { Sitebuilder.sb_start_use_imagecache(args, id); tmp = roxen.load_layers(args->src, id, opts); Sitebuilder.sb_end_use_imagecache(args, id); } else #endif { tmp = roxen.load_layers(args->src, id, opts); }
d86e712002-07-01Anders Johansson  if (mappingp(tmp)) {
02d09b2004-05-05Anders Johansson  if (tmp->error == Protocols.HTTP.HTTP_UNAUTH)
d86e712002-07-01Anders Johansson  return tmp; else layers = 0; }
6a613a2002-06-17Anders Johansson  else layers = tmp; }
689f3a2000-11-21Per Hedbor 
7b56752001-06-25Marcus Wellhardh  if(!layers)
bd2fd02001-08-15Per Hedbor  { if( args->data )
78b9122012-06-21Martin Stjernholm  RXML.run_error("Failed to decode specified data\n");
bd2fd02001-08-15Per Hedbor  else
78b9122012-06-21Martin Stjernholm  RXML.run_error("Failed to load specified image [%O]\n", args->src);
bd2fd02001-08-15Per Hedbor  }
d86e712002-07-01Anders Johansson 
02d09b2004-05-05Anders Johansson  if (!sizeof(filter(layers->image(), objectp)))
78b9122012-06-21Martin Stjernholm  RXML.run_error("Failed to decode layers in specified image [%O]\n", args->src);
5715f82005-10-05Marcus Wellhardh  if(!args["exclude-invisible-layers"]) layers->set_misc_value( "visible",1 );
930b632000-12-10Per Hedbor  foreach( layers, Image.Layer lay ) if( !lay->get_misc_value( "name" ) ) lay->set_misc_value( "name", "Background" );
689f3a2000-11-21Per Hedbor  if( args["exclude-layers"] ) { foreach( args["exclude-layers"] / ",", string match ) foreach( layers, Image.Layer lay ) if( glob( match, lay->get_misc_value( "name" ) ) ) lay->set_misc_value( "visible", 0 ); } if( args["include-layers"] ) { foreach( args["include-layers"] / ",", string match ) foreach( layers, Image.Layer lay ) if( glob( match, lay->get_misc_value( "name" ) ) ) lay->set_misc_value( "visible", 1 ); } array res = ({}); foreach( layers, Image.Layer l ) { if( l->get_misc_value( "visible" ) ) res += ({ l }); } return res;
37bdda1999-05-18Per Hedbor } mapping find_internal( string f, RequestID id ) {
4afee22001-04-03Per Hedbor  // It's not enough to // 1. Only do this check when the ext flag is set, old URLs might // live in caches // // 2. Check str[-4] for '.', consider .jpeg .tiff etc. //
e449062008-10-29 Erik Dahl  // 3. Also handle / if filename attribute is used in either tag //
4afee22001-04-03Per Hedbor  // However, . is not a valid character in the ID, so just cutting at
e449062008-10-29 Erik Dahl  // the first one works as well as also cutting at the first /. sscanf (f, "%[^./]", f); return the_cache->http_file_answer( f, id );
37bdda1999-05-18Per Hedbor }
2fa8d52000-06-02Martin Nilsson mapping get_my_args( mapping args, RequestID id )
37bdda1999-05-18Per Hedbor {
36eceb2000-01-30Per Hedbor  mapping a= ([
37bdda1999-05-18Per Hedbor  "quant":args->quant,
77926b2000-04-11Per Hedbor  "crop":args->crop,
c526921999-05-18Per Hedbor  "format":args->format, "maxwidth":args->maxwidth, "maxheight":args->maxheight, "scale":args->scale, "dither":args->dither,
b941aa1999-06-25Per Hedbor  "gamma":args->gamma,
34a9b81999-08-06Peter Bortas  "data":args->data,
37bdda1999-05-18Per Hedbor  ]);
77926b2000-04-11Per Hedbor 
7c4b6b2003-09-15Jonas Wallden  if( args->src ) {
a6f9562000-09-19Per Hedbor  a->src = Roxen.fix_relative( args->src, id );
c0acab2009-02-19Jonas Wallden  array(int)|Stat st = (id->conf->try_stat_file(a->src, id));
689f3a2000-11-21Per Hedbor  if (st) { string fn = id->conf->real_file( a->src, id ); if( fn ) Roxen.add_cache_stat_callback( id, fn, st[ST_MTIME] ); a->mtime = (string) (a->stat = st[ST_MTIME]);
1133a72000-07-07Henrik Grubbström (Grubba)  a->filesize = (string) st[ST_SIZE];
5ae0a32002-10-24Jonas Wallden 
192e362013-11-26Anders Johansson #if constant(Sitebuilder) && constant(Sitebuilder.sb_start_use_imagecache)
5d41d12002-11-06Anders Johansson  // The file we called try_stat_file() on above may be a SiteBuilder
5ae0a32002-10-24Jonas Wallden  // file. If so we need to extend the argument data with e.g. // current language fork. if (Sitebuilder.sb_prepare_imagecache)
2007802002-10-24Jonas Wallden  a = Sitebuilder.sb_prepare_imagecache(a, a->src, id);
5ae0a32002-10-24Jonas Wallden #endif
1133a72000-07-07Henrik Grubbström (Grubba)  }
7c4b6b2003-09-15Jonas Wallden  }
2fa8d52000-06-02Martin Nilsson 
1c10ca2000-07-05Per Hedbor  a["background-color"] = id->misc->defines->bgcolor || "#eeeeee";
77926b2000-04-11Per Hedbor 
65abe92013-09-17Anders Johansson  foreach( glob( "*-*", indices(args)), string n ) { if (!has_prefix(n, "data-")) a[n] = args[n]; }
77926b2000-04-11Per Hedbor 
34a9b81999-08-06Peter Bortas  return a; }
a49dae2000-08-17Per Hedbor mapping check_args( mapping args ) { if( !args->format ) args->format = "png"; if( !(args->src || args->data) ) RXML.parse_error("Required attribute 'src' or 'data' missing\n");
314e012006-10-05Jonas Wallden  if (args->src == "") RXML.parse_error("Attribute 'src' cannot be empty\n");
a49dae2000-08-17Per Hedbor  if( args->src && args->data ) RXML.parse_error("Only one of 'src' and 'data' may be specified\n"); return args; } class TagCimgplugin { inherit RXML.Tag; constant name = "emit"; constant plugin_name = "cimg"; array get_dataset( mapping args, RequestID id ) { mapping res = ([ ]); mapping a = get_my_args( check_args( args ), id ); string data;
9363fa2009-11-24Henrik Grubbström (Grubba) 
ce4deb2009-11-26Henrik Grubbström (Grubba)  int timeout = Roxen.timeout_dequantifier(args);
9363fa2009-11-24Henrik Grubbström (Grubba) 
21bd602004-06-16Anders Johansson  // Store misc->cacheable since the image cache can raise it and // disable protocol cache. int cacheable = id->misc->cacheable; int no_proto_cache = id->misc->no_proto_cache; #ifdef DEBUG_CACHEABLE report_debug("%s:%d saved cacheable flags\n", __FILE__, __LINE__); #endif
9363fa2009-11-24Henrik Grubbström (Grubba)  res->src=(query_absolute_internal_location(id)+ the_cache->store( a, id, timeout ));
e449062008-10-29 Erik Dahl  if(args->filename && sizeof(args->filename))
241b7e2008-10-29 Erik Dahl  res->src += "/" + Roxen.http_encode_url(args->filename);
4afee22001-04-03Per Hedbor  if(do_ext)
046fc42008-12-17Tomas Nilsson  res->src += "." + a->format;
eac60f2001-01-26Per Hedbor  data = the_cache->data( a, id , 0 ); res["file-size"] = strlen(data); res["file-size-kb"] = strlen(data)/1024;
a0909c2004-10-27Jonas Wallden  if (lower_case(args->nodata || "no") == "no") res["data"] = data;
91d0172009-12-01Henrik Grubbström (Grubba)  res |= the_cache->metadata( a, id, 0, timeout ); // enforce generation
21bd602004-06-16Anders Johansson #ifdef DEBUG_CACHEABLE report_debug("%s:%d restored cacheable flags\n", __FILE__, __LINE__); #endif id->misc->cacheable = cacheable; id->misc->no_proto_cache = no_proto_cache;
eac60f2001-01-26Per Hedbor  return ({ res });
a49dae2000-08-17Per Hedbor  } } class TagCImg {
2fa8d52000-06-02Martin Nilsson  inherit RXML.Tag; constant name = "cimg";
1b2d742001-10-08Anders Johansson  constant flags = RXML.FLAG_EMPTY_ELEMENT;
2fa8d52000-06-02Martin Nilsson 
fe32ad2001-03-30Johan Sundström  class Frame
a49dae2000-08-17Per Hedbor  {
2fa8d52000-06-02Martin Nilsson  inherit RXML.Frame;
a49dae2000-08-17Per Hedbor  array do_return(RequestID id) {
ce4deb2009-11-26Henrik Grubbström (Grubba)  int timeout = Roxen.timeout_dequantifier(args);
a49dae2000-08-17Per Hedbor  mapping a = get_my_args( check_args( args ), id );
2fa8d52000-06-02Martin Nilsson  args -= a;
fe32ad2001-03-30Johan Sundström  string ext = "";
e449062008-10-29 Erik Dahl  string filename = ""; if(args->filename && sizeof(args->filename))
241b7e2008-10-29 Erik Dahl  filename += "/" + Roxen.http_encode_url(m_delete(args, "filename"));
4afee22001-04-03Per Hedbor  if(do_ext)
046fc42008-12-17Tomas Nilsson  ext = "." + a->format;
241b7e2008-10-29 Erik Dahl  args->src = query_absolute_internal_location( id )
9363fa2009-11-24Henrik Grubbström (Grubba)  + the_cache->store( a, id, timeout ) + filename + ext;
5701ac2003-10-17Anders Johansson  int no_draw = !id->misc->generate_images;
94a6152009-01-08Stephen R. van den Berg  mapping size; if( !args->width && !args->height
91d0172009-12-01Henrik Grubbström (Grubba)  && (size = the_cache->metadata( a, id, no_draw, timeout )) )
2fa8d52000-06-02Martin Nilsson  {
cf5b112003-10-16Anders Johansson  // image in cache (no_draw above prevents generation on-the-fly)
2fa8d52000-06-02Martin Nilsson  args->width = size->xsize; args->height = size->ysize; }
0023a62000-08-22Martin Nilsson  int xml=!args->noxml; m_delete(args, "noxml"); result = Roxen.make_tag( "img", args, xml );
2fa8d52000-06-02Martin Nilsson  return 0; }
37bdda1999-05-18Per Hedbor  } }
698c121999-05-19Peter Bortas 
2fa8d52000-06-02Martin Nilsson class TagCImgURL { inherit RXML.Tag; constant name = "cimg-url";
1b2d742001-10-08Anders Johansson  constant flags = RXML.FLAG_EMPTY_ELEMENT;
2fa8d52000-06-02Martin Nilsson 
a49dae2000-08-17Per Hedbor  class Frame {
2fa8d52000-06-02Martin Nilsson  inherit RXML.Frame;
4b3fc02001-03-12Johan Sundström  array do_return(RequestID id)
a49dae2000-08-17Per Hedbor  {
ce4deb2009-11-26Henrik Grubbström (Grubba)  int timeout = Roxen.timeout_dequantifier(args);
e449062008-10-29 Erik Dahl  string filename = "";
046fc42008-12-17Tomas Nilsson  mapping a = get_my_args (check_args (args), id);
6e84362009-07-08Anders Johansson  if(args->filename && sizeof(args->filename)) filename = "/" + Roxen.http_encode_url(args->filename);
241b7e2008-10-29 Erik Dahl  result = query_absolute_internal_location(id)
9363fa2009-11-24Henrik Grubbström (Grubba)  + the_cache->store(a, id, timeout)
241b7e2008-10-29 Erik Dahl  + filename
046fc42008-12-17Tomas Nilsson  + (do_ext ? "." + a->format : "");
2fa8d52000-06-02Martin Nilsson  return 0; } }
698c121999-05-19Peter Bortas }