Annotation of parser3/src/classes/image.C, revision 1.3
1.1 paf 1: /** @file
2: Parser: @b image parser class.
3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
5:
6: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
7:
1.3 ! paf 8: $Id: image.C,v 1.2 2001/04/10 13:24:49 paf Exp $
1.1 paf 9: */
10:
11: #include "pa_config_includes.h"
12:
13: #ifdef WIN32
14: # include "smtp/smtp.h"
15: #endif
16:
17: #include "pa_common.h"
18: #include "pa_request.h"
19: #include "pa_vfile.h"
20: #include "pa_vimage.h"
21:
22: // global var
23:
24: VStateless_class *image_class;
25:
26: // helpers
27:
28: class Measure_reader {
29: public:
1.3 ! paf 30: enum { READ_CHUNK_SIZE=0x400 }; // 1K
1.1 paf 31: typedef size_t (*Func)(void *& buf, size_t limit, void *info);
32:
33: Measure_reader(Func afunc, void *ainfo) :
34: func(afunc), info(ainfo),
35: chunk(0), offset(0), size(0) {
36: }
37:
38: size_t read(unsigned char *& buf, size_t limit) {
1.3 ! paf 39: if(offset+limit>size) // nothing left
! 40: if(offset==0 || limit==1) { // only one-byte continuations allowed
! 41: size=(*func)(chunk, READ_CHUNK_SIZE, info);
! 42: offset=0;
! 43: } else
! 44: return 0; // as if EOF
1.1 paf 45: if(!size) // EOF
46: return 0;
47:
48: // something left
49: size_t read_size=min(offset+limit, size)-offset;
50: buf=((unsigned char *)chunk)+offset;
51: offset+=read_size;
52: return read_size;
53: }
54:
55: private:
56: Func func;
57: void *info;
58:
59: void *chunk;
60: size_t offset;
61: size_t size;
62: };
63:
64: // GIF
65: struct GIF_Header {
66: char type[3]; // 'GIF'
67: char version[3];
68: unsigned char width[2];
69: unsigned char height[2];
70: char dif;
71: char fonColor;
72: char nulls;
73: };
74:
75: // JPEG
76: struct JFIF_Header {
77: char length[2]; // length of JFIF segment marker
78: char identifier[5]; // JFIF identifier
79: char version[2]; // version
80: char units; // units X of Y pixel density
81: char xdensity[2]; // X pixel density
82: char ydensity[2]; // X pixel density
83: char xthumbnails; // width of thumbnails
84: char ythumbnails; // height of thumbnails
85: char reserved; // reserved
86: };
87: struct JPG_Frame {
88: char length[2]; // length of image marker
89: char data; // data precision of bits/sample
90: char height[2]; // image height
91: char width[2]; // image width
92: char numComponents; // number of color components
93: };
94:
95: //
96:
97: inline short bytes_to_int(unsigned char HI, unsigned char LO) {
98: return (short)((HI<<8) + LO);
99: }
100:
101: void measure_gif(Pool& pool, const String *origin_string,
102: Measure_reader& reader, int& width, int& height) {
103:
104: unsigned char *buf;
105: const int head_size=sizeof(GIF_Header);
106: if(reader.read(buf, head_size)<head_size)
107: PTHROW(0, 0,
108: origin_string,
109: "broken GIF header - file size is less then %d bytes", head_size);
110:
111: GIF_Header& screenD=*reinterpret_cast<GIF_Header *>(buf);
112: if(strncmp(screenD.type, "GIF", 3)!=0)
113: PTHROW(0, 0,
114: origin_string,
115: "bad image file - GIF signature not found");
116:
117: width=bytes_to_int(screenD.width[1], screenD.width[0]);
118: height=bytes_to_int(screenD.height[1], screenD.height[0]);
119: }
120:
121: void measure_jpeg(Pool& pool, const String *origin_string,
122: Measure_reader& reader, int& width, int& height) {
1.2 paf 123: // JFIF format markers
124: const unsigned char SOI=0xD8;
125: const unsigned char EOI=0xD9;
126: const unsigned char APP0=0xE0;
127: const unsigned char SOF0=0xC0;
128: const unsigned char SOF2=0xC2;
129: const unsigned char COM=0xFE;
130:
1.1 paf 131: unsigned char *screenD_buf;
1.3 ! paf 132: unsigned char *h_buf=0;
1.1 paf 133:
134: bool flag=false;
135:
136: unsigned char *prefix;
137: const prefix_size=2;
138: if(reader.read(prefix, prefix_size)<prefix_size)
139: PTHROW(0, 0,
140: origin_string,
141: "broken JPEG file - size is less then %d bytes", prefix_size);
142:
143: if(((unsigned char *)prefix)[1]!=SOI)
144: PTHROW(0, 0,
145: origin_string,
146: "broken JPEG file - second byte of header is not 0x%02X", SOI);
147:
148: unsigned char zero=0;
149: unsigned char *marker=&zero;
150:
151: do {
152: while((*marker)!=0xFF)
153: if(reader.read(marker, sizeof(char))<=0) break;
154: if(reader.read(marker, sizeof(char))<=0) break;
155: switch(*marker) {
156: case EOI:
157: marker=&zero;
158: break;
159: case APP0:
160: if(!flag) {
161: flag=true;
162: if(reader.read(screenD_buf, sizeof(JFIF_Header)) < sizeof(JFIF_Header))
163: break;
164: JFIF_Header& screenD=*reinterpret_cast<JFIF_Header *>(screenD_buf);
165: if((bytes_to_int(screenD.length[0], screenD.length[1]) < 16) ||
1.2 paf 166: strcasecmp(screenD.identifier, "JFIF")) flag=false;
1.1 paf 167: }
168: break;
169: case SOF0:
170: case SOF2:
171: if(reader.read(h_buf, sizeof(JPG_Frame))<sizeof(JPG_Frame))
172: flag=false;
173: break;
174: default: break;
175: }
176: } while(*marker!=EOI);
177:
1.3 ! paf 178: if(flag && h_buf) {
1.1 paf 179: JPG_Frame& h=*reinterpret_cast<JPG_Frame *>(h_buf);
180: width=bytes_to_int(h.width[0], h.width[1]);
181: height=bytes_to_int(h.height[0], h.height[1]);
182: } else
183: PTHROW(0, 0,
184: origin_string,
185: "broken JPEG file - APP0 frame not found");
186: }
187:
188: // measure center
189:
190: void measure(Pool& pool, const String& file_name,
191: Measure_reader& reader, int& width, int& height) {
192: if(const char *cext=strrchr(file_name.cstr(), '.')) {
193: cext++;
194: if(strcasecmp(cext, "GIF")==0)
195: measure_gif(pool, &file_name, reader, width, height);
196: else if(strcasecmp(cext, "JPG")==0 || strcasecmp(cext, "JPEG")==0)
197: measure_jpeg(pool, &file_name, reader, width, height);
198: else
199: PTHROW(0, 0,
200: &file_name,
201: "unhandled image file name extension '%s'", cext);
202: } else
203: PTHROW(0, 0,
204: &file_name,
205: "can not determine image type - no file name extension");
206: }
207:
208: // read from somewhere
209:
210: struct Read_mem_info {
211: unsigned char *ptr;
212: unsigned char *eof;
213: };
214: static size_t read_mem(void*& buf, size_t limit, void *info) {
215: Read_mem_info& rmi=*static_cast<Read_mem_info *>(info);
216: buf=rmi.ptr;
217: size_t read_size=min(limit, (size_t)(rmi.eof-rmi.ptr));
218: rmi.ptr+=read_size;
219: return read_size;
220: }
221:
222: struct Read_disk_info {
223: const String *file_spec;
224: size_t offset;
225: };
226: static size_t read_disk(void*& buf, size_t limit, void *info) {
227: Read_disk_info& rdi=*static_cast<Read_disk_info *>(info);
228: Pool& pool=rdi.file_spec->pool();
229:
230: size_t read_size;
231: file_read(pool, *rdi.file_spec,
232: buf, read_size,
233: false/*as_text*/,
234: true/*fail_on_read_problem*/,
235: rdi.offset, limit);
236:
237: rdi.offset+=read_size;
238: return read_size;
239: }
240:
241: // methods
242:
243: /// ^image:measure[DATA]
244: static void _measure(Request& r, const String& method_name, Array *params) {
245: Pool& pool=r.pool();
246:
247: Value& data=*static_cast<Value *>(params->get(0));
248: // forcing [this body type]
249: r.fail_if_junction_(true, data, method_name, "data must not be code");
250:
251: void *info; Measure_reader::Func read_func;
252: Read_mem_info read_mem_info;
253: Read_disk_info read_disk_info;
254: const String *file_name;
255: if(data.is_string()) {
256: file_name=data.get_string();
257: read_disk_info.file_spec=&r.absolute(*file_name);
258: read_disk_info.offset=0;
259: info=&read_disk_info; read_func=read_disk;
260: } else {
261: const VFile& vfile=*data.as_vfile();
262: file_name=&static_cast<Value *>(vfile.fields().get(*name_name))->as_string();
263: read_mem_info.ptr=(unsigned char *)vfile.value_ptr();
264: read_mem_info.eof=read_mem_info.ptr+vfile.value_size();
265: info=&read_mem_info; read_func=read_mem;
266: }
267:
268: Measure_reader reader(read_func, info);
269: int width, height;
270: measure(pool, *file_name, reader, width, height);
271:
272: static_cast<VImage *>(r.self)->set(*file_name, width, height);
273: }
274:
1.3 ! paf 275: static void append_attrib_pair(const Hash::Key& key, Hash::Val *val, void *info) {
! 276: String& tag=*static_cast<String *>(info);
! 277: Value& value=*static_cast<Value *>(val);
! 278: // src="a.gif" width=123 ismap[=-1]
! 279: tag << " " << key;
! 280: if(value.is_string() || value.as_double()>=0) {
! 281: tag << "=";
! 282: if(value.is_string())
! 283: tag << "\"";
! 284: tag << value.as_string();
! 285: if(value.is_string())
! 286: tag << "\"";
! 287: }
! 288: }
! 289: /// ^image.html[]
! 290: /// ^image.html[hash]
! 291: static void _html(Request& r, const String& method_name, Array *params) {
! 292: Pool& pool=r.pool();
! 293:
! 294: String tag(pool);
! 295: tag << "<img";
! 296: static_cast<VImage *>(r.self)->fields().for_each(append_attrib_pair, &tag);
! 297: tag << ">";
! 298: r.write_pass_lang(tag);
! 299: }
! 300:
1.1 paf 301: // initialize
302: void initialize_image_class(Pool& pool, VStateless_class& vclass) {
303: // ^image:measure[DATA]
304: vclass.add_native_method("measure", Method::CT_DYNAMIC, _measure, 1, 1);
1.3 ! paf 305:
! 306: /// ^image.html[]
! 307: /// ^image.html[hash]
! 308: vclass.add_native_method("html", Method::CT_DYNAMIC, _html, 0, 1);
1.1 paf 309: }
E-mail: