--- parser3/src/classes/image.C 2001/04/10 13:24:49 1.2 +++ parser3/src/classes/image.C 2001/04/11 17:00:53 1.8 @@ -5,15 +5,19 @@ Author: Alexander Petrosyan (http://design.ru/paf) - $Id: image.C,v 1.2 2001/04/10 13:24:49 paf Exp $ + $Id: image.C,v 1.8 2001/04/11 17:00:53 paf Exp $ */ #include "pa_config_includes.h" +#include + #ifdef WIN32 # include "smtp/smtp.h" #endif +#include "gif.h" + #include "pa_common.h" #include "pa_request.h" #include "pa_vfile.h" @@ -27,7 +31,7 @@ VStateless_class *image_class; class Measure_reader { public: - enum { READ_CHUNK_SIZE=10*0x400 }; // 10K + enum { READ_CHUNK_SIZE=0x400 }; // 1K typedef size_t (*Func)(void *& buf, size_t limit, void *info); Measure_reader(Func afunc, void *ainfo) : @@ -36,8 +40,12 @@ public: } size_t read(unsigned char *& buf, size_t limit) { - if(!size) // nothing left - size=(*func)(chunk, READ_CHUNK_SIZE, info); + if(offset+limit>size) // nothing left + if(offset==0 || limit==1) { // only one-byte continuations allowed + size=(*func)(chunk, READ_CHUNK_SIZE, info); + offset=0; + } else + return 0; // as if EOF if(!size) // EOF return 0; @@ -125,7 +133,7 @@ void measure_jpeg(Pool& pool, const Stri const unsigned char COM=0xFE; unsigned char *screenD_buf; - unsigned char *h_buf; + unsigned char *h_buf=0; bool flag=false; @@ -171,7 +179,7 @@ void measure_jpeg(Pool& pool, const Stri } } while(*marker!=EOI); - if(flag) { + if(flag && h_buf) { JPG_Frame& h=*reinterpret_cast(h_buf); width=bytes_to_int(h.width[0], h.width[1]); height=bytes_to_int(h.height[0], h.height[1]); @@ -265,11 +273,137 @@ static void _measure(Request& r, const S int width, height; measure(pool, *file_name, reader, width, height); - static_cast(r.self)->set(*file_name, width, height); + static_cast(r.self)->set(file_name, width, height); +} + +struct Attrib_info { + String *tag; + Hash *skip; +}; +static void append_attrib_pair(const Hash::Key& key, Hash::Val *val, void *info) { + Attrib_info& ai=*static_cast(info); + + if(ai.skip && ai.skip->get(key)) + return; + + Value& value=*static_cast(val); + // src="a.gif" width=123 ismap[=-1] + *ai.tag << " " << key; + if(value.is_string() || value.as_double()>=0) + *ai.tag << "=\"" << value.as_string() << "\""; +} +/// ^image.html[] +/// ^image.html[hash] +static void _html(Request& r, const String& method_name, Array *params) { + Pool& pool=r.pool(); + + String tag(pool); + tag << "(r.self)->fields(); + Hash *attribs=0; + + if(params) + if(attribs=static_cast(params->get(0))->get_hash()) { + Attrib_info attrib_info={&tag, 0}; + attribs->for_each(append_attrib_pair, &attrib_info); + } else + PTHROW(0, 0, + &method_name, + "attributes must be must be hash"); + + Attrib_info attrib_info={&tag, attribs}; + fields.for_each(append_attrib_pair, &attrib_info); + tag << " />"; + r.write_pass_lang(tag); +} + +/// ^image.load[background.gif] +static void _load(Request& r, const String& method_name, Array *params) { + Pool& pool=r.pool(); + + Value& vfile_name=*static_cast(params->get(0)); + // forcing [this body type] + r.fail_if_junction_(true, vfile_name, method_name, "file name must not be code"); + const String& file_name=vfile_name.as_string(); + + const char *file_name_cstr=r.absolute(file_name).cstr(String::UL_FILE_NAME); + if(FILE *f=fopen(file_name_cstr, "rb")) { + gdImagePtr image=gdImageCreateFromGif(f); + int width=gdImageSX(image); + int height=gdImageSY(image); + fclose(f); + + static_cast(r.self)->set(&file_name, width, height, image); + } else + PTHROW(0, 0, + &method_name, + "can not open background image '%s'", file_name_cstr); +} + +/// ^image.create[width;height] bgcolor=white +/// ^image.create[width;height;bgcolor] +static void _create(Request& r, const String& method_name, Array *params) { + Pool& pool=r.pool(); + + int width=(int)r.process(*static_cast(params->get(0))).as_double(); + int height=(int)r.process(*static_cast(params->get(1))).as_double(); + int bgcolor_value=0xffFFff; + if(params->size()>2) + bgcolor_value= + (int)r.process(*static_cast(params->get(2))).as_double(); + gdImage *image=new(pool) gdImage(pool); + image->Create(width, height); + image->FilledRectangle(0, 0, width-1, height-1, image->Color(bgcolor_value)); + static_cast(r.self)->set(0, width, height, image); +} + +/// ^image.gif[] +/// ^image.gif[user-file-name] +/// @test gdImageDestroy make gd pooled! +static void _gif(Request& r, const String& method_name, Array *params) { + Pool& pool=r.pool(); + + gdImagePtr image=static_cast(r.self)->image; + if(!image) + PTHROW(0, 0, + &method_name, + "does not contain image"); + + char *file_name_cstr=0; + if(params) { + Value& vfile_name=*static_cast(params->get(0)); + // forcing [this body type] + r.fail_if_junction_(true, vfile_name, method_name, "file name must not be code"); + + file_name_cstr=vfile_name.as_string().cstr(String::UL_FILE_NAME); + } + // could _ but don't thing it's wise to use $image.src for vfile.name + + VFile& vfile=*new(pool) VFile(pool); + String& image_gif=*new(pool) String(pool, "image/gif"); + vfile.set(false/*not tainted*/, z, z, file_name_cstr, &image_gif); + + r.write_no_lang(vfile); } // initialize void initialize_image_class(Pool& pool, VStateless_class& vclass) { // ^image:measure[DATA] vclass.add_native_method("measure", Method::CT_DYNAMIC, _measure, 1, 1); + + /// ^image.html[] + /// ^image.html[hash] + vclass.add_native_method("html", Method::CT_DYNAMIC, _html, 0, 1); + + /// ^image.load[background.gif] + vclass.add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1); + + /// ^image.create[width;height] bgcolor=white + /// ^image.create[width;height;bgcolor] + vclass.add_native_method("create", Method::CT_DYNAMIC, _create, 2, 3); + + /// ^image.gif[] + /// ^image.gif[user-file-name] + vclass.add_native_method("gif", Method::CT_DYNAMIC, _gif, 0, 1); }