Diff for /parser3/src/classes/image.C between versions 1.30 and 1.39

version 1.30, 2001/07/07 16:38:01 version 1.39, 2001/09/04 19:44:32
Line 9 Line 9
 */  */
 static const char *RCSId="$Id$";   static const char *RCSId="$Id$"; 
   
   /*
           jpegsize: gets the width and height (in pixels) of a jpeg file
           Andrew Tong, werdna@ugcs.caltech.edu           February 14, 1995
           modified slightly by alex@ed.ac.uk
           and further still by rjray@uswest.com
           optimization and general re-write from tmetro@vl.com
           from perl by paf@design.ru
   */
   
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
   
 #include "gif.h"  #include "gif.h"
Line 41  public: // Methoded Line 50  public: // Methoded
 /// simple buffered reader[from memory/file], used in _measure  /// simple buffered reader[from memory/file], used in _measure
 class Measure_reader {  class Measure_reader {
 public:  public:
         enum { READ_CHUNK_SIZE=0x400 };// 1K          enum { READ_CHUNK_SIZE=0x400*10 };// 10K
         typedef size_t(*Func)(void *& buf, size_t limit, void *info);          typedef size_t(*Func)(void *& buf, size_t limit, void *info);
   
         Measure_reader(Func afunc, void *ainfo) :           Measure_reader(Func afunc, void *ainfo) : 
Line 49  public: Line 58  public:
                 chunk(0), offset(0), size(0) {                  chunk(0), offset(0), size(0) {
         }          }
   
         size_t read(unsigned char *& buf, size_t limit) {          size_t read(void *&buf, size_t limit) {
                 if(offset+limit>size) // nothing left                  if(offset+limit>size) // nothing left
                         if(offset==0 || limit==1) { // only one-byte continuations allowed                          if(offset==0 || limit==1) { // only one-byte continuations allowed
                                 size=(*func)(chunk, READ_CHUNK_SIZE, info);                                  size=(*func)(chunk, READ_CHUNK_SIZE, info);
Line 86  struct GIF_Header { Line 95  struct GIF_Header {
         char       nulls;          char       nulls;
 };  };
   
 /// JPEG file header  /// JPEG record head
 struct JFIF_Header {  struct JPG_Segment_head {
         char length[2];              //< length of JFIF segment marker          unsigned char marker;
         char identifier[5];          //< JFIF identifier          unsigned char code;
         char version[2];             //< version          unsigned char length[2];
         char units;                  //< units X of Y pixel density  
         char xdensity[2];            //< X pixel density  
         char ydensity[2];            //< X pixel density  
         char xthumbnails;            //< width of thumbnails  
         char ythumbnails;            //< height of thumbnails  
         char reserved;               //< reserved  
 };  };
 /// JPEG frame header  /// JPEG frame header
 struct JPG_Frame {  struct JPG_Size_segment_body {
         char length[2];               //< length of image marker  
         char data;                    //< data precision of bits/sample          char data;                    //< data precision of bits/sample
         char height[2];               //< image height          unsigned char height[2];               //< image height
         char width[2];                //< image width          unsigned char width[2];                //< image width
         char numComponents;           //< number of color components          char numComponents;           //< number of color components
 };  };
   
 //  //
   
 inline short bytes_to_int(unsigned char HI, unsigned char LO) {  inline short x_endian_to_int(unsigned char L, unsigned char H) {
         return(short)((HI<<8) + LO);          return(short)((H<<8) + L);
   }
   
   inline short big_endian_to_int(unsigned char b[2]) {
           return x_endian_to_int(b[1], b[0]);
   }
   
   inline short little_endian_to_int(unsigned char b[2]) {
           return x_endian_to_int(b[0], b[1]);
 }  }
   
 void measure_gif(Pool& pool, const String *origin_string,   void measure_gif(Pool& pool, const String *origin_string, 
                          Measure_reader& reader, int& width, int& height) {                           Measure_reader& reader, int& width, int& height) {
   
         unsigned char *buf;          void *buf;
         const int head_size=sizeof(GIF_Header);          const int head_size=sizeof(GIF_Header);
         if(reader.read(buf, head_size)<head_size)          if(reader.read(buf, head_size)<head_size)
                 PTHROW(0, 0,                   PTHROW(0, 0, 
                         origin_string,                           origin_string, 
                         "broken GIF header - file size is less then %d bytes", head_size);                          "not GIF file - too small");
           GIF_Header *head=(GIF_Header *)buf;
   
         GIF_Header& screenD=*reinterpret_cast<GIF_Header *>(buf);          if(strncmp(head->type, "GIF", 3)!=0)
         if(strncmp(screenD.type, "GIF", 3)!=0)  
                 PTHROW(0, 0,                   PTHROW(0, 0, 
                         origin_string,                           origin_string, 
                         "bad image file - GIF signature not found");                              "not GIF file - signature not found");  
   
         width=bytes_to_int(screenD.width[1], screenD.width[0]);          width=little_endian_to_int(head->width);
         height=bytes_to_int(screenD.height[1], screenD.height[0]);          height=little_endian_to_int(head->height);
 }  }
   
 void measure_jpeg(Pool& pool, const String *origin_string,   void measure_jpeg(Pool& pool, const String *origin_string, 
                          Measure_reader& reader, int& width, int& height) {                           Measure_reader& reader, int& width, int& height) {
         // JFIF format markers          // JFIF format markers
         const unsigned char SOI=0xD8;          const unsigned char MARKER=0xFF;
         const unsigned char EOI=0xD9;          const unsigned char CODE_SIZE_FIRST=0xC0;
         const unsigned char APP0=0xE0;          const unsigned char CODE_SIZE_LAST=0xC3;
         const unsigned char SOF0=0xC0;  
         const unsigned char SOF2=0xC2;  
         const unsigned char COM=0xFE;  
   
         unsigned char *screenD_buf;          void *buf;
         unsigned char *h_buf=0;  
           
         bool flag=false;  
           
         unsigned char *prefix;  
         const size_t prefix_size=2;          const size_t prefix_size=2;
         if(reader.read(prefix, prefix_size)<prefix_size)          if(reader.read(buf, prefix_size)<prefix_size)
                 PTHROW(0, 0,                   PTHROW(0, 0, 
                         origin_string,                           origin_string, 
                         "broken JPEG file - size is less then %d bytes", prefix_size);                          "not JPEG file - too small");
           unsigned char *signature=(unsigned char *)buf;
                   
         if(((unsigned char *)prefix)[1]!=SOI)           if(!(signature[0]==0xFF && signature[1]==0xD8)) 
                 PTHROW(0, 0,                   PTHROW(0, 0, 
                         origin_string,                           origin_string, 
                         "broken JPEG file - second byte of header is not 0x%02X", SOI);                          "not JPEG file - signature not found");
                   
         unsigned char zero=0;          bool found=false;
         unsigned char *marker=&zero;          while(true) {
                   void *buf;
         do {          // Extract the segment header.
                 while((*marker)!=0xFF)                  if(reader.read(buf, sizeof(JPG_Segment_head))<sizeof(JPG_Segment_head))
                         if(reader.read(marker, sizeof(char))<=0) break;                          break;          
                 if(reader.read(marker, sizeof(char))<=0) break;                  JPG_Segment_head *head=(JPG_Segment_head *)buf;
                 switch(*marker) {  
                 case EOI:          // Verify that it's a valid segment.
                         marker=&zero;                  if(head->marker!=MARKER)
                         break;  
                 case APP0:  
                         if(!flag) {  
                                 flag=true;  
                                 if(reader.read(screenD_buf, sizeof(JFIF_Header)) < sizeof(JFIF_Header))  
                                         break;  
                                 JFIF_Header& screenD=*reinterpret_cast<JFIF_Header *>(screenD_buf);  
                                 if((bytes_to_int(screenD.length[0], screenD.length[1]) < 16) ||  
                                         strcasecmp(screenD.identifier, "JFIF")) flag=false;  
                         }  
                         break;                          break;
                 case SOF0:  
                 case SOF2:                  if(head->code >= CODE_SIZE_FIRST && head->code  <= CODE_SIZE_LAST) {
                         if(reader.read(h_buf, sizeof(JPG_Frame))<sizeof(JPG_Frame))              // Segments that contain size info
                                 flag=false;                          if(reader.read(buf, sizeof(JPG_Size_segment_body))<sizeof(JPG_Size_segment_body))
                                   break;
                           JPG_Size_segment_body *body=(JPG_Size_segment_body *)buf;
                           
                           width=big_endian_to_int(body->width);
                           height=big_endian_to_int(body->height);
                           found=true;
                         break;                          break;
                 default: break;                  } else {
                 }              // Dummy read to skip over data
         } while(*marker!=EOI);              size_t limit=big_endian_to_int(head->length) - 2;
                                   if(reader.read(buf, limit)<limit)
         if(flag && h_buf) {                                  break;
                 JPG_Frame& h=*reinterpret_cast<JPG_Frame *>(h_buf);          }
                 width=bytes_to_int(h.width[0], h.width[1]);          }
                 height=bytes_to_int(h.height[0], h.height[1]);  
         } else          if(!found)
                 PTHROW(0, 0,                   PTHROW(0, 0, 
                         origin_string,                           origin_string, 
                         "broken JPEG file - APP0 frame not found");                                               "broken JPEG file - size frame not found");
 }  }
   
 // measure center  // measure center
Line 310  static void _html(Request& r, const Stri Line 309  static void _html(Request& r, const Stri
         const Hash& fields=static_cast<VImage *>(r.self)->fields();          const Hash& fields=static_cast<VImage *>(r.self)->fields();
         Hash *attribs=0;          Hash *attribs=0;
   
         if(params->size())          if(params->size()) {
                 if(attribs=params->get(0).get_hash()) {                  Value &vattribs=params->get(0);
                         Attrib_info attrib_info={&tag, 0};                  if(vattribs.is_defined()) // allow 'void'
                         attribs->for_each(append_attrib_pair, &attrib_info);                          if(Hash *attribs=vattribs.get_hash()) {
                 } else                                  Attrib_info attrib_info={&tag, 0};
                         PTHROW(0, 0,                                   attribs->for_each(append_attrib_pair, &attrib_info);
                                 &method_name,                           } else
                                 "attributes must be must be hash");                                  PTHROW(0, 0, 
                                           &method_name, 
                                           "attributes must be hash");
           }
   
         Attrib_info attrib_info={&tag, attribs};          Attrib_info attrib_info={&tag, attribs};
         fields.for_each(append_attrib_pair, &attrib_info);          fields.for_each(append_attrib_pair, &attrib_info);
Line 363  static void _load(Request& r, const Stri Line 365  static void _load(Request& r, const Stri
 static void _create(Request& r, const String& method_name, MethodParams *params) {  static void _create(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
   
         int width=r.process(params->get(0)).as_int();          int width=params->as_int(0, r);
         int height=r.process(params->get(1)).as_int();          int height=params->as_int(1, r);
         int bgcolor_value=0xffFFff;          int bgcolor_value=0xffFFff;
         if(params->size()>2)          if(params->size()>2)
                 bgcolor_value=r.process(params->get(2)).as_int();                  bgcolor_value=params->as_int(2, r);
         gdImage& image=*new(pool) gdImage(pool);          gdImage& image=*new(pool) gdImage(pool);
         image.Create(width, height);          image.Create(width, height);
         image.FilledRectangle(0, 0, width-1, height-1, image.Color(bgcolor_value));          image.FilledRectangle(0, 0, width-1, height-1, image.Color(bgcolor_value));
Line 405  static void _line(Request& r, const Stri Line 407  static void _line(Request& r, const Stri
                         "does not contain an image");                          "does not contain an image");
   
         image->Line(          image->Line(
                 r.process(params->get(0)).as_int(),                   params->as_int(0, r), 
                 r.process(params->get(1)).as_int(),                   params->as_int(1, r), 
                 r.process(params->get(2)).as_int(),                   params->as_int(2, r), 
                 r.process(params->get(3)).as_int(),                   params->as_int(3, r), 
                 image->Color(r.process(params->get(4)).as_int()));                  image->Color(params->as_int(4, r)));
 }  }
   
 static void _fill(Request& r, const String& method_name, MethodParams *params) {  static void _fill(Request& r, const String& method_name, MethodParams *params) {
Line 422  static void _fill(Request& r, const Stri Line 424  static void _fill(Request& r, const Stri
                         "does not contain an image");                          "does not contain an image");
   
         image->Fill(          image->Fill(
                 r.process(params->get(0)).as_int(),                   params->as_int(0, r), 
                 r.process(params->get(1)).as_int(),                   params->as_int(1, r), 
                 image->Color(r.process(params->get(2)).as_int()));                  image->Color(params->as_int(2, r)));
 }  }
   
 static void _rectangle(Request& r, const String& method_name, MethodParams *params) {  static void _rectangle(Request& r, const String& method_name, MethodParams *params) {
Line 437  static void _rectangle(Request& r, const Line 439  static void _rectangle(Request& r, const
                         "does not contain an image");                          "does not contain an image");
   
         image->Rectangle(          image->Rectangle(
                 r.process(params->get(0)).as_int(),                   params->as_int(0, r), 
                 r.process(params->get(1)).as_int(),                   params->as_int(1, r), 
                 r.process(params->get(2)).as_int(),                   params->as_int(2, r), 
                 r.process(params->get(3)).as_int(),                   params->as_int(3, r), 
                 image->Color(r.process(params->get(4)).as_int()));                  image->Color(params->as_int(4, r)));
 }  }
   
 static void _bar(Request& r, const String& method_name, MethodParams *params) {  static void _bar(Request& r, const String& method_name, MethodParams *params) {
Line 454  static void _bar(Request& r, const Strin Line 456  static void _bar(Request& r, const Strin
                         "does not contain an image");                          "does not contain an image");
   
         image->FilledRectangle(          image->FilledRectangle(
                 r.process(params->get(0)).as_int(),                   params->as_int(0, r), 
                 r.process(params->get(1)).as_int(),                   params->as_int(1, r), 
                 r.process(params->get(2)).as_int(),                   params->as_int(2, r), 
                 r.process(params->get(3)).as_int(),                   params->as_int(3, r), 
                 image->Color(r.process(params->get(4)).as_int()));                  image->Color(params->as_int(4, r)));
 }  }
   
 static void _replace(Request& r, const String& method_name, MethodParams *params) {  static void _replace(Request& r, const String& method_name, MethodParams *params) {
Line 479  static void _replace(Request& r, const S Line 481  static void _replace(Request& r, const S
                   
         gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);          gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);
         for(int i=0; i<n; i++) {          for(int i=0; i<n; i++) {
                 p[i].x=r.process(params->get(2+i*2+0)).as_int();                  p[i].x=params->as_int(2+i*2+0, r);
                 p[i].y=r.process(params->get(2+i*2+1)).as_int();                  p[i].y=params->as_int(2+i*2+1, r);
         }          }
         image->FilledPolygonReplaceColor(p, n,           image->FilledPolygonReplaceColor(p, n, 
                 image->Color(r.process(params->get(0)).as_int()), // src color                  image->Color(params->as_int(0, r)), // src color
                 image->Color(r.process(params->get(1)).as_int()));// dest color                  image->Color(params->as_int(1, r)));// dest color
 }  }
   
 static void _polygon(Request& r, const String& method_name, MethodParams *params) {  static void _polygon(Request& r, const String& method_name, MethodParams *params) {
Line 505  static void _polygon(Request& r, const S Line 507  static void _polygon(Request& r, const S
                   
         gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);          gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);
         for(int i=0; i<n; i++) {          for(int i=0; i<n; i++) {
                 p[i].x=r.process(params->get(1+i*2+0)).as_int();                  p[i].x=params->as_int(2+i*2+0, r);
                 p[i].y=r.process(params->get(1+i*2+1)).as_int();                  p[i].y=params->as_int(2+i*2+1, r);
         }          }
         image->Polygon(p, n,           image->Polygon(p, n, 
                 image->Color(r.process(params->get(0)).as_int()));                  image->Color(params->as_int(0, r)));
 }  }
   
 static void _polybar(Request& r, const String& method_name, MethodParams *params) {  static void _polybar(Request& r, const String& method_name, MethodParams *params) {
Line 530  static void _polybar(Request& r, const S Line 532  static void _polybar(Request& r, const S
                   
         gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);          gdImage::Point *p=(gdImage::Point *)pool.malloc(sizeof(gdImage::Point)*n);
         for(int i=0; i<n; i++) {          for(int i=0; i<n; i++) {
                 p[i].x=r.process(params->get(1+i*2+0)).as_int();                  p[i].x=params->as_int(2+i*2+0, r);
                 p[i].y=r.process(params->get(1+i*2+1)).as_int();                  p[i].y=params->as_int(2+i*2+1, r);
         }          }
         image->FilledPolygon(p, n,           image->FilledPolygon(p, n, 
                 image->Color(r.process(params->get(0)).as_int()));                  image->Color(params->as_int(0, r)));
 }  }
   
 // font  // font
Line 545  static void _polybar(Request& r, const S Line 547  static void _polybar(Request& r, const S
 class Font : public Pooled {  class Font : public Pooled {
 public:  public:
                   
         int height;         //< Font heigth          const static int letter_spacing;
         int space;          //< Default char width          int height;         ///< Font heigth
           int monospace;      ///< Default char width
           int spacebarspace; ///< spacebar width
         gdImage& ifont;          gdImage& ifont;
         const String& alphabet;          const String& alphabet;
                   
         Font(Pool& pool,           Font(Pool& pool, 
                 const String& aalphabet,                   const String& aalphabet, 
                 gdImage& aifont, int aheight, int aspace) : Pooled(pool),                   gdImage& aifont, int aheight, int amonospace, int aspacebarspace) : Pooled(pool), 
                 alphabet(aalphabet),                   alphabet(aalphabet), 
                 height(aheight), space(aspace),                   height(aheight), monospace(amonospace),  spacebarspace(aspacebarspace),
                 ifont(aifont) {                  ifont(aifont) {
         }          }
                   
Line 567  public: Line 571  public:
                   
         int index_width(int index) {          int index_width(int index) {
                 if(index<0)                  if(index<0)
                         index=index_of('.');                          return spacebarspace;
                 if(index<0)   
                         return 0;  
                 int tr=ifont.GetTransparent();                  int tr=ifont.GetTransparent();
                 for(int x=ifont.SX()-1; x>0; x--) {                  for(int x=ifont.SX()-1; x>=0; x--) {
                         for(int y=0; y<height-1; y++)                          for(int y=0; y<height-1; y++)
                                 if(ifont.GetPixel(x, Y(y))!=tr)                                   if(ifont.GetPixel(x, Y(y))!=tr) 
                                         return x+2;                                          return x+1;
                 }                  }
                 return 0;                  return 0;
         }          }
Line 599  public: Line 601  public:
                 if(cstr) for(; *cstr; cstr++) {                  if(cstr) for(; *cstr; cstr++) {
                         int index=index_of(*cstr);                          int index=index_of(*cstr);
                         index_display(image, x, y, index);                          index_display(image, x, y, index);
                         x+=space ? space : index_width(index);                          x+=letter_spacing + (monospace ? monospace : index_width(index));
                 }                  }
         }          }
                   
 };  };
   const int Font::letter_spacing=1;
   
 static void _font(Request& r, const String& method_name, MethodParams *params) {  static void _font(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
   
         Value& valphabet=params->as_no_junction(0, "alphabet must not be code");          const String& alphabet=params->as_string(0, "alphabet must not be code");
         Value& file_name=params->as_no_junction(1, "file_name must not be code");          gdImage& image=*load(r, method_name, params->as_string(1, "file_name must not be code"));
         int height=r.process(params->get(2)).as_int();          int spacebar_width=params->as_int(2, r);
           int monospace_width;
         int width=params->size()>3?r.process(params->get(3)).as_int():0;          if(params->size()>3) {
                   monospace_width=params->as_int(3, r);
                   if(!monospace_width)
                           monospace_width=image.SX();
           } else
                   monospace_width=0;
   
           if(!alphabet.size())
                   PTHROW(0, 0,
                           &method_name,
                           "alphabet must not be empty");
           
         static_cast<VImage *>(r.self)->font=new(pool) Font(pool,           static_cast<VImage *>(r.self)->font=new(pool) Font(pool, 
                 valphabet.as_string(),                   alphabet, 
                 *load(r, method_name, file_name.as_string()),                   image, 
                 height, width);                  image.SY() / alphabet.size(), monospace_width, spacebar_width);
 }  }
   
 static void _text(Request& r, const String& method_name, MethodParams *params) {  static void _text(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
   
         int x=r.process(params->get(0)).as_int();          int x=params->as_int(0, r);
         int y=r.process(params->get(1)).as_int();          int y=params->as_int(1, r);
         const String& s=r.process(params->get(2)).as_string();          const String& s=params->as_string(2, "text must not be code");
   
         VImage& vimage=*static_cast<VImage *>(r.self);          VImage& vimage=*static_cast<VImage *>(r.self);
         if(vimage.image)          if(vimage.image)
Line 684  MImage::MImage(Pool& apool) : Methoded(a Line 698  MImage::MImage(Pool& apool) : Methoded(a
         // ^image.polybar(color)(x;y)... point coord pairs          // ^image.polybar(color)(x;y)... point coord pairs
         add_native_method("polybar", Method::CT_DYNAMIC, _polybar, 1+3*2, 1+100*2);          add_native_method("polybar", Method::CT_DYNAMIC, _polybar, 1+3*2, 1+100*2);
   
     // ^image.font[alPHAbet;font-file-name.gif](height)      // ^image.font[alPHAbet;font-file-name.gif](spacebar_width)
     // ^image.font[alPHAbet;font-file-name.gif](height;width)      // ^image.font[alPHAbet;font-file-name.gif](spacebar_width;width)
         add_native_method("font", Method::CT_DYNAMIC, _font, 3, 4);          add_native_method("font", Method::CT_DYNAMIC, _font, 3, 4);
   
     // ^image.text(x;y)[text]      // ^image.text(x;y)[text]

Removed from v.1.30  
changed lines
  Added in v.1.39


E-mail: