Annotation of parser3/src/classes/image.C, revision 1.44
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.31 parser 7: */
1.44 ! parser 8: static const char *RCSId="$Id: image.C,v 1.43 2001/09/15 11:48:41 parser Exp $";
1.31 parser 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.31 parser 51: enum { READ_CHUNK_SIZE=0x400*10 };// 10K
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:
296: if(ai.skip && ai.skip->get(key))
297: return;
298:
1.3 paf 299: Value& value=*static_cast<Value *>(val);
300: // src="a.gif" width=123 ismap[=-1]
1.4 paf 301: *ai.tag << " " << key;
1.26 parser 302: if(value.is_string() || value.as_int()>=0)
1.6 paf 303: *ai.tag << "=\"" << value.as_string() << "\"";
1.3 paf 304: }
1.17 paf 305: static void _html(Request& r, const String& method_name, MethodParams *params) {
1.3 paf 306: Pool& pool=r.pool();
307:
308: String tag(pool);
309: tag << "<img";
1.4 paf 310:
1.18 paf 311: const Hash& fields=static_cast<VImage *>(r.self)->fields();
1.5 paf 312: Hash *attribs=0;
1.4 paf 313:
1.39 parser 314: if(params->size()) {
315: Value &vattribs=params->get(0);
316: if(vattribs.is_defined()) // allow 'void'
317: if(Hash *attribs=vattribs.get_hash()) {
318: Attrib_info attrib_info={&tag, 0};
319: attribs->for_each(append_attrib_pair, &attrib_info);
320: } else
321: PTHROW(0, 0,
322: &method_name,
323: "attributes must be hash");
324: }
1.4 paf 325:
1.5 paf 326: Attrib_info attrib_info={&tag, attribs};
1.4 paf 327: fields.for_each(append_attrib_pair, &attrib_info);
1.6 paf 328: tag << " />";
1.3 paf 329: r.write_pass_lang(tag);
330: }
1.8 paf 331:
1.16 paf 332: static gdImage *load(Request& r, const String& method_name,
333: const String& file_name){
334: Pool& pool=r.pool();
335:
1.42 parser 336: const char *file_name_cstr=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
1.16 paf 337: if(FILE *f=fopen(file_name_cstr, "rb")) {
338: gdImage& image=*new(pool) gdImage(pool);
1.23 paf 339: bool ok=image.CreateFromGif(f);
1.16 paf 340: fclose(f);
1.23 paf 341: if(!ok)
342: PTHROW(0, 0,
343: &file_name,
344: "is not in GIF format");
1.16 paf 345: return ℑ
346: } else {
347: PTHROW(0, 0,
348: &method_name,
349: "can not open '%s'", file_name_cstr);
350: return 0;
351: }
352: }
353:
354:
1.17 paf 355: static void _load(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 356: Pool& pool=r.pool();
357:
1.44 ! parser 358: const String& file_name=params->as_string(0, "file name must not be code");
1.6 paf 359:
1.16 paf 360: gdImage& image=*load(r, method_name, file_name);
361: int width=image.SX();
362: int height=image.SY();
363: static_cast<VImage *>(r.self)->set(&file_name, width, height, &image);
1.6 paf 364: }
365:
1.17 paf 366: static void _create(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 367: Pool& pool=r.pool();
368:
1.36 parser 369: int width=params->as_int(0, r);
370: int height=params->as_int(1, r);
1.8 paf 371: int bgcolor_value=0xffFFff;
1.6 paf 372: if(params->size()>2)
1.36 parser 373: bgcolor_value=params->as_int(2, r);
1.15 paf 374: gdImage& image=*new(pool) gdImage(pool);
375: image.Create(width, height);
376: image.FilledRectangle(0, 0, width-1, height-1, image.Color(bgcolor_value));
377: static_cast<VImage *>(r.self)->set(0, width, height, &image);
1.6 paf 378: }
379:
1.17 paf 380: static void _gif(Request& r, const String& method_name, MethodParams *params) {
1.6 paf 381: Pool& pool=r.pool();
382:
1.9 paf 383: gdImage *image=static_cast<VImage *>(r.self)->image;
1.8 paf 384: if(!image)
1.16 paf 385: PTHROW(0, 0,
386: &method_name,
1.12 paf 387: "does not contain an image");
1.6 paf 388:
389: // could _ but don't thing it's wise to use $image.src for vfile.name
1.10 paf 390:
1.16 paf 391: String out(pool); image->Gif(out);
1.6 paf 392:
393: VFile& vfile=*new(pool) VFile(pool);
1.41 parser 394: Value *content_type=new(pool) VString(*new(pool) String(pool, "image/gif"));
1.20 paf 395: vfile.set(false/*not tainted*/,
1.41 parser 396: out.cstr(String::UL_AS_IS), out.size(), 0, content_type);
1.6 paf 397:
398: r.write_no_lang(vfile);
399: }
400:
1.17 paf 401: static void _line(Request& r, const String& method_name, MethodParams *params) {
1.12 paf 402: Pool& pool=r.pool();
403:
404: gdImage *image=static_cast<VImage *>(r.self)->image;
405: if(!image)
1.16 paf 406: PTHROW(0, 0,
407: &method_name,
1.12 paf 408: "does not contain an image");
409:
410: image->Line(
1.36 parser 411: params->as_int(0, r),
412: params->as_int(1, r),
413: params->as_int(2, r),
414: params->as_int(3, r),
415: image->Color(params->as_int(4, r)));
1.13 paf 416: }
417:
1.17 paf 418: static void _fill(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 419: Pool& pool=r.pool();
420:
421: gdImage *image=static_cast<VImage *>(r.self)->image;
422: if(!image)
1.16 paf 423: PTHROW(0, 0,
424: &method_name,
1.13 paf 425: "does not contain an image");
1.12 paf 426:
1.13 paf 427: image->Fill(
1.36 parser 428: params->as_int(0, r),
429: params->as_int(1, r),
430: image->Color(params->as_int(2, r)));
1.13 paf 431: }
432:
1.17 paf 433: static void _rectangle(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 434: Pool& pool=r.pool();
435:
436: gdImage *image=static_cast<VImage *>(r.self)->image;
437: if(!image)
1.16 paf 438: PTHROW(0, 0,
439: &method_name,
1.13 paf 440: "does not contain an image");
441:
442: image->Rectangle(
1.36 parser 443: params->as_int(0, r),
444: params->as_int(1, r),
445: params->as_int(2, r),
446: params->as_int(3, r),
447: image->Color(params->as_int(4, r)));
1.13 paf 448: }
449:
1.17 paf 450: static void _bar(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 451: Pool& pool=r.pool();
452:
453: gdImage *image=static_cast<VImage *>(r.self)->image;
454: if(!image)
1.16 paf 455: PTHROW(0, 0,
456: &method_name,
1.13 paf 457: "does not contain an image");
458:
459: image->FilledRectangle(
1.36 parser 460: params->as_int(0, r),
461: params->as_int(1, r),
462: params->as_int(2, r),
463: params->as_int(3, r),
464: image->Color(params->as_int(4, r)));
1.13 paf 465: }
466:
1.44 ! parser 467: #ifndef DOXYGEN
! 468: static void add_point(Array::Item *value, void *info) {
! 469: Array& row=*static_cast<Array *>(value);
! 470: gdImage::Point **p=static_cast<gdImage::Point **>(info);
! 471:
! 472: (**p).x=row.get_string(0)->as_int();
! 473: (**p).y=row.get_string(1)->as_int();
! 474: (*p)++;
! 475: }
! 476: #endif
1.17 paf 477: static void _replace(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 478: Pool& pool=r.pool();
479:
480: gdImage *image=static_cast<VImage *>(r.self)->image;
481: if(!image)
1.16 paf 482: PTHROW(0, 0,
483: &method_name,
1.13 paf 484: "does not contain an image");
485:
1.44 ! parser 486: Table *table=params->as_no_junction(2, "coordinates must not be code").get_table();
! 487: if(!table)
! 488: PTHROW(0, 0,
! 489: &method_name,
! 490: "coordinates must be table");
1.13 paf 491:
1.44 ! parser 492: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
! 493: gdImage::Point *add_p=all_p;
! 494: table->for_each(add_point, &add_p);
! 495: image->FilledPolygonReplaceColor(all_p, table->size(),
1.36 parser 496: image->Color(params->as_int(0, r)), // src color
497: image->Color(params->as_int(1, r)));// dest color
1.13 paf 498: }
499:
1.44 ! parser 500: static void _polyline(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 501: Pool& pool=r.pool();
502:
503: gdImage *image=static_cast<VImage *>(r.self)->image;
504: if(!image)
1.16 paf 505: PTHROW(0, 0,
506: &method_name,
1.13 paf 507: "does not contain an image");
508:
1.44 ! parser 509: Table *table=params->as_no_junction(1, "coordinates must not be code").get_table();
! 510: if(!table)
! 511: PTHROW(0, 0,
! 512: &method_name,
! 513: "coordinates must be table");
! 514:
! 515: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
! 516: gdImage::Point *add_p=all_p;
! 517: table->for_each(add_point, &add_p);
! 518: image->Polygon(all_p, table->size(),
! 519: image->Color(params->as_int(0, r)),
! 520: false/*not closed*/);
! 521: }
! 522:
! 523: static void _polygon(Request& r, const String& method_name, MethodParams *params) {
! 524: Pool& pool=r.pool();
! 525:
! 526: gdImage *image=static_cast<VImage *>(r.self)->image;
! 527: if(!image)
1.16 paf 528: PTHROW(0, 0,
529: &method_name,
1.44 ! parser 530: "does not contain an image");
1.13 paf 531:
1.44 ! parser 532: Table *table=params->as_no_junction(1, "coordinates must not be code").get_table();
! 533: if(!table)
! 534: PTHROW(0, 0,
! 535: &method_name,
! 536: "coordinates must be table");
! 537:
! 538: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
! 539: gdImage::Point *add_p=all_p;
! 540: table->for_each(add_point, &add_p);
! 541: image->Polygon(all_p, table->size(),
1.36 parser 542: image->Color(params->as_int(0, r)));
1.13 paf 543: }
544:
1.17 paf 545: static void _polybar(Request& r, const String& method_name, MethodParams *params) {
1.13 paf 546: Pool& pool=r.pool();
547:
548: gdImage *image=static_cast<VImage *>(r.self)->image;
549: if(!image)
1.16 paf 550: PTHROW(0, 0,
551: &method_name,
1.13 paf 552: "does not contain an image");
553:
1.44 ! parser 554: Table *table=params->as_no_junction(1, "coordinates must not be code").get_table();
! 555: if(!table)
! 556: PTHROW(0, 0,
! 557: &method_name,
! 558: "coordinates must be table");
1.13 paf 559:
1.44 ! parser 560: gdImage::Point *all_p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*table->size());
! 561: gdImage::Point *add_p=all_p;
! 562: table->for_each(add_point, &add_p);
! 563: image->FilledPolygon(all_p, table->size(),
1.36 parser 564: image->Color(params->as_int(0, r)));
1.12 paf 565: }
566:
1.16 paf 567: // font
568:
569: #define Y(y)(y+index*height+1)
1.21 paf 570:
571: /// simple gdImage-based font storage & text output
1.16 paf 572: class Font : public Pooled {
573: public:
574:
1.38 parser 575: const static int letter_spacing;
1.35 parser 576: int height; ///< Font heigth
577: int monospace; ///< Default char width
578: int spacebarspace; ///< spacebar width
1.16 paf 579: gdImage& ifont;
580: const String& alphabet;
581:
582: Font(Pool& pool,
583: const String& aalphabet,
1.35 parser 584: gdImage& aifont, int aheight, int amonospace, int aspacebarspace) : Pooled(pool),
1.16 paf 585: alphabet(aalphabet),
1.35 parser 586: height(aheight), monospace(amonospace), spacebarspace(aspacebarspace),
1.16 paf 587: ifont(aifont) {
588: }
589:
590: /* ******************************** char ********************************** */
591:
592: int index_of(char ch) {
593: if(ch==' ') return -1;
594: return alphabet.pos(&ch, 1);
595: }
596:
597: int index_width(int index) {
598: if(index<0)
1.35 parser 599: return spacebarspace;
1.16 paf 600: int tr=ifont.GetTransparent();
1.35 parser 601: for(int x=ifont.SX()-1; x>=0; x--) {
1.16 paf 602: for(int y=0; y<height-1; y++)
603: if(ifont.GetPixel(x, Y(y))!=tr)
1.35 parser 604: return x+1;
1.16 paf 605: }
606: return 0;
607: }
608:
609: void index_display(gdImage& image, int x, int y, int index){
610: if(index>=0)
611: ifont.Copy(image, x, y, 0, Y(0), index_width(index), height-1);
612: }
613:
614: /* ******************************** string ********************************** */
615: /*
616: int string_width(const char *cstr){
617: int result=0;
618: for(; *cstr; cstr++)
619: result+=index_width(index_of(*cstr));
620: return result;
621: }
622: */
623:
624: void string_display(gdImage& image, int x, int y, const String& s){
625: const char *cstr=s.cstr(String::UL_AS_IS);
626: if(cstr) for(; *cstr; cstr++) {
627: int index=index_of(*cstr);
628: index_display(image, x, y, index);
1.38 parser 629: x+=letter_spacing + (monospace ? monospace : index_width(index));
1.16 paf 630: }
631: }
632:
633: };
1.38 parser 634: const int Font::letter_spacing=1;
1.35 parser 635:
1.17 paf 636: static void _font(Request& r, const String& method_name, MethodParams *params) {
1.16 paf 637: Pool& pool=r.pool();
638:
1.37 parser 639: const String& alphabet=params->as_string(0, "alphabet must not be code");
640: gdImage& image=*load(r, method_name, params->as_string(1, "file_name must not be code"));
1.36 parser 641: int spacebar_width=params->as_int(2, r);
1.37 parser 642: int monospace_width;
643: if(params->size()>3) {
644: monospace_width=params->as_int(3, r);
645: if(!monospace_width)
646: monospace_width=image.SX();
647: } else
648: monospace_width=0;
1.16 paf 649:
1.37 parser 650: if(!alphabet.size())
651: PTHROW(0, 0,
652: &method_name,
653: "alphabet must not be empty");
654:
1.16 paf 655: static_cast<VImage *>(r.self)->font=new(pool) Font(pool,
1.37 parser 656: alphabet,
1.36 parser 657: image,
1.37 parser 658: image.SY() / alphabet.size(), monospace_width, spacebar_width);
1.16 paf 659: }
660:
1.17 paf 661: static void _text(Request& r, const String& method_name, MethodParams *params) {
1.16 paf 662: Pool& pool=r.pool();
663:
1.36 parser 664: int x=params->as_int(0, r);
665: int y=params->as_int(1, r);
666: const String& s=params->as_string(2, "text must not be code");
1.16 paf 667:
668: VImage& vimage=*static_cast<VImage *>(r.self);
669: if(vimage.image)
670: if(vimage.font)
671: vimage.font->string_display(*vimage.image, x, y, s);
672: else
673: PTHROW(0, 0,
674: &method_name,
675: "set the font first");
676: else
677: PTHROW(0, 0,
678: &method_name,
679: "does not contain an image");
680: }
681:
1.22 paf 682: // constructor
683:
684: MImage::MImage(Pool& apool) : Methoded(apool) {
685: set_name(*NEW String(pool(), IMAGE_CLASS_NAME));
686:
687:
1.1 paf 688: // ^image:measure[DATA]
1.22 paf 689: add_native_method("measure", Method::CT_DYNAMIC, _measure, 1, 1);
1.3 paf 690:
1.25 paf 691: // ^image.html[]
692: // ^image.html[hash]
1.22 paf 693: add_native_method("html", Method::CT_DYNAMIC, _html, 0, 1);
1.6 paf 694:
1.25 paf 695: // ^image.load[background.gif]
1.22 paf 696: add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
1.6 paf 697:
1.25 paf 698: // ^image.create[width;height] bgcolor=white
699: // ^image.create[width;height;bgcolor]
1.22 paf 700: add_native_method("create", Method::CT_DYNAMIC, _create, 2, 3);
1.6 paf 701:
1.25 paf 702: // ^image.gif[]
1.22 paf 703: add_native_method("gif", Method::CT_DYNAMIC, _gif, 0, 0);
1.12 paf 704:
1.25 paf 705: // ^image.line(x0;y0;x1;y1;color)
1.22 paf 706: add_native_method("line", Method::CT_DYNAMIC, _line, 5, 5);
1.13 paf 707:
1.25 paf 708: // ^image.fill(x;y;color)
1.22 paf 709: add_native_method("fill", Method::CT_DYNAMIC, _fill, 3, 3);
1.13 paf 710:
1.25 paf 711: // ^image.rectangle(x0;y0;x1;y1;color)
1.22 paf 712: add_native_method("rectangle", Method::CT_DYNAMIC, _rectangle, 5, 5);
1.13 paf 713:
1.25 paf 714: // ^image.bar(x0;y0;x1;y1;color)
1.22 paf 715: add_native_method("bar", Method::CT_DYNAMIC, _bar, 5, 5);
1.13 paf 716:
1.44 ! parser 717: // ^image.replace(color-source;color-dest)[table x:y]
! 718: add_native_method("replace", Method::CT_DYNAMIC, _replace, 3, 3);
! 719:
! 720: // ^image.polyline(color)[table x:y]
! 721: add_native_method("polyline", Method::CT_DYNAMIC, _polyline, 2, 2);
1.13 paf 722:
1.44 ! parser 723: // ^image.polygon(color)[table x:y]
! 724: add_native_method("polygon", Method::CT_DYNAMIC, _polygon, 2, 2);
1.13 paf 725:
1.44 ! parser 726: // ^image.polybar(color)[table x:y]
! 727: add_native_method("polybar", Method::CT_DYNAMIC, _polybar, 2, 2);
1.13 paf 728:
1.36 parser 729: // ^image.font[alPHAbet;font-file-name.gif](spacebar_width)
730: // ^image.font[alPHAbet;font-file-name.gif](spacebar_width;width)
731: add_native_method("font", Method::CT_DYNAMIC, _font, 3, 4);
1.16 paf 732:
1.25 paf 733: // ^image.text(x;y)[text]
1.22 paf 734: add_native_method("text", Method::CT_DYNAMIC, _text, 3, 3);
1.16 paf 735:
1.22 paf 736: }
737:
738: // global variable
739:
740: Methoded *image_class;
741:
742: // creator
743:
744: Methoded *MImage_create(Pool& pool) {
745: return image_class=new(pool) MImage(pool);
1.1 paf 746: }
E-mail: