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