Annotation of parser3/src/classes/image.C, revision 1.1
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:
! 8: $Id: image.C, v 1.15 2001/04/10 07:47:38 paf Exp $
! 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:
! 30: enum { READ_CHUNK_SIZE=10*0x400 }; // 10K
! 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) {
! 39: if(!size) // nothing left
! 40: size=(*func)(chunk, READ_CHUNK_SIZE, info);
! 41: if(!size) // EOF
! 42: return 0;
! 43:
! 44: // something left
! 45: size_t read_size=min(offset+limit, size)-offset;
! 46: buf=((unsigned char *)chunk)+offset;
! 47: offset+=read_size;
! 48: return read_size;
! 49: }
! 50:
! 51: private:
! 52: Func func;
! 53: void *info;
! 54:
! 55: void *chunk;
! 56: size_t offset;
! 57: size_t size;
! 58: };
! 59:
! 60: // GIF
! 61: struct GIF_Header {
! 62: char type[3]; // 'GIF'
! 63: char version[3];
! 64: unsigned char width[2];
! 65: unsigned char height[2];
! 66: char dif;
! 67: char fonColor;
! 68: char nulls;
! 69: };
! 70:
! 71: // JPEG
! 72: struct JFIF_Header {
! 73: char length[2]; // length of JFIF segment marker
! 74: char identifier[5]; // JFIF identifier
! 75: char version[2]; // version
! 76: char units; // units X of Y pixel density
! 77: char xdensity[2]; // X pixel density
! 78: char ydensity[2]; // X pixel density
! 79: char xthumbnails; // width of thumbnails
! 80: char ythumbnails; // height of thumbnails
! 81: char reserved; // reserved
! 82: };
! 83: struct JPG_Frame {
! 84: char length[2]; // length of image marker
! 85: char data; // data precision of bits/sample
! 86: char height[2]; // image height
! 87: char width[2]; // image width
! 88: char numComponents; // number of color components
! 89: };
! 90: // JFIF format markers
! 91: #define SOI 0xD8
! 92: #define EOI 0xD9
! 93: #define APP0 0xE0
! 94: #define SOF0 0xC0
! 95: #define SOF2 0xC2
! 96: #define COM 0xFE
! 97:
! 98:
! 99: //
! 100:
! 101: inline short bytes_to_int(unsigned char HI, unsigned char LO) {
! 102: return (short)((HI<<8) + LO);
! 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) {
! 127: unsigned char *screenD_buf;
! 128: unsigned char *h_buf;
! 129:
! 130: bool flag=false;
! 131: char Spec[]="JFIF";
! 132:
! 133: unsigned char *prefix;
! 134: const prefix_size=2;
! 135: if(reader.read(prefix, prefix_size)<prefix_size)
! 136: PTHROW(0, 0,
! 137: origin_string,
! 138: "broken JPEG file - size is less then %d bytes", prefix_size);
! 139:
! 140: if(((unsigned char *)prefix)[1]!=SOI)
! 141: PTHROW(0, 0,
! 142: origin_string,
! 143: "broken JPEG file - second byte of header is not 0x%02X", SOI);
! 144:
! 145: unsigned char zero=0;
! 146: unsigned char *marker=&zero;
! 147:
! 148: do {
! 149: while((*marker)!=0xFF)
! 150: if(reader.read(marker, sizeof(char))<=0) break;
! 151: if(reader.read(marker, sizeof(char))<=0) break;
! 152: switch(*marker) {
! 153: case EOI:
! 154: marker=&zero;
! 155: break;
! 156: case APP0:
! 157: if(!flag) {
! 158: flag=true;
! 159: if(reader.read(screenD_buf, sizeof(JFIF_Header)) < sizeof(JFIF_Header))
! 160: break;
! 161: JFIF_Header& screenD=*reinterpret_cast<JFIF_Header *>(screenD_buf);
! 162: if((bytes_to_int(screenD.length[0], screenD.length[1]) < 16) ||
! 163: strcasecmp(screenD.identifier, Spec)) flag=false;
! 164: }
! 165: break;
! 166: case SOF0:
! 167: case SOF2:
! 168: if(reader.read(h_buf, sizeof(JPG_Frame))<sizeof(JPG_Frame))
! 169: flag=false;
! 170: break;
! 171: default: break;
! 172: }
! 173: } while(*marker!=EOI);
! 174:
! 175: if(flag) {
! 176: JPG_Frame& h=*reinterpret_cast<JPG_Frame *>(h_buf);
! 177: width=bytes_to_int(h.width[0], h.width[1]);
! 178: height=bytes_to_int(h.height[0], h.height[1]);
! 179: } else
! 180: PTHROW(0, 0,
! 181: origin_string,
! 182: "broken JPEG file - APP0 frame not found");
! 183: }
! 184:
! 185: // measure center
! 186:
! 187: void measure(Pool& pool, const String& file_name,
! 188: Measure_reader& reader, int& width, int& height) {
! 189: if(const char *cext=strrchr(file_name.cstr(), '.')) {
! 190: cext++;
! 191: if(strcasecmp(cext, "GIF")==0)
! 192: measure_gif(pool, &file_name, reader, width, height);
! 193: else if(strcasecmp(cext, "JPG")==0 || strcasecmp(cext, "JPEG")==0)
! 194: measure_jpeg(pool, &file_name, reader, width, height);
! 195: else
! 196: PTHROW(0, 0,
! 197: &file_name,
! 198: "unhandled image file name extension '%s'", cext);
! 199: } else
! 200: PTHROW(0, 0,
! 201: &file_name,
! 202: "can not determine image type - no file name extension");
! 203: }
! 204:
! 205: // read from somewhere
! 206:
! 207: struct Read_mem_info {
! 208: unsigned char *ptr;
! 209: unsigned char *eof;
! 210: };
! 211: static size_t read_mem(void*& buf, size_t limit, void *info) {
! 212: Read_mem_info& rmi=*static_cast<Read_mem_info *>(info);
! 213: buf=rmi.ptr;
! 214: size_t read_size=min(limit, (size_t)(rmi.eof-rmi.ptr));
! 215: rmi.ptr+=read_size;
! 216: return read_size;
! 217: }
! 218:
! 219: struct Read_disk_info {
! 220: const String *file_spec;
! 221: size_t offset;
! 222: };
! 223: static size_t read_disk(void*& buf, size_t limit, void *info) {
! 224: Read_disk_info& rdi=*static_cast<Read_disk_info *>(info);
! 225: Pool& pool=rdi.file_spec->pool();
! 226:
! 227: size_t read_size;
! 228: file_read(pool, *rdi.file_spec,
! 229: buf, read_size,
! 230: false/*as_text*/,
! 231: true/*fail_on_read_problem*/,
! 232: rdi.offset, limit);
! 233:
! 234: rdi.offset+=read_size;
! 235: return read_size;
! 236: }
! 237:
! 238: // methods
! 239:
! 240: /// ^image:measure[DATA]
! 241: static void _measure(Request& r, const String& method_name, Array *params) {
! 242: Pool& pool=r.pool();
! 243:
! 244: Value& data=*static_cast<Value *>(params->get(0));
! 245: // forcing [this body type]
! 246: r.fail_if_junction_(true, data, method_name, "data must not be code");
! 247:
! 248: void *info; Measure_reader::Func read_func;
! 249: Read_mem_info read_mem_info;
! 250: Read_disk_info read_disk_info;
! 251: const String *file_name;
! 252: if(data.is_string()) {
! 253: file_name=data.get_string();
! 254: read_disk_info.file_spec=&r.absolute(*file_name);
! 255: read_disk_info.offset=0;
! 256: info=&read_disk_info; read_func=read_disk;
! 257: } else {
! 258: const VFile& vfile=*data.as_vfile();
! 259: file_name=&static_cast<Value *>(vfile.fields().get(*name_name))->as_string();
! 260: read_mem_info.ptr=(unsigned char *)vfile.value_ptr();
! 261: read_mem_info.eof=read_mem_info.ptr+vfile.value_size();
! 262: info=&read_mem_info; read_func=read_mem;
! 263: }
! 264:
! 265: Measure_reader reader(read_func, info);
! 266: int width, height;
! 267: measure(pool, *file_name, reader, width, height);
! 268:
! 269: static_cast<VImage *>(r.self)->set(*file_name, width, height);
! 270: }
! 271:
! 272: // initialize
! 273: void initialize_image_class(Pool& pool, VStateless_class& vclass) {
! 274: // ^image:measure[DATA]
! 275: vclass.add_native_method("measure", Method::CT_DYNAMIC, _measure, 1, 1);
! 276: }
E-mail: