Annotation of parser3/src/classes/image.C, revision 1.63
1.63 ! paf 1: 123
1.1 paf 2: /** @file
3: Parser: @b image parser class.
4:
1.16 paf 5: Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
1.62 paf 6: Author: Alexander Petrosyan <paf@design.ru>(http://paf.design.ru)
1.1 paf 7:
1.63 ! paf 8: $Id: image.C,v 1.62 2001/11/05 11:46:20 paf Exp $
1.31 parser 9: */
10:
11: /*
12: jpegsize: gets the width and height (in pixels) of a jpeg file
13: Andrew Tong, werdna@ugcs.caltech.edu February 14, 1995
14: modified slightly by alex@ed.ac.uk
15: and further still by rjray@uswest.com
16: optimization and general re-write from tmetro@vl.com
17: from perl by paf@design.ru
1.1 paf 18: */
19:
20: #include "pa_config_includes.h"
21:
1.8 paf 22: #include "gif.h"
1.6 paf 23:
1.1 paf 24: #include "pa_common.h"
25: #include "pa_request.h"
26: #include "pa_vfile.h"
27: #include "pa_vimage.h"
28:
1.22 paf 29: // defines
1.1 paf 30:
1.22 paf 31: #define IMAGE_CLASS_NAME "image"
32:
33: // class
34:
35: class MImage : public Methoded {
36: public: // VStateless_class
37: Value *create_new_value(Pool& pool) { return new(pool) VImage(pool); }
38:
39: public:
40: MImage(Pool& pool);
1.24 paf 41:
42: public: // Methoded
1.22 paf 43: bool used_directly() { return true; }
44:
45: };
1.1 paf 46:
47: // helpers
48:
1.43 parser 49: #ifndef DOXYGEN
1.1 paf 50: class Measure_reader {
51: public:
1.45 parser 52: enum { READ_CHUNK_SIZE=0x400*20 };// 20K
1.16 paf 53: typedef size_t(*Func)(void *& buf, size_t limit, void *info);
1.1 paf 54:
55: Measure_reader(Func afunc, void *ainfo) :
56: func(afunc), info(ainfo),
57: chunk(0), offset(0), size(0) {
58: }
59:
1.31 parser 60: size_t read(void *&buf, size_t limit) {
1.3 paf 61: if(offset+limit>size) // nothing left
62: if(offset==0 || limit==1) { // only one-byte continuations allowed
63: size=(*func)(chunk, READ_CHUNK_SIZE, info);
64: offset=0;
65: } else
1.16 paf 66: return 0;// as if EOF
1.1 paf 67: if(!size) // EOF
68: return 0;
69:
70: // something left
71: size_t read_size=min(offset+limit, size)-offset;
72: buf=((unsigned char *)chunk)+offset;
73: offset+=read_size;
74: return read_size;
75: }
76:
77: private:
78: Func func;
79: void *info;
80:
81: void *chunk;
82: size_t offset;
83: size_t size;
84: };
1.43 parser 85: #endif
1.1 paf 86:
1.21 paf 87: /// GIF file header
1.1 paf 88: struct GIF_Header {
1.16 paf 89: char type[3]; // 'GIF'
1.1 paf 90: char version[3];
91: unsigned char width[2];
92: unsigned char height[2];
93: char dif;
94: char fonColor;
95: char nulls;
96: };
97:
1.31 parser 98: /// JPEG record head
99: struct JPG_Segment_head {
100: unsigned char marker;
101: unsigned char code;
102: unsigned char length[2];
1.1 paf 103: };
1.21 paf 104: /// JPEG frame header
1.31 parser 105: struct JPG_Size_segment_body {
1.27 parser 106: char data; //< data precision of bits/sample
1.31 parser 107: unsigned char height[2]; //< image height
108: unsigned char width[2]; //< image width
1.27 parser 109: char numComponents; //< number of color components
1.1 paf 110: };
111:
112: //
113:
1.33 parser 114: inline short x_endian_to_int(unsigned char L, unsigned char H) {
115: return(short)((H<<8) + L);
116: }
117:
118: inline short big_endian_to_int(unsigned char b[2]) {
119: return x_endian_to_int(b[1], b[0]);
120: }
121:
122: inline short little_endian_to_int(unsigned char b[2]) {
123: return x_endian_to_int(b[0], b[1]);
1.1 paf 124: }
125:
126: void measure_gif(Pool& pool, const String *origin_string,
127: Measure_reader& reader, int& width, int& height) {
128:
1.31 parser 129: void *buf;
1.1 paf 130: const int head_size=sizeof(GIF_Header);
131: if(reader.read(buf, head_size)<head_size)
1.57 parser 132: throw Exception(0, 0,
1.1 paf 133: origin_string,
1.34 parser 134: "not GIF file - too small");
1.31 parser 135: GIF_Header *head=(GIF_Header *)buf;
1.1 paf 136:
1.31 parser 137: if(strncmp(head->type, "GIF", 3)!=0)
1.57 parser 138: throw Exception(0, 0,
1.1 paf 139: origin_string,
1.44 parser 140: "not GIF file - wrong signature");
1.1 paf 141:
1.33 parser 142: width=little_endian_to_int(head->width);
143: height=little_endian_to_int(head->height);
1.1 paf 144: }
145:
1.58 parser 146: /// @test remove ugly mech in reader - 20K limit
1.1 paf 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.57 parser 157: throw Exception(0, 0,
1.1 paf 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.57 parser 163: throw Exception(0, 0,
1.1 paf 164: origin_string,
1.44 parser 165: "not JPEG file - wrong signature");
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.57 parser 198: throw Exception(0, 0,
1.16 paf 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) {
1.60 paf 207: if(const char *cext=strrchr(file_name.cstr(String::UL_FILE_SPEC), '.')) {
1.1 paf 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
1.57 parser 214: throw Exception(0, 0,
1.1 paf 215: &file_name,
216: "unhandled image file name extension '%s'", cext);
217: } else
1.57 parser 218: throw Exception(0, 0,
1.1 paf 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:
1.49 parser 298: // skip user-specified and internal(starting with "line-") attributes
299: if(ai.skip && ai.skip->get(key) || key.pos("line-")==0)
1.4 paf 300: return;
301:
1.3 paf 302: Value& value=*static_cast<Value *>(val);
303: // src="a.gif" width=123 ismap[=-1]
1.4 paf 304: *ai.tag << " " << key;
1.26 parser 305: if(value.is_string() || value.as_int()>=0)
1.6 paf 306: *ai.tag << "=\"" << value.as_string() << "\"";
1.3 paf 307: }
1.17 paf 308: static void _html(Request& r, const String& method_name, MethodParams *params) {
1.3 paf 309: Pool& pool=r.pool();
310:
311: String tag(pool);
312: tag << "<img";
1.4 paf 313:
1.18 paf 314: const Hash& fields=static_cast<VImage *>(r.self)->fields();
1.5 paf 315: Hash *attribs=0;
1.4 paf 316:
1.39 parser 317: if(params->size()) {
1.52 parser 318: Value &vattribs=r.process(params->get(0),
319: 0/*no name*/,
320: false/*don't intercept string*/);
1.39 parser 321: if(vattribs.is_defined()) // allow 'void'
1.59 parser 322: if(attribs=vattribs.get_hash(&method_name)) {
1.39 parser 323: Attrib_info attrib_info={&tag, 0};
324: attribs->for_each(append_attrib_pair, &attrib_info);
325: } else
1.57 parser 326: throw Exception(0, 0,
1.39 parser 327: &method_name,
328: "attributes must be hash");
329: }
1.4 paf 330:
1.5 paf 331: Attrib_info attrib_info={&tag, attribs};
1.4 paf 332: fields.for_each(append_attrib_pair, &attrib_info);
1.6 paf 333: tag << " />";
1.3 paf 334: r.write_pass_lang(tag);
335: }
1.8 paf 336:
1.16 paf 337: static gdImage *load(Request& r, const String& method_name,
338: const String& file_name){
339: Pool& pool=r.pool();
340:
1.42 parser 341: const char *file_name_cstr=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
1.16 paf 342: if(FILE *f=fopen(file_name_cstr, "rb")) {
343: gdImage& image=*new(pool) gdImage(pool);
1.23 paf 344: bool ok=image.CreateFromGif(f);
1.16 paf 345: fclose(f);
1.23 paf 346: if(!ok)
1.57 parser 347: throw Exception(0, 0,
1.23 paf 348: &file_name,
349: "is not in GIF format");
1.16 paf 350: return ℑ
351: } else {
1.57 parser 352: throw Exception(0, 0,
1.16 paf 353: &method_name,
354: "can not open '%s'", file_name_cstr);
355: return 0;
356: }
357: }
358:
359:
1.17 paf 360: static void _load(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 361: Pool& pool=r.pool();
362:
1.44 parser 363: const String& file_name=params->as_string(0, "file name must not be code");
1.6 paf 364:
1.16 paf 365: gdImage& image=*load(r, method_name, file_name);
366: int width=image.SX();
367: int height=image.SY();
368: static_cast<VImage *>(r.self)->set(&file_name, width, height, &image);
1.6 paf 369: }
370:
1.17 paf 371: static void _create(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 372: Pool& pool=r.pool();
373:
1.51 parser 374: int width=params->as_int(0, "width must be int", r);
375: int height=params->as_int(1, "height must be int", r);
1.8 paf 376: int bgcolor_value=0xffFFff;
1.6 paf 377: if(params->size()>2)
1.51 parser 378: bgcolor_value=params->as_int(2, "color must be int", r);
1.15 paf 379: gdImage& image=*new(pool) gdImage(pool);
380: image.Create(width, height);
381: image.FilledRectangle(0, 0, width-1, height-1, image.Color(bgcolor_value));
382: static_cast<VImage *>(r.self)->set(0, width, height, &image);
1.6 paf 383: }
384:
1.17 paf 385: static void _gif(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 386: Pool& pool=r.pool();
387:
1.9 paf 388: gdImage *image=static_cast<VImage *>(r.self)->image;
1.8 paf 389: if(!image)
1.57 parser 390: throw Exception(0, 0,
1.16 paf 391: &method_name,
1.12 paf 392: "does not contain an image");
1.6 paf 393:
394: // could _ but don't thing it's wise to use $image.src for vfile.name
1.10 paf 395:
1.16 paf 396: String out(pool); image->Gif(out);
1.6 paf 397:
398: VFile& vfile=*new(pool) VFile(pool);
1.41 parser 399: Value *content_type=new(pool) VString(*new(pool) String(pool, "image/gif"));
1.20 paf 400: vfile.set(false/*not tainted*/,
1.61 paf 401: out.cstr(), out.size(), 0, content_type);
1.6 paf 402:
403: r.write_no_lang(vfile);
404: }
405:
1.17 paf 406: static void _line(Request& r, const String& method_name, MethodParams *params) {
1.12 paf 407: Pool& pool=r.pool();
408:
409: gdImage *image=static_cast<VImage *>(r.self)->image;
410: if(!image)
1.57 parser 411: throw Exception(0, 0,
1.16 paf 412: &method_name,
1.12 paf 413: "does not contain an image");
414:
415: image->Line(
1.51 parser 416: params->as_int(0, "x0 must be int", r),
417: params->as_int(1, "y0 must be int", r),
418: params->as_int(2, "x1 must be int", r),
419: params->as_int(3, "y1 must be int", r),
420: image->Color(params->as_int(4, "color must be int", r)));
1.13 paf 421: }
422:
1.17 paf 423: static void _fill(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 424: Pool& pool=r.pool();
425:
426: gdImage *image=static_cast<VImage *>(r.self)->image;
427: if(!image)
1.57 parser 428: throw Exception(0, 0,
1.16 paf 429: &method_name,
1.13 paf 430: "does not contain an image");
1.12 paf 431:
1.13 paf 432: image->Fill(
1.51 parser 433: params->as_int(0, "x must be int", r),
434: params->as_int(1, "y must be int", r),
435: image->Color(params->as_int(2, "color must be int", r)));
1.13 paf 436: }
437:
1.17 paf 438: static void _rectangle(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 439: Pool& pool=r.pool();
440:
441: gdImage *image=static_cast<VImage *>(r.self)->image;
442: if(!image)
1.57 parser 443: throw Exception(0, 0,
1.16 paf 444: &method_name,
1.13 paf 445: "does not contain an image");
446:
447: image->Rectangle(
1.51 parser 448: params->as_int(0, "x0 must be int", r),
449: params->as_int(1, "y0 must be int", r),
450: params->as_int(2, "x1 must be int", r),
451: params->as_int(3, "y1 must be int", r),
452: image->Color(params->as_int(4, "color must be int", r)));
1.13 paf 453: }
454:
1.17 paf 455: static void _bar(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 456: Pool& pool=r.pool();
457:
458: gdImage *image=static_cast<VImage *>(r.self)->image;
459: if(!image)
1.57 parser 460: throw Exception(0, 0,
1.16 paf 461: &method_name,
1.13 paf 462: "does not contain an image");
463:
464: image->FilledRectangle(
1.51 parser 465: params->as_int(0, "x0 must be int", r),
466: params->as_int(1, "y0 must be int", r),
467: params->as_int(2, "x1 must be int", r),
468: params->as_int(3, "y1 must be int", r),
469: image->Color(params->as_int(4, "color must be int", r)));
1.13 paf 470: }
471:
1.44 parser 472: #ifndef DOXYGEN
473: static void add_point(Array::Item *value, void *info) {
474: Array& row=*static_cast<Array *>(value);
475: gdImage::Point **p=static_cast<gdImage::Point **>(info);
476:
477: (**p).x=row.get_string(0)->as_int();
478: (**p).y=row.get_string(1)->as_int();
479: (*p)++;
480: }
481: #endif
1.17 paf 482: static void _replace(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 483: Pool& pool=r.pool();
484:
485: gdImage *image=static_cast<VImage *>(r.self)->image;
486: if(!image)
1.57 parser 487: throw Exception(0, 0,
1.16 paf 488: &method_name,
1.13 paf 489: "does not contain an image");
490:
1.44 parser 491: Table *table=params->as_no_junction(2, "coordinates must not be code").get_table();
492: if(!table)
1.57 parser 493: throw Exception(0, 0,
1.44 parser 494: &method_name,
495: "coordinates must be table");
1.13 paf 496:
1.44 parser 497: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
498: gdImage::Point *add_p=all_p;
499: table->for_each(add_point, &add_p);
500: image->FilledPolygonReplaceColor(all_p, table->size(),
1.51 parser 501: image->Color(params->as_int(0, "src color must be int", r)),
502: image->Color(params->as_int(1, "dest color must be int", r)));
1.13 paf 503: }
504:
1.44 parser 505: static void _polyline(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 506: Pool& pool=r.pool();
507:
508: gdImage *image=static_cast<VImage *>(r.self)->image;
509: if(!image)
1.57 parser 510: throw Exception(0, 0,
1.16 paf 511: &method_name,
1.13 paf 512: "does not contain an image");
513:
1.44 parser 514: Table *table=params->as_no_junction(1, "coordinates must not be code").get_table();
515: if(!table)
1.57 parser 516: throw Exception(0, 0,
1.44 parser 517: &method_name,
518: "coordinates must be table");
519:
520: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
521: gdImage::Point *add_p=all_p;
522: table->for_each(add_point, &add_p);
523: image->Polygon(all_p, table->size(),
1.51 parser 524: image->Color(params->as_int(0, "color must be int", r)),
1.44 parser 525: false/*not closed*/);
526: }
527:
528: static void _polygon(Request& r, const String& method_name, MethodParams *params) {
529: Pool& pool=r.pool();
530:
531: gdImage *image=static_cast<VImage *>(r.self)->image;
532: if(!image)
1.57 parser 533: throw Exception(0, 0,
1.16 paf 534: &method_name,
1.44 parser 535: "does not contain an image");
1.13 paf 536:
1.44 parser 537: Table *table=params->as_no_junction(1, "coordinates must not be code").get_table();
538: if(!table)
1.57 parser 539: throw Exception(0, 0,
1.44 parser 540: &method_name,
541: "coordinates must be table");
542:
543: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
544: gdImage::Point *add_p=all_p;
545: table->for_each(add_point, &add_p);
546: image->Polygon(all_p, table->size(),
1.51 parser 547: image->Color(params->as_int(0, "color must be int", r)));
1.13 paf 548: }
549:
1.17 paf 550: static void _polybar(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 551: Pool& pool=r.pool();
552:
553: gdImage *image=static_cast<VImage *>(r.self)->image;
554: if(!image)
1.57 parser 555: throw Exception(0, 0,
1.16 paf 556: &method_name,
1.13 paf 557: "does not contain an image");
558:
1.44 parser 559: Table *table=params->as_no_junction(1, "coordinates must not be code").get_table();
560: if(!table)
1.57 parser 561: throw Exception(0, 0,
1.44 parser 562: &method_name,
563: "coordinates must be table");
1.13 paf 564:
1.44 parser 565: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
566: gdImage::Point *add_p=all_p;
567: table->for_each(add_point, &add_p);
568: image->FilledPolygon(all_p, table->size(),
1.51 parser 569: image->Color(params->as_int(0, "color must be int", r)));
1.12 paf 570: }
571:
1.16 paf 572: // font
573:
574: #define Y(y)(y+index*height+1)
1.21 paf 575:
576: /// simple gdImage-based font storage & text output
1.16 paf 577: class Font : public Pooled {
578: public:
579:
1.38 parser 580: const static int letter_spacing;
1.35 parser 581: int height; ///< Font heigth
582: int monospace; ///< Default char width
583: int spacebarspace; ///< spacebar width
1.16 paf 584: gdImage& ifont;
585: const String& alphabet;
586:
587: Font(Pool& pool,
588: const String& aalphabet,
1.35 parser 589: gdImage& aifont, int aheight, int amonospace, int aspacebarspace) : Pooled(pool),
1.16 paf 590: alphabet(aalphabet),
1.35 parser 591: height(aheight), monospace(amonospace), spacebarspace(aspacebarspace),
1.16 paf 592: ifont(aifont) {
593: }
594:
595: /* ******************************** char ********************************** */
596:
597: int index_of(char ch) {
598: if(ch==' ') return -1;
599: return alphabet.pos(&ch, 1);
600: }
601:
602: int index_width(int index) {
603: if(index<0)
1.35 parser 604: return spacebarspace;
1.16 paf 605: int tr=ifont.GetTransparent();
1.35 parser 606: for(int x=ifont.SX()-1; x>=0; x--) {
1.16 paf 607: for(int y=0; y<height-1; y++)
608: if(ifont.GetPixel(x, Y(y))!=tr)
1.35 parser 609: return x+1;
1.16 paf 610: }
611: return 0;
612: }
613:
614: void index_display(gdImage& image, int x, int y, int index){
615: if(index>=0)
616: ifont.Copy(image, x, y, 0, Y(0), index_width(index), height-1);
617: }
618:
619: /* ******************************** string ********************************** */
1.47 parser 620:
621: int string_width(const String& s){
1.61 paf 622: const char *cstr=s.cstr();
1.16 paf 623: int result=0;
624: for(; *cstr; cstr++)
625: result+=index_width(index_of(*cstr));
626: return result;
627: }
628:
629: void string_display(gdImage& image, int x, int y, const String& s){
1.61 paf 630: const char *cstr=s.cstr();
1.16 paf 631: if(cstr) for(; *cstr; cstr++) {
632: int index=index_of(*cstr);
633: index_display(image, x, y, index);
1.38 parser 634: x+=letter_spacing + (monospace ? monospace : index_width(index));
1.16 paf 635: }
636: }
637:
638: };
1.38 parser 639: const int Font::letter_spacing=1;
1.35 parser 640:
1.17 paf 641: static void _font(Request& r, const String& method_name, MethodParams *params) {
1.16 paf 642: Pool& pool=r.pool();
643:
1.37 parser 644: const String& alphabet=params->as_string(0, "alphabet must not be code");
645: gdImage& image=*load(r, method_name, params->as_string(1, "file_name must not be code"));
1.51 parser 646: int spacebar_width=params->as_int(2, "spacebar_width must be int", r);
1.37 parser 647: int monospace_width;
648: if(params->size()>3) {
1.51 parser 649: monospace_width=params->as_int(3, "monospace_width must be int", r);
1.37 parser 650: if(!monospace_width)
651: monospace_width=image.SX();
652: } else
653: monospace_width=0;
1.16 paf 654:
1.37 parser 655: if(!alphabet.size())
1.57 parser 656: throw Exception(0, 0,
1.37 parser 657: &method_name,
658: "alphabet must not be empty");
659:
1.16 paf 660: static_cast<VImage *>(r.self)->font=new(pool) Font(pool,
1.37 parser 661: alphabet,
1.36 parser 662: image,
1.37 parser 663: image.SY() / alphabet.size(), monospace_width, spacebar_width);
1.16 paf 664: }
665:
1.17 paf 666: static void _text(Request& r, const String& method_name, MethodParams *params) {
1.16 paf 667: Pool& pool=r.pool();
668:
1.51 parser 669: int x=params->as_int(0, "x must be int", r);
670: int y=params->as_int(1, "y must be int", r);
1.36 parser 671: const String& s=params->as_string(2, "text must not be code");
1.16 paf 672:
673: VImage& vimage=*static_cast<VImage *>(r.self);
674: if(vimage.image)
675: if(vimage.font)
676: vimage.font->string_display(*vimage.image, x, y, s);
677: else
1.57 parser 678: throw Exception(0, 0,
1.16 paf 679: &method_name,
680: "set the font first");
681: else
1.57 parser 682: throw Exception(0, 0,
1.16 paf 683: &method_name,
684: "does not contain an image");
685: }
686:
1.47 parser 687: static void _length(Request& r, const String& method_name, MethodParams *params) {
688: Pool& pool=r.pool();
689:
690: const String& s=params->as_string(0, "text must not be code");
691:
692: VImage& vimage=*static_cast<VImage *>(r.self);
693: if(vimage.image)
694: if(vimage.font) {
695: VInt& result=*new(pool) VInt(pool, vimage.font->string_width(s));
696: result.set_name(method_name);
697: r.write_assign_lang(result);
698: } else
1.57 parser 699: throw Exception(0, 0,
1.47 parser 700: &method_name,
701: "set the font first");
702: else
1.57 parser 703: throw Exception(0, 0,
1.47 parser 704: &method_name,
705: "does not contain an image");
706: }
707:
1.48 parser 708: static void _arc(Request& r, const String& method_name, MethodParams *params) {
709: Pool& pool=r.pool();
710:
711: gdImage *image=static_cast<VImage *>(r.self)->image;
712: if(!image)
1.57 parser 713: throw Exception(0, 0,
1.48 parser 714: &method_name,
715: "does not contain an image");
716:
717: image->Arc(
1.51 parser 718: params->as_int(0, "center_x must be int", r),
719: params->as_int(1, "center_y must be int", r),
720: params->as_int(2, "width must be int", r),
721: params->as_int(3, "height must be int", r),
722: params->as_int(4, "start degrees must be int", r),
723: params->as_int(5, "end degrees must be int", r),
724: image->Color(params->as_int(6, "cx must be int", r)));
1.48 parser 725: }
726:
1.49 parser 727: static void _sector(Request& r, const String& method_name, MethodParams *params) {
728: Pool& pool=r.pool();
729:
730: gdImage *image=static_cast<VImage *>(r.self)->image;
731: if(!image)
1.57 parser 732: throw Exception(0, 0,
1.49 parser 733: &method_name,
734: "does not contain an image");
735:
736: image->Sector(
1.51 parser 737: params->as_int(0, "center_x must be int", r),
738: params->as_int(1, "center_y must be int", r),
739: params->as_int(2, "width must be int", r),
740: params->as_int(3, "height must be int", r),
741: params->as_int(4, "start degrees must be int", r),
742: params->as_int(5, "end degrees must be int", r),
743: image->Color(params->as_int(6, "color must be int", r)));
1.49 parser 744: }
745:
1.48 parser 746: static void _circle(Request& r, const String& method_name, MethodParams *params) {
747: Pool& pool=r.pool();
748:
749: gdImage *image=static_cast<VImage *>(r.self)->image;
750: if(!image)
1.57 parser 751: throw Exception(0, 0,
1.48 parser 752: &method_name,
753: "does not contain an image");
754:
1.51 parser 755: int size=params->as_int(2, "radius must be int", r)*2;
1.48 parser 756: image->Arc(
1.51 parser 757: params->as_int(0, "center_x must be int", r),
758: params->as_int(1, "center_y must be int", r),
1.50 parser 759: size, //w
760: size, //h
1.48 parser 761: 0, //s
762: 360, //e
1.51 parser 763: image->Color(params->as_int(3, "color must be int", r)));
1.48 parser 764: }
765:
1.53 parser 766: gdImage& as_image(Pool& pool, const String& method_name, MethodParams *params,
767: int index, const char *msg) {
768: Value& value=params->as_no_junction(index, msg);
769:
770: if(strcmp(value.type(), VIMAGE_TYPE)!=0)
1.57 parser 771: throw Exception(0, 0,
1.53 parser 772: &method_name,
773: msg);
774:
775: gdImage *src=static_cast<VImage *>(&value)->image;
776: if(!src)
1.57 parser 777: throw Exception(0, 0,
1.53 parser 778: &method_name,
779: msg);
780:
781: return *src;
782: }
783:
784: static void _copy(Request& r, const String& method_name, MethodParams *params) {
785: Pool& pool=r.pool();
786:
787: gdImage *dest=static_cast<VImage *>(r.self)->image;
788: if(!dest)
1.57 parser 789: throw Exception(0, 0,
1.53 parser 790: &method_name,
791: "self does not contain an image");
792:
793: gdImage& src=as_image(pool, method_name, params, 0, "src must be image");
794:
795: int sx=params->as_int(1, "src_x must be int", r);
796: int sy=params->as_int(2, "src_y must be int", r);
797: int sw=params->as_int(3, "src_w must be int", r);
798: int sh=params->as_int(4, "src_h must be int", r);
799: int dx=params->as_int(5, "dest_x must be int", r);
800: int dy=params->as_int(6, "dest_y must be int", r);
801: if(params->size()>1+2+2+2) {
802: int dw=params->as_int(1+2+2+2, "dest_w must be int", r);
1.56 parser 803: int dh=(int)(params->size()>1+2+2+2+1?
804: params->as_int(1+2+2+2+1, "dest_h must be int", r):sh*(((double)dw)/((double)sw)));
805: int tolerance=params->size()>1+2+2+2+2?
806: params->as_int(1+2+2+2+2, "tolerance must be int", r):150;
1.53 parser 807:
1.56 parser 808: src.CopyResampled(*dest, dx, dy, sx, sy, dw, dh, sw, sh, tolerance);
1.53 parser 809: } else
1.54 parser 810: src.Copy(*dest, dx, dy, sx, sy, sw, sh);
1.53 parser 811: }
812:
813:
1.22 paf 814: // constructor
815:
816: MImage::MImage(Pool& apool) : Methoded(apool) {
817: set_name(*NEW String(pool(), IMAGE_CLASS_NAME));
818:
819:
1.1 paf 820: // ^image:measure[DATA]
1.22 paf 821: add_native_method("measure", Method::CT_DYNAMIC, _measure, 1, 1);
1.3 paf 822:
1.25 paf 823: // ^image.html[]
824: // ^image.html[hash]
1.22 paf 825: add_native_method("html", Method::CT_DYNAMIC, _html, 0, 1);
1.6 paf 826:
1.25 paf 827: // ^image.load[background.gif]
1.22 paf 828: add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
1.6 paf 829:
1.25 paf 830: // ^image.create[width;height] bgcolor=white
831: // ^image.create[width;height;bgcolor]
1.22 paf 832: add_native_method("create", Method::CT_DYNAMIC, _create, 2, 3);
1.6 paf 833:
1.25 paf 834: // ^image.gif[]
1.22 paf 835: add_native_method("gif", Method::CT_DYNAMIC, _gif, 0, 0);
1.12 paf 836:
1.25 paf 837: // ^image.line(x0;y0;x1;y1;color)
1.22 paf 838: add_native_method("line", Method::CT_DYNAMIC, _line, 5, 5);
1.13 paf 839:
1.25 paf 840: // ^image.fill(x;y;color)
1.22 paf 841: add_native_method("fill", Method::CT_DYNAMIC, _fill, 3, 3);
1.13 paf 842:
1.25 paf 843: // ^image.rectangle(x0;y0;x1;y1;color)
1.22 paf 844: add_native_method("rectangle", Method::CT_DYNAMIC, _rectangle, 5, 5);
1.13 paf 845:
1.25 paf 846: // ^image.bar(x0;y0;x1;y1;color)
1.22 paf 847: add_native_method("bar", Method::CT_DYNAMIC, _bar, 5, 5);
1.13 paf 848:
1.44 parser 849: // ^image.replace(color-source;color-dest)[table x:y]
850: add_native_method("replace", Method::CT_DYNAMIC, _replace, 3, 3);
851:
852: // ^image.polyline(color)[table x:y]
853: add_native_method("polyline", Method::CT_DYNAMIC, _polyline, 2, 2);
1.13 paf 854:
1.44 parser 855: // ^image.polygon(color)[table x:y]
856: add_native_method("polygon", Method::CT_DYNAMIC, _polygon, 2, 2);
1.13 paf 857:
1.44 parser 858: // ^image.polybar(color)[table x:y]
859: add_native_method("polybar", Method::CT_DYNAMIC, _polybar, 2, 2);
1.13 paf 860:
1.36 parser 861: // ^image.font[alPHAbet;font-file-name.gif](spacebar_width)
862: // ^image.font[alPHAbet;font-file-name.gif](spacebar_width;width)
863: add_native_method("font", Method::CT_DYNAMIC, _font, 3, 4);
1.16 paf 864:
1.25 paf 865: // ^image.text(x;y)[text]
1.22 paf 866: add_native_method("text", Method::CT_DYNAMIC, _text, 3, 3);
1.47 parser 867:
868: // ^image.ngth[text]
869: add_native_method("length", Method::CT_DYNAMIC, _length, 1, 1);
1.16 paf 870:
1.48 parser 871: // ^image.arc(center x;center y;width;height;start in degrees;end in degrees;color)
872: add_native_method("arc", Method::CT_DYNAMIC, _arc, 7, 7);
1.49 parser 873:
874: // ^image.sector(center x;center y;width;height;start in degrees;end in degrees;color)
875: add_native_method("sector", Method::CT_DYNAMIC, _sector, 7, 7);
1.48 parser 876:
877: // ^image.circle(center x;center y;r;color)
878: add_native_method("circle", Method::CT_DYNAMIC, _circle, 4, 4);
879:
1.56 parser 880: // ^image.copy[source](src x;src y;src w;src h;dst x;dst y[;dest w[;dest h[;tolerance]]])
881: add_native_method("copy", Method::CT_DYNAMIC, _copy, 1+2+2+2, (1+2+2+2)+2+1);
1.22 paf 882: }
883:
884: // global variable
885:
886: Methoded *image_class;
887:
888: // creator
889:
890: Methoded *MImage_create(Pool& pool) {
891: return image_class=new(pool) MImage(pool);
1.1 paf 892: }
E-mail: