Diff for /parser3/src/classes/image.C between versions 1.125 and 1.140

version 1.125, 2009/06/24 09:09:50 version 1.140, 2012/06/08 11:44:01
Line 1 Line 1
 /** @file  /** @file
         Parser: @b image parser class.          Parser: @b image parser class.
   
         Copyright(c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com)
         Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
 */  */
   
 static const char * const IDENT_IMAGE_C="$Date$";  
   
 /*  /*
         jpegsize: gets the width and height (in pixels) of a jpeg file          jpegsize: gets the width and height (in pixels) of a jpeg file
         Andrew Tong, werdna@ugcs.caltech.edu           February 14, 1995          Andrew Tong, werdna@ugcs.caltech.edu           February 14, 1995
Line 17  static const char * const IDENT_IMAGE_C= Line 15  static const char * const IDENT_IMAGE_C=
 */  */
   
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
   
 #include "pa_vmethod_frame.h"  
   
 #include "gif.h"  #include "gif.h"
   
   #include "pa_vmethod_frame.h"
 #include "pa_common.h"  #include "pa_common.h"
 #include "pa_request.h"  #include "pa_request.h"
 #include "pa_vfile.h"  #include "pa_vfile.h"
Line 29  static const char * const IDENT_IMAGE_C= Line 25  static const char * const IDENT_IMAGE_C=
 #include "pa_vdate.h"  #include "pa_vdate.h"
 #include "pa_table.h"  #include "pa_table.h"
   
   volatile const char * IDENT_IMAGE_C="$Id$";
   
 // defines  // defines
   
 static const String spacebar_width_name("space-width");  static const String spacebar_width_name("space");
 static const String monospace_width_name("letter-width");  static const String monospace_width_name("width");
 static const String letter_spacing_name("letter-space");  static const String letter_spacing_name("spacing");
   
 // class  // class
   
 class MImage: public Methoded {  class MImage: public Methoded {
 public: // VStateless_class  public: // VStateless_class
         Value* create_new_value(Pool&, HashStringValue*) { return new VImage(); }          Value* create_new_value(Pool&) { return new VImage(); }
   
 public:  public:
         MImage();          MImage();
   
 public: // Methoded  
         bool used_directly() { return true; }  
   
 };  };
   
 // globals  // globals
