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