|
|
| version 1.170, 2020/12/01 00:50:06 | version 1.184, 2023/09/26 20:49:05 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: @b image parser class. | Parser: @b image parser class. |
| Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> |
| */ | */ |
| /* | /* |
| Line 234 public: | Line 234 public: |
| class Measure_reader { | class Measure_reader { |
| public: | public: |
| virtual size_t read(const char* &buf, size_t limit)=0; | virtual size_t read(const char* &buf, size_t limit)=0; |
| virtual void seek(long value, int whence)=0; | virtual void seek(uint64_t value)=0; |
| virtual long tell()=0; | virtual uint64_t tell()=0; |
| virtual uint64_t length()=0; | |
| }; | }; |
| class Measure_file_reader: public Measure_reader { | class Measure_file_reader: public Measure_reader { |
| Line 258 public: | Line 259 public: |
| return read_size; | return read_size; |
| } | } |
| override void seek(long value, int whence) { | override void seek(uint64_t value) { |
| if(lseek(f, value, whence)<0) | if(pa_lseek(f, value, SEEK_SET)<0) |
| throw Exception(IMAGE_FORMAT, &file_name, "seek(value=%ld, whence=%d) failed: %s (%d)", value, whence, strerror(errno), errno); | throw Exception(IMAGE_FORMAT, &file_name, "seek to %.15g failed: %s (%d)", (double)value, strerror(errno), errno); |
| } | } |
| override long tell() { return lseek(f, 0, SEEK_CUR); } | override uint64_t tell() { return pa_lseek(f, 0, SEEK_CUR); } |
| override uint64_t length() { return pa_lseek(f, 0, SEEK_END); } | |
| }; | }; |
| Line 286 public: | Line 289 public: |
| return to_read; | return to_read; |
| } | } |
| override void seek(long value, int whence) { | override void seek(uint64_t value) { |
| size_t new_offset; | if(value>(uint64_t)size) |
| switch(whence) { | throw Exception(IMAGE_FORMAT, &file_name, "seek to %.15g failed: out of buffer (%.15g)", value, size); |
| case SEEK_CUR: new_offset=offset+value; break; | offset=(size_t)value; |
| case SEEK_SET: new_offset=(size_t)value; break; | |
| case SEEK_END: new_offset=size; break; | |
| default: | |
| throw Exception(0, 0, "whence #%d not supported", 0, whence); | |
| break; // never | |
| } | |
| if((ssize_t)new_offset<0 || new_offset>size) | |
| throw Exception(IMAGE_FORMAT, &file_name, "seek(value=%l, whence=%d) failed: out of buffer, new_offset>size (%l>%l) or new_offset<0", | |
| value, whence, new_offset, size); | |
| offset=new_offset; | |
| } | } |
| override long tell() { return offset; } | override uint64_t tell() { return offset; } |
| override uint64_t length() { return size; } | |
| }; | }; |
| Line 314 struct Measure_info { | Line 308 struct Measure_info { |
| Value** exif; | Value** exif; |
| Value** xmp; | Value** xmp; |
| Charset* xmp_charset; | Charset* xmp_charset; |
| bool video; | |
| }; | }; |
| Line 426 static Value* parse_IFD_entry_formatted_ | Line 421 static Value* parse_IFD_entry_formatted_ |
| size_t length=components_count; | size_t length=components_count; |
| // Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes | // Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes |
| if(length==JPEG_EXIF_DATE_CHARS && isdigit((unsigned char)cstr[0]) && cstr[length-1]==0) { | if(length==JPEG_EXIF_DATE_CHARS && isdigit((unsigned char)cstr[0]) && cstr[length-1]==0) { |
| char cstr_writable[JPEG_EXIF_DATE_CHARS]; | |
| strcpy(cstr_writable, cstr); | |
| try { | try { |
| tm tmIn=cstr_to_time_t(cstr_writable, 0); | tm tmIn=cstr_to_time_t(pa_strdup(cstr), 0); |
| return new VDate(tmIn); | return new VDate(tmIn); |
| } | } |
| catch(...) { /*ignore bad date times*/ } | catch(...) { /*ignore bad date times*/ } |
| Line 453 static Value* parse_IFD_entry_formatted_ | Line 445 static Value* parse_IFD_entry_formatted_ |
| return result; | return result; |
| } | } |
| static Value* parse_IFD_entry_value(bool is_big, Measure_reader& reader, long tiff_base, JPG_Exif_IFD_entry& entry) { | static Value* parse_IFD_entry_value(bool is_big, Measure_reader& reader, uint64_t tiff_base, JPG_Exif_IFD_entry& entry) { |
| size_t format2component_size[]={ | size_t format2component_size[]={ |
| 0, // undefined | 0, // undefined |
| 1, // unsigned byte | 1, // unsigned byte |
| Line 490 static Value* parse_IFD_entry_value(bool | Line 482 static Value* parse_IFD_entry_value(bool |
| if(value_size<=4) | if(value_size<=4) |
| result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, entry.value_or_offset_to_it); | result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, entry.value_or_offset_to_it); |
| else { | else { |
| long remembered=reader.tell(); | uint64_t remembered=reader.tell(); |
| { | { |
| reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it), SEEK_SET); | reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it)); |
| const char* value; | const char* value; |
| if(reader.read(value, value_size)<value_size) | if(reader.read(value, value_size)<value_size) |
| return 0; | return 0; |
| result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, (const uchar*)value); | result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, (const uchar*)value); |
| } | } |
| reader.seek(remembered, SEEK_SET); | reader.seek(remembered); |
| } | } |
| return result; | return result; |
| } | } |
| static void parse_IFD(HashStringValue& hash, bool is_big, Measure_reader& reader, long tiff_base, bool gps=false); | static void parse_IFD(HashStringValue& hash, bool is_big, Measure_reader& reader, uint64_t tiff_base, bool gps=false); |
| static void parse_IFD_entry(HashStringValue& hash, bool is_big, Measure_reader& reader, long tiff_base, JPG_Exif_IFD_entry& entry, bool gps=false) { | static void parse_IFD_entry(HashStringValue& hash, bool is_big, Measure_reader& reader, uint64_t tiff_base, JPG_Exif_IFD_entry& entry, bool gps=false) { |
| ushort tag=endian_to_ushort(is_big, entry.tag); | ushort tag=endian_to_ushort(is_big, entry.tag); |
| if(tag==JPG_IFD_TAG_EXIF_OFFSET || tag==JPG_IFD_TAG_EXIF_GPS_OFFSET){ | if(tag==JPG_IFD_TAG_EXIF_OFFSET || tag==JPG_IFD_TAG_EXIF_GPS_OFFSET){ |
| long remembered=reader.tell(); | uint64_t remembered=reader.tell(); |
| { | { |
| reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it), SEEK_SET); | reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it)); |
| parse_IFD(hash, is_big, reader, tiff_base, (tag==JPG_IFD_TAG_EXIF_GPS_OFFSET)?true:gps); | parse_IFD(hash, is_big, reader, tiff_base, (tag==JPG_IFD_TAG_EXIF_GPS_OFFSET)?true:gps); |
| } | } |
| reader.seek(remembered, SEEK_SET); | reader.seek(remembered); |
| return; | return; |
| } | } |
| Line 527 static void parse_IFD_entry(HashStringVa | Line 519 static void parse_IFD_entry(HashStringVa |
| } | } |
| } | } |
| static void parse_IFD(HashStringValue& hash, bool is_big, Measure_reader& reader, long tiff_base, bool gps) { | static void parse_IFD(HashStringValue& hash, bool is_big, Measure_reader& reader, uint64_t tiff_base, bool gps) { |
| const char* buf; | const char* buf; |
| if(reader.read(buf, sizeof(JPG_Exif_IFD_begin))<sizeof(JPG_Exif_IFD_begin)) | if(reader.read(buf, sizeof(JPG_Exif_IFD_begin))<sizeof(JPG_Exif_IFD_begin)) |
| return; | return; |
| Line 546 static void parse_IFD(HashStringValue& h | Line 538 static void parse_IFD(HashStringValue& h |
| static Value* parse_exif(Measure_reader& reader) { | static Value* parse_exif(Measure_reader& reader) { |
| const char* buf; | const char* buf; |
| uint tiff_base=reader.tell(); | uint64_t tiff_base=reader.tell(); |
| if(reader.read(buf, sizeof(JPG_Exif_TIFF_header))<sizeof(JPG_Exif_TIFF_header)) | if(reader.read(buf, sizeof(JPG_Exif_TIFF_header))<sizeof(JPG_Exif_TIFF_header)) |
| return 0; | return 0; |
| Line 554 static Value* parse_exif(Measure_reader& | Line 546 static Value* parse_exif(Measure_reader& |
| bool is_big=head->byte_align_identifier[0]=='M'; // [M]otorola vs [I]ntel | bool is_big=head->byte_align_identifier[0]=='M'; // [M]otorola vs [I]ntel |
| uint first_IFD_offset=endian_to_uint(is_big, head->first_IFD_offset); | uint first_IFD_offset=endian_to_uint(is_big, head->first_IFD_offset); |
| reader.seek(tiff_base+first_IFD_offset, SEEK_SET); | reader.seek(tiff_base+first_IFD_offset); |
| VHash* vhash=new VHash; | VHash* vhash=new VHash; |
| Line 592 static void measure_jpeg(const String& o | Line 584 static void measure_jpeg(const String& o |
| throw Exception(IMAGE_FORMAT, &origin_string, "not JPEG file - wrong signature"); | throw Exception(IMAGE_FORMAT, &origin_string, "not JPEG file - wrong signature"); |
| while(true) { | while(true) { |
| uint segment_base=reader.tell()+2/*marker,code*/; | uint64_t segment_base=reader.tell()+2/*marker,code*/; |
| if(reader.read(buf, sizeof(JPG_Segment_head))<sizeof(JPG_Segment_head)) | if(reader.read(buf, sizeof(JPG_Segment_head))<sizeof(JPG_Segment_head)) |
| break; | break; |
| JPG_Segment_head *head=(JPG_Segment_head *)buf; | JPG_Segment_head *head=(JPG_Segment_head *)buf; |
| Line 646 static void measure_jpeg(const String& o | Line 638 static void measure_jpeg(const String& o |
| return; | return; |
| }; | }; |
| reader.seek(segment_base + segment_length, SEEK_SET); | reader.seek(segment_base + segment_length); |
| } | } |
| throw Exception(IMAGE_FORMAT, &origin_string, "broken JPEG file - size frame not found"); | throw Exception(IMAGE_FORMAT, &origin_string, "broken JPEG file - size frame not found"); |
| Line 673 static bool parse_tiff_IFD(bool is_big, | Line 665 static bool parse_tiff_IFD(bool is_big, |
| if(entry_format != 3 && entry_format != 4 || endian_to_uint(is_big, entry->components_count) != 1) | if(entry_format != 3 && entry_format != 4 || endian_to_uint(is_big, entry->components_count) != 1) |
| return false; | return false; |
| uint value = (entry_format == 3) ? endian_to_ushort(is_big, entry->value_or_offset_to_it) : endian_to_uint(is_big, entry->value_or_offset_to_it); | uint value = (entry_format == 3) ? endian_to_ushort(is_big, entry->value_or_offset_to_it) : endian_to_uint(is_big, entry->value_or_offset_to_it); |
| (entry_tag == 256) ? info.width=value : info.height=value; | (entry_tag == 256) ? info.width=(short)value : info.height=(short)value; |
| if(info.width && info.height) | if(info.width && info.height) |
| return true; | return true; |
| } | } |
| Line 699 static void measure_tiff(const String& o | Line 691 static void measure_tiff(const String& o |
| if(endian_to_ushort(is_big, head->signature) != 42) | if(endian_to_ushort(is_big, head->signature) != 42) |
| throw Exception(IMAGE_FORMAT, &origin_string, "not TIFF file - wrong signature"); | throw Exception(IMAGE_FORMAT, &origin_string, "not TIFF file - wrong signature"); |
| reader.seek(endian_to_uint(is_big, head->first_IFD_offset), SEEK_SET); | reader.seek(endian_to_uint(is_big, head->first_IFD_offset)); |
| if(!parse_tiff_IFD(is_big, reader, info)) | if(!parse_tiff_IFD(is_big, reader, info)) |
| throw Exception(IMAGE_FORMAT, &origin_string, "broken TIFF file - size field entry not found"); | throw Exception(IMAGE_FORMAT, &origin_string, "broken TIFF file - size field entry not found"); |
| } | } |
| Line 785 static void measure_bmp(const String& or | Line 777 static void measure_bmp(const String& or |
| if(strncmp(head->signature, "BM", 2)!=0) | if(strncmp(head->signature, "BM", 2)!=0) |
| throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - wrong signature"); | throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - wrong signature"); |
| reader.seek(0, SEEK_END); | if((uint)reader.length() != endian_to_uint(false, head->file_size)) |
| if((uint)reader.tell() != endian_to_uint(false, head->file_size)) | |
| throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - length header and file size do not match"); | throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - length header and file size do not match"); |
| width=endian_to_ushort(false, head->width); | width=endian_to_ushort(false, head->width); |
| Line 875 struct MP4_Header { | Line 866 struct MP4_Header { |
| char signature[4]; // 'ftyp' in first chunk | char signature[4]; // 'ftyp' in first chunk |
| }; | }; |
| static bool measure_mp4(const String& origin_string, Measure_reader& reader, ushort& width, ushort& height, long anext, const char* lastTkhd=NULL) { | struct MP4_ExtSize { |
| uchar high[4]; | |
| uchar low[4]; | |
| }; | |
| struct MP4_Tkhd { | |
| uchar width[4]; | |
| uchar height[4]; | |
| }; | |
| static bool measure_mp4(const String& origin_string, Measure_reader& reader, ushort& width, ushort& height, uint64_t anext, const char* lastTkhd=NULL) { | |
| for(bool first=anext==0;;){ | for(bool first=anext==0;;){ |
| const char* buf; | const char* buf; |
| const size_t head_size=sizeof(MP4_Header); | uint64_t next=reader.tell(); |
| if(reader.read(buf, head_size)<head_size) | |
| throw Exception(IMAGE_FORMAT, &origin_string, first ? "not MP4 file - too small" : "broken MP4 file - small chunk header"); | if(reader.read(buf, sizeof(MP4_Header))<sizeof(MP4_Header)) |
| throw Exception(IMAGE_FORMAT, &origin_string, first ? "not MP4 file - too small" : "broken MP4 file - truncated chunk header"); | |
| MP4_Header *head=(MP4_Header *)buf; | MP4_Header *head=(MP4_Header *)buf; |
| uint size=endian_to_uint(true, head->size); | uint64_t size=endian_to_uint(true, head->size); |
| long next=reader.tell() + size - head_size; | |
| // printf("%d processing chunk size %d signature '%c%c%c%c %p'\n", anext, size, head->signature[0], head->signature[1], head->signature[2], head->signature[3], lastTkhd); | if(size==1){ |
| if(reader.read(buf, sizeof(MP4_ExtSize))<sizeof(MP4_ExtSize)) | |
| throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - truncated chunk extended size header"); | |
| MP4_ExtSize *ext_size=(MP4_ExtSize *)buf; | |
| size=((uint64_t)endian_to_uint(true, ext_size->high) << 32) + endian_to_uint(true, ext_size->low); | |
| } | |
| next+=size; | |
| if(first){ | if(first){ |
| if(strncmp(head->signature, "ftyp", 4)!=0) | if(strncmp(head->signature, "ftyp", 4)!=0) |
| throw Exception(IMAGE_FORMAT, &origin_string, "not MP4 file - wrong signature"); | throw Exception(IMAGE_FORMAT, &origin_string, "not MP4 file - wrong signature"); |
| first=false; | first=false; |
| anext=reader.length(); // to avoid reading beyond EOF | |
| } else if(strncmp(head->signature, "moov", 4)==0 || strncmp(head->signature, "mdia", 4)==0 || strncmp(head->signature, "trak", 4)==0) { | } else if(strncmp(head->signature, "moov", 4)==0 || strncmp(head->signature, "mdia", 4)==0 || strncmp(head->signature, "trak", 4)==0) { |
| if(measure_mp4(origin_string, reader, width, height, next, lastTkhd)) | if(measure_mp4(origin_string, reader, width, height, next, lastTkhd)) |
| return true; | return true; |
| } else if(strncmp(head->signature, "tkhd", 4)==0) { | } else if(strncmp(head->signature, "tkhd", 4)==0) { |
| if(size>8){ | if(size>8){ |
| reader.seek(next-8, SEEK_SET); | reader.seek(next-8); |
| if(reader.read(lastTkhd, 8)<8) | if(reader.read(lastTkhd, sizeof(MP4_Tkhd))<sizeof(MP4_Tkhd)) |
| throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - bad tkhd chunk"); | throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - bad tkhd chunk"); |
| } | } |
| } else if (strncmp(head->signature, "hdlr", 4)==0) { | } else if (strncmp(head->signature, "hdlr", 4)==0) { |
| Line 906 static bool measure_mp4(const String& or | Line 914 static bool measure_mp4(const String& or |
| const char* hdlr; | const char* hdlr; |
| if(reader.read(hdlr, 12)<12) | if(reader.read(hdlr, 12)<12) |
| throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - bad hdlr chunk"); | throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - bad hdlr chunk"); |
| // if(strncmp(hdlr+8, "vide", 4)==0) | if(lastTkhd && strncmp(hdlr+8, "vide", 4)==0) { |
| // printf("vide found\n"); | MP4_Tkhd *tkhd=(MP4_Tkhd *)lastTkhd; |
| if( lastTkhd && strncmp(hdlr+8, "vide", 4)==0) { | width=endian_to_ushort(true, tkhd->width); |
| width=endian_to_ushort(true, (const unsigned char*)(lastTkhd)); | height=endian_to_ushort(true, tkhd->height); |
| height=endian_to_ushort(true, (const unsigned char*)(lastTkhd+4)); | |
| // printf("wh %d %d\n",width, height); | |
| return true; | return true; |
| } | } |
| } | } |
| } | } |
| if(anext && next>=anext) | if(anext && next>=anext) |
| break; | break; |
| reader.seek(next, SEEK_SET); | reader.seek(next); |
| } | } |
| return false; | return false; |
| } | } |
| Line 946 static void measure(const String& file_n | Line 952 static void measure(const String& file_n |
| measure_webp(file_name, reader, info.width, info.height); | measure_webp(file_name, reader, info.width, info.height); |
| else if(strcasecmp(cext, "TIF")==0 || strcasecmp(cext, "TIFF")==0) | else if(strcasecmp(cext, "TIF")==0 || strcasecmp(cext, "TIFF")==0) |
| measure_tiff(file_name, reader, info); | measure_tiff(file_name, reader, info); |
| else if(strcasecmp(cext, "MP4")==0) | else if(strcasecmp(cext, "MP4")==0 || strcasecmp(cext, "MOV")==0) |
| measure_mp4(file_name, reader, info.width, info.height); | if(info.video) |
| measure_mp4(file_name, reader, info.width, info.height); | |
| else | |
| throw Exception(IMAGE_FORMAT, &file_name, "handling disabled for file name extension '%s'", cext); | |
| else | else |
| throw Exception(IMAGE_FORMAT, &file_name, "unhandled image file name extension '%s'", cext); | throw Exception(IMAGE_FORMAT, &file_name, "unhandled file name extension '%s'", cext); |
| } else | } else |
| throw Exception(IMAGE_FORMAT, &file_name, "can not determine image type - no file name extension"); | throw Exception(IMAGE_FORMAT, &file_name, "can not determine file type - no file name extension"); |
| } | } |
| // methods | // methods |
| Line 966 static void _measure(Request& r, MethodP | Line 975 static void _measure(Request& r, MethodP |
| Value* exif=0; | Value* exif=0; |
| Value* xmp=0; | Value* xmp=0; |
| Measure_info info={ 0, 0, 0, 0, &pa_UTF8_charset }; | Measure_info info={ 0, 0, 0, 0, &pa_UTF8_charset, false }; |
| if(params.count()>1) | if(params.count()>1) |
| if(HashStringValue* options=params.as_hash(1, "methods options")) { | if(HashStringValue* options=params.as_hash(1, "methods options")) { |
| Line 988 static void _measure(Request& r, MethodP | Line 997 static void _measure(Request& r, MethodP |
| info.xmp_charset=&pa_charsets.get(value->as_string()); | info.xmp_charset=&pa_charsets.get(value->as_string()); |
| valid_options++; | valid_options++; |
| } | } |
| if(key == "video") { | |
| info.video=r.process(*value).as_bool(); | |
| valid_options++; | |
| } | |
| } | } |
| if(valid_options!=options->count()) | if(valid_options!=options->count()) |
| throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); | throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); |
| Line 998 static void _measure(Request& r, MethodP | Line 1011 static void _measure(Request& r, MethodP |
| if(file_name=data.get_string()) { | if(file_name=data.get_string()) { |
| file_read_action_under_lock(r.full_disk_path(*file_name), "measure", file_measure_action, &info); | file_read_action_under_lock(r.full_disk_path(*file_name), "measure", file_measure_action, &info); |
| } else { | } else { |
| VFile* vfile=data.as_vfile(String::L_AS_IS); | VFile* vfile=data.as_vfile(); |
| file_name=&vfile->fields().get(name_name)->as_string(); | file_name=&vfile->fields().get(name_name)->as_string(); |
| Measure_buf_reader reader(vfile->value_ptr(), vfile->value_size(), *file_name); | Measure_buf_reader reader(vfile->value_ptr(), vfile->value_size(), *file_name); |
| measure(*file_name, reader, info); | measure(*file_name, reader, info); |
| Line 1167 static void _replace(Request& r, MethodP | Line 1180 static void _replace(Request& r, MethodP |
| gdImage::Point* all_p=0; | gdImage::Point* all_p=0; |
| size_t count=0; | size_t count=0; |
| if(params.count() == 3){ | if(params.count() == 3){ |
| Table* table=params.as_table(2, "coordinates"); | if(Table* table=params.as_table(2, "coordinates")){ |
| count=table->count(); | count=table->count(); |
| all_p=new(PointerFreeGC) gdImage::Point[count]; | all_p=new(PointerFreeGC) gdImage::Point[count]; |
| gdImage::Point* add_p=all_p; | gdImage::Point* add_p=all_p; |
| table->for_each(add_point, &add_p); | table->for_each(add_point, &add_p); |
| } | |
| } else { | } else { |
| int max_x=image.SX()-1; | int max_x=image.SX()-1; |
| int max_y=image.SY()-1; | int max_y=image.SY()-1; |
| Line 1193 static void _replace(Request& r, MethodP | Line 1207 static void _replace(Request& r, MethodP |
| 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_table(1, "coordinates"); | if(Table* table=params.as_table(1, "coordinates")){ |
| 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; | table->for_each(add_point, &add_p); |
| table->for_each(add_point, &add_p); | image.Polygon(all_p, table->count(), image.Color(params.as_int(0, "color must be int", r)), false/*not closed*/); |
| image.Polygon(all_p, table->count(), | } |
| image.Color(params.as_int(0, "color must be int", r)), | |
| false/*not closed*/); | |
| } | } |
| 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=(Table*)params.as_table(1, "coordinates"); | if(Table* table=(Table*)params.as_table(1, "coordinates")){ |
| 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; | table->for_each(add_point, &add_p); |
| table->for_each(add_point, &add_p); | image.Polygon(all_p, table->count(), image.Color(params.as_int(0, "color must be int", r))); |
| image.Polygon(all_p, table->count(), | } |
| image.Color(params.as_int(0, "color must be int", r))); | |
| } | } |
| 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=(Table*)params.as_table(1, "coordinates"); | if(Table* table=(Table*)params.as_table(1, "coordinates")){ |
| 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; | table->for_each(add_point, &add_p); |
| table->for_each(add_point, &add_p); | image.FilledPolygon(all_p, table->count(), image.Color(params.as_int(0, "color must be int", r))); |
| image.FilledPolygon(all_p, table->count(), | } |
| image.Color(params.as_int(0, "color must be int", r))); | |
| } | } |
| // font | // font |