Line 731  static void measure_png(const String& or Line 725  static void measure_png(const String& or
   
 static void measure(const String& file_name,   static void measure(const String& file_name, 
                          Measure_reader& reader, ushort& width, ushort& height, Value** exif) {                           Measure_reader& reader, ushort& width, ushort& height, Value** exif) {
         const char* file_name_cstr=file_name.cstr(String::L_FILE_SPEC);          const char* file_name_cstr=file_name.taint_cstr(String::L_FILE_SPEC);
         if(const char* cext=strrchr(file_name_cstr, '.')) {          if(const char* cext=strrchr(file_name_cstr, '.')) {
                 cext++;                  cext++;
                 if(strcasecmp(cext, "GIF")==0)                  if(strcasecmp(cext, "GIF")==0)
Line 786  static void _measure(Request& r, MethodP Line 780  static void _measure(Request& r, MethodP
                 file_read_action_under_lock(r.absolute(*file_name),                   file_read_action_under_lock(r.absolute(*file_name), 
                         "measure", file_measure_action, &info);                          "measure", file_measure_action, &info);
         } else {          } else {
                 VFile* vfile=data.as_vfile();                  VFile* vfile=data.as_vfile(String::L_AS_IS);
                 file_name=&vfile->fields().get(name_name)->as_string();                  file_name=&vfile->fields().get(name_name)->as_string();
                 Measure_buf_reader reader(                  Measure_buf_reader reader(
                         vfile->value_ptr(),                          vfile->value_ptr(),
Line 806  struct Attrib_info { Line 800  struct Attrib_info {
 };  };
 #endif  #endif
 static void append_attrib_pair(  static void append_attrib_pair(
                                HashStringValue::key_type key,                                   HashStringValue::key_type key, 
                                HashStringValue::value_type value,                                   HashStringValue::value_type value, 
                                Attrib_info* info) {                                  Attrib_info* info) {
         // skip user-specified and internal(starting with "line-") attributes           // skip user-specified, internal(starting with "line-") attributes and border attribute with empty value
         if(info->skip && info->skip->get(key) || key.pos("line-")==0)          if(
                   (info->skip && info->skip->get(key))
                   || key.pos("line-")==0
                   || (key=="border" && !value->is_defined())
           )
                 return;                  return;
   
         // src="a.gif" width=123 ismap[=-1]          // src="a.gif" width="123" ismap[=-1]
         *info->tag << " " << key;          *info->tag << " " << key;
         if(value->is_string() || value->as_int()>=0)          if(value->is_string() || value->as_int()>=0)
                 *info->tag << "=\"" << value->as_string() << "\"";                  *info->tag << "=\"" << value->as_string() << "\"";
Line 828  static void _html(Request& r, MethodPara Line 826  static void _html(Request& r, MethodPara
   
         if(params.count()) {          if(params.count()) {
                 // for backward compatibility: someday was ^html{}                  // for backward compatibility: someday was ^html{}
                 Value& vattribs=r.process_to_value(params[0],                  Value& vattribs=r.process_to_value(params[0], false/*don't intercept string*/);
                         false/*don't intercept string*/);  
                 if(!vattribs.is_string()) // allow empty                  if(!vattribs.is_string()) // allow empty
                         if((attribs=vattribs.get_hash())) {                          if((attribs=vattribs.get_hash())) {
                                 Attrib_info info={&tag, 0};                                  Attrib_info info={&tag, 0};
Line 851  static void _html(Request& r, MethodPara Line 848  static void _html(Request& r, MethodPara
 /// @test wrap FILE to auto-object  /// @test wrap FILE to auto-object
 static gdImage* load(Request& r,   static gdImage* load(Request& r, 
                                          const String& file_name){                                           const String& file_name){
         const char* file_name_cstr=r.absolute(file_name).cstr(String::L_FILE_SPEC);          const char* file_name_cstr=r.absolute(file_name).taint_cstr(String::L_FILE_SPEC);
         if(FILE *f=fopen(file_name_cstr, "rb")) {          if(FILE *f=fopen(file_name_cstr, "rb")) {
                 gdImage* image=new gdImage;                  gdImage* image=new gdImage;
                 bool ok=image->CreateFromGif(f);                  bool ok=image->CreateFromGif(f);
Line 891  static void _create(Request& r, MethodPa Line 888  static void _create(Request& r, MethodPa
 static void _gif(Request& r, MethodParams& params) {  static void _gif(Request& r, MethodParams& params) {
         gdImage& image=GET_SELF(r, VImage).image();          gdImage& image=GET_SELF(r, VImage).image();
   
         const String *file_name=0;          const String *file_name=params.count()>0?&params.as_string(0, FILE_NAME_MUST_BE_STRING):0;
         if(params.count()>0)  
                 file_name=&params.as_string(0, FILE_NAME_MUST_BE_STRING);  
   
         gdBuf buf=image.Gif();          gdBuf buf=image.Gif();
                   
         VFile& vfile=*new VFile;          VFile& vfile=*new VFile;
         Value* content_type=new VString(*new String("image/gif"));  
         vfile.set(false/*not tainted*/,           vfile.set(false/*not tainted*/,
                 (const char*)buf.ptr, buf.size,                   (const char*)buf.ptr, buf.size,
                 file_name? file_name->cstr(String::L_FILE_SPEC): 0,                   file_name,
                 content_type);                  new VString(*new String("image/gif")));
   
           vfile.set_mode(false/*binary*/);
   
         r.write_no_lang(vfile);          r.write_no_lang(vfile);
 }  }
Line 961  static void add_point(Table::element_typ Line 958  static void add_point(Table::element_typ
         (*p)++;          (*p)++;
 }  }
 #endif  #endif
   #ifndef DOXYGEN
   static void add_point(int x, int y, 
                                             gdImage::Point **p) {
           (**p).x=x;
           (**p).y=y;
           (*p)++;
   }
   #endif
 static void _replace(Request& r, MethodParams& params) {  static void _replace(Request& r, MethodParams& params) {
           int src_color=params.as_int(0, "src color must be int", r);
           int dest_color=params.as_int(1, "dest color must be int", r);
   
         gdImage& image=GET_SELF(r, VImage).image();          gdImage& image=GET_SELF(r, VImage).image();
   
         Table* table=params.as_no_junction(2, COORDINATES_MUST_NOT_BE_CODE).get_table();          gdImage::Point* all_p=0;
         if(!table)           size_t count=0;
                 throw Exception(PARSER_RUNTIME,          if(params.count() == 3){
                         0,                  Table* table=params.as_table(2, "coordinates");
                         "coordinates must be table");                  count=table->count();
                   all_p=new(PointerFreeGC) gdImage::Point[count];
                   gdImage::Point* add_p=all_p;
                   table->for_each(add_point, &add_p);
           } else {
                   int max_x=image.SX()-1;
                   int max_y=image.SY()-1;
                   if(max_x > 0 && max_y > 0){
                           count=4;
                           all_p=new(PointerFreeGC) gdImage::Point[count];
                           gdImage::Point* add_p=all_p;
                           add_point(0, 0, &add_p);
                           add_point(max_x, 0, &add_p);
                           add_point(max_x, max_y, &add_p);
                           add_point(0, max_y, &add_p);
                   }
           }
   
         gdImage::Point *all_p=new(PointerFreeGC) gdImage::Point[table->count()];          if(count)
         gdImage::Point *add_p=all_p;                      image.FilledPolygonReplaceColor(all_p, count, image.Color(src_color), image.Color(dest_color));
         table->for_each(add_point, &add_p);  
         image.FilledPolygonReplaceColor(all_p, table->count(),   
                 image.Color(params.as_int(0, "src color must be int", r)),  
                 image.Color(params.as_int(1, "dest color must be int", r)));  
 }  }
   
 static void _polyline(Request& r, MethodParams& params) {  static void _polyline(Request& r, MethodParams& params) {
         gdImage& image=GET_SELF(r, VImage).image();          gdImage& image=GET_SELF(r, VImage).image();
   
         Table* table=params.as_no_junction(1, COORDINATES_MUST_NOT_BE_CODE).get_table();          Table* table=params.as_table(1, "coordinates");
         if(!table)   
                 throw Exception(PARSER_RUNTIME,  
                         0,  
                         "coordinates must be table");  
   
         gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()];          gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()];
         gdImage::Point *add_p=all_p;              gdImage::Point *add_p=all_p;    
Line 998  static void _polyline(Request& r, Method Line 1014  static void _polyline(Request& r, Method
 static void _polygon(Request& r, MethodParams& params) {  static void _polygon(Request& r, MethodParams& params) {
         gdImage& image=GET_SELF(r, VImage).image();          gdImage& image=GET_SELF(r, VImage).image();
   
         Table* table=params.as_no_junction(1, COORDINATES_MUST_NOT_BE_CODE).get_table();          Table* table=(Table*)params.as_table(1, "coordinates");
         if(!table)   
                 throw Exception(PARSER_RUNTIME,  
                         0,  
                         "coordinates must be table");  
   
         gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()];          gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()];
         gdImage::Point *add_p=all_p;              gdImage::Point *add_p=all_p;    
Line 1014  static void _polygon(Request& r, MethodP Line 1026  static void _polygon(Request& r, MethodP
 static void _polybar(Request& r, MethodParams& params) {  static void _polybar(Request& r, MethodParams& params) {
         gdImage& image=GET_SELF(r, VImage).image();          gdImage& image=GET_SELF(r, VImage).image();
   
         Table* table=params.as_no_junction(1, COORDINATES_MUST_NOT_BE_CODE).get_table();          Table* table=(Table*)params.as_table(1, "coordinates");
         if(!table)   
                 throw Exception(PARSER_RUNTIME,  
                         0,  
                         "coordinates must be table");  
   
         gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()];          gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()];
         gdImage::Point *add_p=all_p;              gdImage::Point *add_p=all_p;    
Line 1033  static void _polybar(Request& r, MethodP Line 1041  static void _polybar(Request& r, MethodP
   
 // Font class  // Font class
   
 Font::Font(//,   Font::Font(
           Charset& asource_charset, 
         const String& aalphabet,           const String& aalphabet, 
         gdImage* aifont, int aheight, int amonospace, int aspacebarspace, int aletterspacing):          gdImage* aifont, int aheight, int amonospace, int aspacebarspace, int aletterspacing):
         height(aheight), monospace(amonospace),  spacebarspace(aspacebarspace),          fsource_charset(asource_charset),
           height(aheight),
           monospace(amonospace),
           spacebarspace(aspacebarspace),
         letterspacing(aletterspacing),          letterspacing(aletterspacing),
         ifont(aifont),          ifont(aifont),
         alphabet(aalphabet)     {          alphabet(aalphabet)     {
   
           if(fsource_charset.isUTF8()){
                   size_t index=0;
                   for(UTF8_string_iterator i(alphabet); i.has_next(); )
                           fletter2index.put_dont_replace(i.next(), index++);
           }
 }  }
   
 /* ******************************** char ********************************** */  /* ******************************** char ********************************** */
Line 1049  size_t Font::index_of(char ch) { Line 1067  size_t Font::index_of(char ch) {
         return alphabet.pos(ch);          return alphabet.pos(ch);
 }  }
   
   size_t Font::index_of(XMLCh ch) {
           if(ch==' ') return STRING_NOT_FOUND;
           return fletter2index.get(ch);
   }
   
 int Font::index_width(size_t index) {  int Font::index_width(size_t index) {
         if(index==STRING_NOT_FOUND)          if(index==STRING_NOT_FOUND)
                 return spacebarspace;                  return spacebarspace;
Line 1076  int Font::step_width(int index) { Line 1099  int Font::step_width(int index) {
 int Font::string_width(const String& s){  int Font::string_width(const String& s){
         const char* cstr=s.cstr();          const char* cstr=s.cstr();
         int result=0;          int result=0;
         for(const char* current=cstr; *current; current++)  
                 result+=step_width(index_of(*current));          if(fsource_charset.isUTF8()){
                   for(UTF8_string_iterator i(s); i.has_next(); )
                           result+=step_width(index_of(i.next()));
           } else {
                   for(const char* current=cstr; *current; current++)
                           result+=step_width(index_of(*current));
           }
   
         return result;          return result;
 }  }
   
 void Font::string_display(gdImage& image, int x, int y, const String& s){  void Font::string_display(gdImage& image, int x, int y, const String& s){
         const char* cstr=s.cstr();          const char* cstr=s.cstr();
         for(const char* current=cstr; *current; current++) {  
                 size_t index=index_of(*current);          if(fsource_charset.isUTF8()){
                 index_display(image, x, y, index);                  for(UTF8_string_iterator i(s); i.has_next(); ){
                 x+=step_width(index);                          size_t index=index_of(i.next());
                           index_display(image, x, y, index);
                           x+=step_width(index);
                   }
           } else {
                   for(const char* current=cstr; *current; current++) {
                           size_t index=index_of(*current);
                           index_display(image, x, y, index);
                           x+=step_width(index);
                   }
         }          }
 }  }
   
Line 1095  void Font::string_display(gdImage& image Line 1134  void Font::string_display(gdImage& image
   
 static void _font(Request& r, MethodParams& params) {  static void _font(Request& r, MethodParams& params) {
         const String& alphabet=params.as_string(0, "alphabet must not be code");          const String& alphabet=params.as_string(0, "alphabet must not be code");
         if(!alphabet.length())          size_t alphabet_length=alphabet.length(r.charsets.source());
           if(!alphabet_length)
                 throw Exception(PARSER_RUNTIME,                  throw Exception(PARSER_RUNTIME,
                         0,                          0,
                         "alphabet must not be empty");                          "alphabet must not be empty");
   
         gdImage* image=load(r, params.as_string(1, FILE_NAME_MUST_NOT_BE_CODE));          gdImage* image=load(r, params.as_string(1, FILE_NAME_MUST_NOT_BE_CODE));
   
         int spacebar_width=0;          int spacebar_width=image->SX();
         int monospace_width=0; // proportional          int monospace_width=0; // proportional
         int letter_spacing=1;          int letter_spacing=1;
         if(params.count()>2){          if(params.count()>2){
Line 1128  static void _font(Request& r, MethodPara Line 1168  static void _font(Request& r, MethodPara
                                 letter_spacing=r.process_to_value(*vletter_spacing).as_int();                                  letter_spacing=r.process_to_value(*vletter_spacing).as_int();
                         }                          }
                         if(valid_options!=options->count())                          if(valid_options!=options->count())
                                 throw Exception(PARSER_RUNTIME,                                  throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                                         0,  
                                         "called with invalid option");  
                 } else {                  } else {
                         // backward                          // backward
                         spacebar_width=params.as_int(2, "spacebar_width must be int", r);                          spacebar_width=params.as_int(2, "spacebar_width must be int", r);
Line 1142  static void _font(Request& r, MethodPara Line 1180  static void _font(Request& r, MethodPara
                 }                  }
         }          }
   
         if(int remainder=image->SY() % alphabet.length())          if(int remainder=image->SY() % alphabet_length)
                 throw Exception(PARSER_RUNTIME,                  throw Exception(PARSER_RUNTIME,
                         0,                          0,
                         "font-file height(%d) not divisable by alphabet size(%d), remainder=%d",                          "font-file height(%d) not divisable by alphabet size(%d), remainder=%d",
                                 image->SY(), alphabet.length(), remainder);                                  image->SY(), alphabet_length, remainder);
                   
         GET_SELF(r, VImage).set_font(new Font(          GET_SELF(r, VImage).set_font(new Font(
                   r.charsets.source(),
                 alphabet,                   alphabet, 
                 image,                   image, 
                 image->SY() / alphabet.length(), monospace_width, spacebar_width, letter_spacing));                  image->SY() / alphabet_length, monospace_width, spacebar_width, letter_spacing));
 }  }
   
 static void _text(Request& r, MethodParams& params) {  static void _text(Request& r, MethodParams& params) {
Line 1213  static void _circle(Request& r, MethodPa Line 1252  static void _circle(Request& r, MethodPa
 gdImage& as_image(MethodParams& params, int index, const char* msg) {  gdImage& as_image(MethodParams& params, int index, const char* msg) {
         Value& value=params.as_no_junction(index, msg);          Value& value=params.as_no_junction(index, msg);
   
         if(Value* vimage=value.as(VIMAGE_TYPE, false)) {          if(Value* vimage=value.as(VIMAGE_TYPE)) {
                 return static_cast<VImage *>(vimage)->image();                  return static_cast<VImage *>(vimage)->image();
         } else          } else
                 throw Exception(PARSER_RUNTIME,                   throw Exception(PARSER_RUNTIME, 
Line 1291  MImage::MImage(): Methoded("image") { Line 1330  MImage::MImage(): Methoded("image") {
         add_native_method("bar", Method::CT_DYNAMIC, _bar, 5, 5);          add_native_method("bar", Method::CT_DYNAMIC, _bar, 5, 5);
   
         // ^image.replace(color-source;color-dest)[table x:y]          // ^image.replace(color-source;color-dest)[table x:y]
         add_native_method("replace", Method::CT_DYNAMIC, _replace, 3, 3);          // ^image.replace(color-source;color-dest)
           add_native_method("replace", Method::CT_DYNAMIC, _replace, 2, 3);
   
         // ^image.polyline(color)[table x:y]          // ^image.polyline(color)[table x:y]
         add_native_method("polyline", Method::CT_DYNAMIC, _polyline, 2, 2);          add_native_method("polyline", Method::CT_DYNAMIC, _polyline, 2, 2);

Removed from v.1.125  
changed lines
  Added in v.1.140


E-mail: