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: