Annotation of parser3/src/classes/image.C, revision 1.43
1.1 paf 1: /** @file
2: Parser: @b image parser class.
3:
1.16 paf 4: Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
1.1 paf 5:
1.16 paf 6: Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
1.1 paf 7:
1.43 ! parser 8: $Id: image.C,v 1.42 2001/09/14 15:41:59 parser Exp $
1.31 parser 9: */
1.43 ! parser 10: static const char *RCSId="$Id: image.C,v 1.42 2001/09/14 15:41:59 parser Exp $";
1.31 parser 11:
12: /*
13: jpegsize: gets the width and height (in pixels) of a jpeg file
14: Andrew Tong, werdna@ugcs.caltech.edu February 14, 1995
15: modified slightly by alex@ed.ac.uk
16: and further still by rjray@uswest.com
17: optimization and general re-write from tmetro@vl.com
18: from perl by paf@design.ru
1.1 paf 19: */
20:
21: #include "pa_config_includes.h"
22:
1.8 paf 23: #include "gif.h"
1.6 paf 24:
1.1 paf 25: #include "pa_common.h"
26: #include "pa_request.h"
27: #include "pa_vfile.h"
28: #include "pa_vimage.h"
29:
1.22 paf 30: // defines
1.1 paf 31:
1.22 paf 32: #define IMAGE_CLASS_NAME "image"
33:
34: // class
35:
36: class MImage : public Methoded {
37: public: // VStateless_class
38: Value *create_new_value(Pool& pool) { return new(pool) VImage(pool); }
39:
40: public:
41: MImage(Pool& pool);
1.24 paf 42:
43: public: // Methoded
1.22 paf 44: bool used_directly() { return true; }
45:
46: };
1.1 paf 47:
48: // helpers
49:
1.43 ! parser 50: #ifndef DOXYGEN
1.1 paf 51: class Measure_reader {
52: public:
1.31 parser 53: enum { READ_CHUNK_SIZE=0x400*10 };// 10K
1.16 paf 54: typedef size_t(*Func)(void *& buf, size_t limit, void *info);
1.1 paf 55:
56: Measure_reader(Func afunc, void *ainfo) :
57: func(afunc), info(ainfo),
58: chunk(0), offset(0), size(0) {
59: }
60:
1.31 parser 61: size_t read(void *&buf, size_t limit) {
1.3 paf 62: if(offset+limit>size) // nothing left
63: if(offset==0 || limit==1) { // only one-byte continuations allowed
64: size=(*func)(chunk, READ_CHUNK_SIZE, info);
65: offset=0;
66: } else
1.16 paf 67: return 0;// as if EOF
1.1 paf 68: if(!size) // EOF
69: return 0;
70:
71: // something left
72: size_t read_size=min(offset+limit, size)-offset;
73: buf=((unsigned char *)chunk)+offset;
74: offset+=read_size;
75: return read_size;
76: }
77:
78: private:
79: Func func;
80: void *info;
81:
82: void *chunk;
83: size_t offset;
84: size_t size;
85: };
1.43 ! parser 86: #endif
1.1 paf 87:
1.21 paf 88: /// GIF file header
1.1 paf 89: struct GIF_Header {
1.16 paf 90: char type[3]; // 'GIF'
1.1 paf 91: char version[3];
92: unsigned char width[2];
93: unsigned char height[2];
94: char dif;
95: char fonColor;
96: char nulls;
97: };
98:
1.31 parser 99: /// JPEG record head
100: struct JPG_Segment_head {
101: unsigned char marker;
102: unsigned char code;
103: unsigned char length[2];
1.1 paf 104: };
1.21 paf 105: /// JPEG frame header
1.31 parser 106: struct JPG_Size_segment_body {
1.27 parser 107: char data; //< data precision of bits/sample
1.31 parser 108: unsigned char height[2]; //< image height
109: unsigned char width[2]; //< image width
1.27 parser 110: char numComponents; //< number of color components
1.1 paf 111: };
112:
113: //
114:
1.33 parser 115: inline short x_endian_to_int(unsigned char L, unsigned char H) {
116: return(short)((H<<8) + L);
117: }
118:
119: inline short big_endian_to_int(unsigned char b[2]) {
120: return x_endian_to_int(b[1], b[0]);
121: }
122:
123: inline short little_endian_to_int(unsigned char b[2]) {
124: return x_endian_to_int(b[0], b[1]);
1.1 paf 125: }
126:
127: void measure_gif(Pool& pool, const String *origin_string,
128: Measure_reader& reader, int& width, int& height) {
129:
1.31 parser 130: void *buf;
1.1 paf 131: const int head_size=sizeof(GIF_Header);
132: if(reader.read(buf, head_size)<head_size)
133: PTHROW(0, 0,
134: origin_string,
1.34 parser 135: "not GIF file - too small");
1.31 parser 136: GIF_Header *head=(GIF_Header *)buf;
1.1 paf 137:
1.31 parser 138: if(strncmp(head->type, "GIF", 3)!=0)
1.1 paf 139: PTHROW(0, 0,
140: origin_string,
1.34 parser 141: "not GIF file - signature not found");
1.1 paf 142:
1.33 parser 143: width=little_endian_to_int(head->width);
144: height=little_endian_to_int(head->height);
1.1 paf 145: }
146:
147: void measure_jpeg(Pool& pool, const String *origin_string,
148: Measure_reader& reader, int& width, int& height) {
1.2 paf 149: // JFIF format markers
1.31 parser 150: const unsigned char MARKER=0xFF;
1.34 parser 151: const unsigned char CODE_SIZE_FIRST=0xC0;
152: const unsigned char CODE_SIZE_LAST=0xC3;
1.2 paf 153:
1.31 parser 154: void *buf;
1.18 paf 155: const size_t prefix_size=2;
1.31 parser 156: if(reader.read(buf, prefix_size)<prefix_size)
1.1 paf 157: PTHROW(0, 0,
158: origin_string,
1.34 parser 159: "not JPEG file - too small");
1.31 parser 160: unsigned char *signature=(unsigned char *)buf;
1.1 paf 161:
1.31 parser 162: if(!(signature[0]==0xFF && signature[1]==0xD8))
1.1 paf 163: PTHROW(0, 0,
164: origin_string,
1.34 parser 165: "not JPEG file - signature not found");
1.31 parser 166:
167: bool found=false;
168: while(true) {
169: void *buf;
170: // Extract the segment header.
171: if(reader.read(buf, sizeof(JPG_Segment_head))<sizeof(JPG_Segment_head))
172: break;
173: JPG_Segment_head *head=(JPG_Segment_head *)buf;
174:
175: // Verify that it's a valid segment.
176: if(head->marker!=MARKER)
1.1 paf 177: break;
1.31 parser 178:
1.34 parser 179: if(head->code >= CODE_SIZE_FIRST && head->code <= CODE_SIZE_LAST) {
1.31 parser 180: // Segments that contain size info
181: if(reader.read(buf, sizeof(JPG_Size_segment_body))<sizeof(JPG_Size_segment_body))
182: break;
183: JPG_Size_segment_body *body=(JPG_Size_segment_body *)buf;
184:
1.32 parser 185: width=big_endian_to_int(body->width);
186: height=big_endian_to_int(body->height);
1.31 parser 187: found=true;
1.1 paf 188: break;
1.31 parser 189: } else {
190: // Dummy read to skip over data
1.32 parser 191: size_t limit=big_endian_to_int(head->length) - 2;
1.31 parser 192: if(reader.read(buf, limit)<limit)
193: break;
194: }
195: }
196:
197: if(!found)
1.16 paf 198: PTHROW(0, 0,
199: origin_string,
1.31 parser 200: "broken JPEG file - size frame not found");
1.1 paf 201: }
202:
203: // measure center
204:
205: void measure(Pool& pool, const String& file_name,
206: Measure_reader& reader, int& width, int& height) {
207: if(const char *cext=strrchr(file_name.cstr(), '.')) {
208: cext++;
209: if(strcasecmp(cext, "GIF")==0)
210: measure_gif(pool, &file_name, reader, width, height);
211: else if(strcasecmp(cext, "JPG")==0 || strcasecmp(cext, "JPEG")==0)
212: measure_jpeg(pool, &file_name, reader, width, height);
213: else
214: PTHROW(0, 0,
215: &file_name,
216: "unhandled image file name extension '%s'", cext);
217: } else
218: PTHROW(0, 0,
219: &file_name,
220: "can not determine image type - no file name extension");
221: }
222:
1.40 parser 223: #ifndef DOXYGEN
1.1 paf 224: struct Read_mem_info {
225: unsigned char *ptr;
226: unsigned char *eof;
227: };
1.40 parser 228: #endif
1.1 paf 229: static size_t read_mem(void*& buf, size_t limit, void *info) {
230: Read_mem_info& rmi=*static_cast<Read_mem_info *>(info);
231: buf=rmi.ptr;
232: size_t read_size=min(limit, (size_t)(rmi.eof-rmi.ptr));
233: rmi.ptr+=read_size;
234: return read_size;
235: }
236:
1.40 parser 237: #ifndef DOXYGEN
1.1 paf 238: struct Read_disk_info {
239: const String *file_spec;
240: size_t offset;
241: };
1.40 parser 242: #endif
1.1 paf 243: static size_t read_disk(void*& buf, size_t limit, void *info) {
244: Read_disk_info& rdi=*static_cast<Read_disk_info *>(info);
245: Pool& pool=rdi.file_spec->pool();
246:
247: size_t read_size;
248: file_read(pool, *rdi.file_spec,
249: buf, read_size,
250: false/*as_text*/,
251: true/*fail_on_read_problem*/,
252: rdi.offset, limit);
253:
254: rdi.offset+=read_size;
255: return read_size;
256: }
257:
258: // methods
259:
1.17 paf 260: static void _measure(Request& r, const String& method_name, MethodParams *params) {
1.1 paf 261: Pool& pool=r.pool();
262:
1.30 parser 263: Value& data=params->as_no_junction(0, "data must not be code");
1.1 paf 264:
1.16 paf 265: void *info;Measure_reader::Func read_func;
1.1 paf 266: Read_mem_info read_mem_info;
267: Read_disk_info read_disk_info;
268: const String *file_name;
269: if(data.is_string()) {
270: file_name=data.get_string();
271: read_disk_info.file_spec=&r.absolute(*file_name);
272: read_disk_info.offset=0;
1.16 paf 273: info=&read_disk_info;read_func=read_disk;
1.1 paf 274: } else {
275: const VFile& vfile=*data.as_vfile();
276: file_name=&static_cast<Value *>(vfile.fields().get(*name_name))->as_string();
277: read_mem_info.ptr=(unsigned char *)vfile.value_ptr();
278: read_mem_info.eof=read_mem_info.ptr+vfile.value_size();
1.16 paf 279: info=&read_mem_info;read_func=read_mem;
1.1 paf 280: }
281:
282: Measure_reader reader(read_func, info);
283: int width, height;
284: measure(pool, *file_name, reader, width, height);
285:
1.6 paf 286: static_cast<VImage *>(r.self)->set(file_name, width, height);
1.1 paf 287: }
288:
1.40 parser 289: #ifndef DOXYGEN
1.4 paf 290: struct Attrib_info {
1.21 paf 291: String *tag; ///< html tag being constructed
292: Hash *skip; ///< tag attributes not to append to tag string [to skip]
1.4 paf 293: };
1.40 parser 294: #endif
1.3 paf 295: static void append_attrib_pair(const Hash::Key& key, Hash::Val *val, void *info) {
1.4 paf 296: Attrib_info& ai=*static_cast<Attrib_info *>(info);
297:
298: if(ai.skip && ai.skip->get(key))
299: return;
300:
1.3 paf 301: Value& value=*static_cast<Value *>(val);
302: // src="a.gif" width=123 ismap[=-1]
1.4 paf 303: *ai.tag << " " << key;
1.26 parser 304: if(value.is_string() || value.as_int()>=0)
1.6 paf 305: *ai.tag << "=\"" << value.as_string() << "\"";
1.3 paf 306: }
1.17 paf 307: static void _html(Request& r, const String& method_name, MethodParams *params) {
1.3 paf 308: Pool& pool=r.pool();
309:
310: String tag(pool);
311: tag << "<img";
1.4 paf 312:
1.18 paf 313: const Hash& fields=static_cast<VImage *>(r.self)->fields();
1.5 paf 314: Hash *attribs=0;
1.4 paf 315:
1.39 parser 316: if(params->size()) {
317: Value &vattribs=params->get(0);
318: if(vattribs.is_defined()) // allow 'void'
319: if(Hash *attribs=vattribs.get_hash()) {
320: Attrib_info attrib_info={&tag, 0};
321: attribs->for_each(append_attrib_pair, &attrib_info);
322: } else
323: PTHROW(0, 0,
324: &method_name,
325: "attributes must be hash");
326: }
1.4 paf 327:
1.5 paf 328: Attrib_info attrib_info={&tag, attribs};
1.4 paf 329: fields.for_each(append_attrib_pair, &attrib_info);
1.6 paf 330: tag << " />";
1.3 paf 331: r.write_pass_lang(tag);
332: }
1.8 paf 333:
1.16 paf 334: static gdImage *load(Request& r, const String& method_name,
335: const String& file_name){
336: Pool& pool=r.pool();
337:
1.42 parser 338: const char *file_name_cstr=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
1.16 paf 339: if(FILE *f=fopen(file_name_cstr, "rb")) {
340: gdImage& image=*new(pool) gdImage(pool);
1.23 paf 341: bool ok=image.CreateFromGif(f);
1.16 paf 342: fclose(f);
1.23 paf 343: if(!ok)
344: PTHROW(0, 0,
345: &file_name,
346: "is not in GIF format");
1.16 paf 347: return ℑ
348: } else {
349: PTHROW(0, 0,
350: &method_name,
351: "can not open '%s'", file_name_cstr);
352: return 0;
353: }
354: }
355:
356:
1.17 paf 357: static void _load(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 358: Pool& pool=r.pool();
359:
1.30 parser 360: Value& vfile_name=params->as_no_junction(0, "file name must not be code");
1.6 paf 361: const String& file_name=vfile_name.as_string();
362:
1.16 paf 363: gdImage& image=*load(r, method_name, file_name);
364: int width=image.SX();
365: int height=image.SY();
366: static_cast<VImage *>(r.self)->set(&file_name, width, height, &image);
1.6 paf 367: }
368:
1.17 paf 369: static void _create(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 370: Pool& pool=r.pool();
371:
1.36 parser 372: int width=params->as_int(0, r);
373: int height=params->as_int(1, r);
1.8 paf 374: int bgcolor_value=0xffFFff;
1.6 paf 375: if(params->size()>2)
1.36 parser 376: bgcolor_value=params->as_int(2, r);
1.15 paf 377: gdImage& image=*new(pool) gdImage(pool);
378: image.Create(width, height);
379: image.FilledRectangle(0, 0, width-1, height-1, image.Color(bgcolor_value));
380: static_cast<VImage *>(r.self)->set(0, width, height, &image);
1.6 paf 381: }
382:
1.17 paf 383: static void _gif(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 384: Pool& pool=r.pool();
385:
1.9 paf 386: gdImage *image=static_cast<VImage *>(r.self)->image;
1.8 paf 387: if(!image)
1.16 paf 388: PTHROW(0, 0,
389: &method_name,
1.12 paf 390: "does not contain an image");
1.6 paf 391:
392: // could _ but don't thing it's wise to use $image.src for vfile.name
1.10 paf 393:
1.16 paf 394: String out(pool); image->Gif(out);
1.6 paf 395:
396: VFile& vfile=*new(pool) VFile(pool);
1.41 parser 397: Value *content_type=new(pool) VString(*new(pool) String(pool, "image/gif"));
1.20 paf 398: vfile.set(false/*not tainted*/,
1.41 parser 399: out.cstr(String::UL_AS_IS), out.size(), 0, content_type);
1.6 paf 400:
401: r.write_no_lang(vfile);
402: }
403:
1.17 paf 404: static void _line(Request& r, const String& method_name, MethodParams *params) {
1.12 paf 405: Pool& pool=r.pool();
406:
407: gdImage *image=static_cast<VImage *>(r.self)->image;
408: if(!image)
1.16 paf 409: PTHROW(0, 0,
410: &method_name,
1.12 paf 411: "does not contain an image");
412:
413: image->Line(
1.36 parser 414: params->as_int(0, r),
415: params->as_int(1, r),
416: params->as_int(2, r),
417: params->as_int(3, r),
418: image->Color(params->as_int(4, r)));
1.13 paf 419: }
420:
1.17 paf 421: static void _fill(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 422: Pool& pool=r.pool();
423:
424: gdImage *image=static_cast<VImage *>(r.self)->image;
425: if(!image)
1.16 paf 426: PTHROW(0, 0,
427: &method_name,
1.13 paf 428: "does not contain an image");
1.12 paf 429:
1.13 paf 430: image->Fill(
1.36 parser 431: params->as_int(0, r),
432: params->as_int(1, r),
433: image->Color(params->as_int(2, r)));
1.13 paf 434: }
435:
1.17 paf 436: static void _rectangle(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 437: Pool& pool=r.pool();
438:
439: gdImage *image=static_cast<VImage *>(r.self)->image;
440: if(!image)
1.16 paf 441: PTHROW(0, 0,
442: &method_name,
1.13 paf 443: "does not contain an image");
444:
445: image->Rectangle(
1.36 parser 446: params->as_int(0, r),
447: params->as_int(1, r),
448: params->as_int(2, r),
449: params->as_int(3, r),
450: image->Color(params->as_int(4, r)));
1.13 paf 451: }
452:
1.17 paf 453: static void _bar(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 454: Pool& pool=r.pool();
455:
456: gdImage *image=static_cast<VImage *>(r.self)->image;
457: if(!image)
1.16 paf 458: PTHROW(0, 0,
459: &method_name,
1.13 paf 460: "does not contain an image");
461:
462: image->FilledRectangle(
1.36 parser 463: params->as_int(0, r),
464: params->as_int(1, r),
465: params->as_int(2, r),
466: params->as_int(3, r),
467: image->Color(params->as_int(4, r)));
1.13 paf 468: }
469:
1.17 paf 470: static void _replace(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 471: Pool& pool=r.pool();
472:
473: gdImage *image=static_cast<VImage *>(r.self)->image;
474: if(!image)
1.16 paf 475: PTHROW(0, 0,
476: &method_name,
1.13 paf 477: "does not contain an image");
478:
479: if((params->size()-2)%2) // I see your thoughts, but that's more readable
1.16 paf 480: PTHROW(0, 0,
481: &method_name,
1.13 paf 482: "y coordinate missing");
483:
484: int n=(params->size()-2)/2;
485:
486: gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);
487: for(int i=0; i<n; i++) {
1.36 parser 488: p[i].x=params->as_int(2+i*2+0, r);
489: p[i].y=params->as_int(2+i*2+1, r);
1.13 paf 490: }
1.16 paf 491: image->FilledPolygonReplaceColor(p, n,
1.36 parser 492: image->Color(params->as_int(0, r)), // src color
493: image->Color(params->as_int(1, r)));// dest color
1.13 paf 494: }
495:
1.17 paf 496: static void _polygon(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 497: Pool& pool=r.pool();
498:
499: gdImage *image=static_cast<VImage *>(r.self)->image;
500: if(!image)
1.16 paf 501: PTHROW(0, 0,
502: &method_name,
1.13 paf 503: "does not contain an image");
504:
505: if((params->size()-1)%2) // [I see..] see now?
1.16 paf 506: PTHROW(0, 0,
507: &method_name,
1.13 paf 508: "y coordinate missing");
509:
510: int n=(params->size()-1)/2;
511:
512: gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);
513: for(int i=0; i<n; i++) {
1.36 parser 514: p[i].x=params->as_int(2+i*2+0, r);
515: p[i].y=params->as_int(2+i*2+1, r);
1.13 paf 516: }
1.16 paf 517: image->Polygon(p, n,
1.36 parser 518: image->Color(params->as_int(0, r)));
1.13 paf 519: }
520:
1.17 paf 521: static void _polybar(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 522: Pool& pool=r.pool();
523:
524: gdImage *image=static_cast<VImage *>(r.self)->image;
525: if(!image)
1.16 paf 526: PTHROW(0, 0,
527: &method_name,
1.13 paf 528: "does not contain an image");
529:
530: if((params->size()-1)%2) // [I see..] see now?
1.16 paf 531: PTHROW(0, 0,
532: &method_name,
1.13 paf 533: "y coordinate missing");
534:
535: int n=(params->size()-1)/2;
536:
537: gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);
538: for(int i=0; i<n; i++) {
1.36 parser 539: p[i].x=params->as_int(2+i*2+0, r);
540: p[i].y=params->as_int(2+i*2+1, r);
1.13 paf 541: }
1.16 paf 542: image->FilledPolygon(p, n,
1.36 parser 543: image->Color(params->as_int(0, r)));
1.12 paf 544: }
545:
1.16 paf 546: // font
547:
548: #define Y(y)(y+index*height+1)
1.21 paf 549:
550: /// simple gdImage-based font storage & text output
1.16 paf 551: class Font : public Pooled {
552: public:
553:
1.38 parser 554: const static int letter_spacing;
1.35 parser 555: int height; ///< Font heigth
556: int monospace; ///< Default char width
557: int spacebarspace; ///< spacebar width
1.16 paf 558: gdImage& ifont;
559: const String& alphabet;
560:
561: Font(Pool& pool,
562: const String& aalphabet,
1.35 parser 563: gdImage& aifont, int aheight, int amonospace, int aspacebarspace) : Pooled(pool),
1.16 paf 564: alphabet(aalphabet),
1.35 parser 565: height(aheight), monospace(amonospace), spacebarspace(aspacebarspace),
1.16 paf 566: ifont(aifont) {
567: }
568:
569: /* ******************************** char ********************************** */
570:
571: int index_of(char ch) {
572: if(ch==' ') return -1;
573: return alphabet.pos(&ch, 1);
574: }
575:
576: int index_width(int index) {
577: if(index<0)
1.35 parser 578: return spacebarspace;
1.16 paf 579: int tr=ifont.GetTransparent();
1.35 parser 580: for(int x=ifont.SX()-1; x>=0; x--) {
1.16 paf 581: for(int y=0; y<height-1; y++)
582: if(ifont.GetPixel(x, Y(y))!=tr)
1.35 parser 583: return x+1;
1.16 paf 584: }
585: return 0;
586: }
587:
588: void index_display(gdImage& image, int x, int y, int index){
589: if(index>=0)
590: ifont.Copy(image, x, y, 0, Y(0), index_width(index), height-1);
591: }
592:
593: /* ******************************** string ********************************** */
594: /*
595: int string_width(const char *cstr){
596: int result=0;
597: for(; *cstr; cstr++)
598: result+=index_width(index_of(*cstr));
599: return result;
600: }
601: */
602:
603: void string_display(gdImage& image, int x, int y, const String& s){
604: const char *cstr=s.cstr(String::UL_AS_IS);
605: if(cstr) for(; *cstr; cstr++) {
606: int index=index_of(*cstr);
607: index_display(image, x, y, index);
1.38 parser 608: x+=letter_spacing + (monospace ? monospace : index_width(index));
1.16 paf 609: }
610: }
611:
612: };
1.38 parser 613: const int Font::letter_spacing=1;
1.35 parser 614:
1.17 paf 615: static void _font(Request& r, const String& method_name, MethodParams *params) {
1.16 paf 616: Pool& pool=r.pool();
617:
1.37 parser 618: const String& alphabet=params->as_string(0, "alphabet must not be code");
619: gdImage& image=*load(r, method_name, params->as_string(1, "file_name must not be code"));
1.36 parser 620: int spacebar_width=params->as_int(2, r);
1.37 parser 621: int monospace_width;
622: if(params->size()>3) {
623: monospace_width=params->as_int(3, r);
624: if(!monospace_width)
625: monospace_width=image.SX();
626: } else
627: monospace_width=0;
1.16 paf 628:
1.37 parser 629: if(!alphabet.size())
630: PTHROW(0, 0,
631: &method_name,
632: "alphabet must not be empty");
633:
1.16 paf 634: static_cast<VImage *>(r.self)->font=new(pool) Font(pool,
1.37 parser 635: alphabet,
1.36 parser 636: image,
1.37 parser 637: image.SY() / alphabet.size(), monospace_width, spacebar_width);
1.16 paf 638: }
639:
1.17 paf 640: static void _text(Request& r, const String& method_name, MethodParams *params) {
1.16 paf 641: Pool& pool=r.pool();
642:
1.36 parser 643: int x=params->as_int(0, r);
644: int y=params->as_int(1, r);
645: const String& s=params->as_string(2, "text must not be code");
1.16 paf 646:
647: VImage& vimage=*static_cast<VImage *>(r.self);
648: if(vimage.image)
649: if(vimage.font)
650: vimage.font->string_display(*vimage.image, x, y, s);
651: else
652: PTHROW(0, 0,
653: &method_name,
654: "set the font first");
655: else
656: PTHROW(0, 0,
657: &method_name,
658: "does not contain an image");
659: }
660:
1.22 paf 661: // constructor
662:
663: MImage::MImage(Pool& apool) : Methoded(apool) {
664: set_name(*NEW String(pool(), IMAGE_CLASS_NAME));
665:
666:
1.1 paf 667: // ^image:measure[DATA]
1.22 paf 668: add_native_method("measure", Method::CT_DYNAMIC, _measure, 1, 1);
1.3 paf 669:
1.25 paf 670: // ^image.html[]
671: // ^image.html[hash]
1.22 paf 672: add_native_method("html", Method::CT_DYNAMIC, _html, 0, 1);
1.6 paf 673:
1.25 paf 674: // ^image.load[background.gif]
1.22 paf 675: add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
1.6 paf 676:
1.25 paf 677: // ^image.create[width;height] bgcolor=white
678: // ^image.create[width;height;bgcolor]
1.22 paf 679: add_native_method("create", Method::CT_DYNAMIC, _create, 2, 3);
1.6 paf 680:
1.25 paf 681: // ^image.gif[]
1.22 paf 682: add_native_method("gif", Method::CT_DYNAMIC, _gif, 0, 0);
1.12 paf 683:
1.25 paf 684: // ^image.line(x0;y0;x1;y1;color)
1.22 paf 685: add_native_method("line", Method::CT_DYNAMIC, _line, 5, 5);
1.13 paf 686:
1.25 paf 687: // ^image.fill(x;y;color)
1.22 paf 688: add_native_method("fill", Method::CT_DYNAMIC, _fill, 3, 3);
1.13 paf 689:
1.25 paf 690: // ^image.rectangle(x0;y0;x1;y1;color)
1.22 paf 691: add_native_method("rectangle", Method::CT_DYNAMIC, _rectangle, 5, 5);
1.13 paf 692:
1.25 paf 693: // ^image.bar(x0;y0;x1;y1;color)
1.22 paf 694: add_native_method("bar", Method::CT_DYNAMIC, _bar, 5, 5);
1.13 paf 695:
1.25 paf 696: // ^image.replace(color-source;color-dest)(x;y)... point coord pairs
1.22 paf 697: add_native_method("replace", Method::CT_DYNAMIC, _replace, 2+3*2, 2+100*2);
1.13 paf 698:
1.25 paf 699: // ^image.polygon(color)(x;y)... point coord pairs
1.22 paf 700: add_native_method("polygon", Method::CT_DYNAMIC, _polygon, 1+3*2, 1+100*2);
1.13 paf 701:
1.25 paf 702: // ^image.polybar(color)(x;y)... point coord pairs
1.22 paf 703: add_native_method("polybar", Method::CT_DYNAMIC, _polybar, 1+3*2, 1+100*2);
1.13 paf 704:
1.36 parser 705: // ^image.font[alPHAbet;font-file-name.gif](spacebar_width)
706: // ^image.font[alPHAbet;font-file-name.gif](spacebar_width;width)
707: add_native_method("font", Method::CT_DYNAMIC, _font, 3, 4);
1.16 paf 708:
1.25 paf 709: // ^image.text(x;y)[text]
1.22 paf 710: add_native_method("text", Method::CT_DYNAMIC, _text, 3, 3);
1.16 paf 711:
1.22 paf 712: }
713:
714: // global variable
715:
716: Methoded *image_class;
717:
718: // creator
719:
720: Methoded *MImage_create(Pool& pool) {
721: return image_class=new(pool) MImage(pool);
1.1 paf 722: }
E-mail: