--- parser3/src/classes/image.C 2020/12/07 23:18:40 1.178 +++ parser3/src/classes/image.C 2026/04/25 13:38:46 1.199 @@ -1,8 +1,8 @@ /** @file Parser: @b image parser class. - Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com) - Author: Alexandr Petrosian (http://paf.design.ru) + Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com) + Authors: Konstantin Morshnev , Alexandr Petrosian */ /* @@ -26,7 +26,7 @@ #include "pa_table.h" #include "pa_charsets.h" -volatile const char * IDENT_IMAGE_C="$Id: image.C,v 1.178 2020/12/07 23:18:40 moko Exp $"; +volatile const char * IDENT_IMAGE_C="$Id: image.C,v 1.199 2026/04/25 13:38:46 moko Exp $"; // defines @@ -189,7 +189,14 @@ public: EXIF_TAG(0xa434, LensModel); EXIF_TAG(0xa435, LensSerialNumber); } -} exif_tag_value2name; + + static EXIF_tag_value2name &instance(){ + static EXIF_tag_value2name *singleton=NULL; + if(!singleton) + singleton=new EXIF_tag_value2name; + return *singleton; + } +}; class EXIF_gps_tag_value2name: public Hash { public: @@ -226,7 +233,15 @@ public: EXIF_TAG(0x1D, GPSDateStamp); EXIF_TAG(0x1E, GPSDifferential); } -} exif_gps_tag_value2name; + + static EXIF_gps_tag_value2name &instance(){ + static EXIF_gps_tag_value2name *singleton=NULL; + if(!singleton) + singleton=new EXIF_gps_tag_value2name; + return *singleton; + } + +}; ///*********************************************** support functions @@ -308,6 +323,7 @@ struct Measure_info { Value** exif; Value** xmp; Charset* xmp_charset; + bool video; }; @@ -420,17 +436,14 @@ static Value* parse_IFD_entry_formatted_ size_t length=components_count; // 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) { - char cstr_writable[JPEG_EXIF_DATE_CHARS]; - strcpy(cstr_writable, cstr); - try { - tm tmIn=cstr_to_time_t(cstr_writable, 0); + tm tmIn=cstr_to_time_t(pa_strdup(cstr), 0); return new VDate(tmIn); } catch(...) { /*ignore bad date times*/ } } - return new VString(*new String(cstr, String::L_TAINTED)); + return new VString(cstr); } if(components_count==1) @@ -440,7 +453,7 @@ static Value* parse_IFD_entry_formatted_ HashStringValue& hash=result->hash(); for(uint i=0; iwidth); @@ -955,11 +968,14 @@ static void measure(const String& file_n else if(strcasecmp(cext, "TIF")==0 || strcasecmp(cext, "TIFF")==0) measure_tiff(file_name, reader, info); 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 - 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 - throw Exception(IMAGE_FORMAT, &file_name, "can not determine image type - no file name extension"); + throw Exception(IMAGE_FORMAT, &file_name, "cannot determine file type - no file name extension"); } // methods @@ -974,31 +990,26 @@ static void _measure(Request& r, MethodP Value* exif=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(HashStringValue* options=params.as_hash(1, "methods options")) { - int valid_options=0; for(HashStringValue::Iterator i(*options); i; i.next() ){ String::Body key=i.key(); Value* value=i.value(); if(key == "exif") { if(r.process(*value).as_bool()) info.exif=&exif; - valid_options++; - } - if(key == "xmp") { + } else if(key == "xmp") { if(r.process(*value).as_bool()) info.xmp=&xmp; - valid_options++; - } - if(key == "xmp-charset") { + } else if(key == "xmp-charset") { info.xmp_charset=&pa_charsets.get(value->as_string()); - valid_options++; - } + } else if(key == "video") { + info.video=r.process(*value).as_bool(); + } else + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); } - if(valid_options!=options->count()) - throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); } const String* file_name; @@ -1006,7 +1017,7 @@ static void _measure(Request& r, MethodP if(file_name=data.get_string()) { file_read_action_under_lock(r.full_disk_path(*file_name), "measure", file_measure_action, &info); } else { - VFile* vfile=data.as_vfile(String::L_AS_IS); + VFile* vfile=data.as_vfile(); file_name=&vfile->fields().get(name_name)->as_string(); Measure_buf_reader reader(vfile->value_ptr(), vfile->value_size(), *file_name); measure(*file_name, reader, info); @@ -1070,13 +1081,13 @@ static gdImage* load(Request& r, const S throw Exception(IMAGE_FORMAT, &file_name, "is not in GIF format"); return image; } else { - throw Exception("file.missing", 0, "can not open '%s'", file_name_cstr); + throw Exception("file.missing", 0, "cannot open '%s'", file_name_cstr); } } static void _load(Request& r, MethodParams& params) { - const String& file_name=params.as_string(0, FILE_NAME_MUST_NOT_BE_CODE); + const String& file_name=params.as_file_name(0); gdImage* image=load(r, file_name); GET_SELF(r, VImage).set(&file_name, image->SX(), image->SY(), image); @@ -1175,11 +1186,12 @@ static void _replace(Request& r, MethodP gdImage::Point* all_p=0; size_t count=0; if(params.count() == 3){ - Table* table=params.as_table(2, "coordinates"); - count=table->count(); - all_p=new(PointerFreeGC) gdImage::Point[count]; - gdImage::Point* add_p=all_p; - table->for_each(add_point, &add_p); + if(Table* table=params.as_table(2, "coordinates")){ + 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; @@ -1201,38 +1213,34 @@ static void _replace(Request& r, MethodP static void _polyline(Request& r, MethodParams& params) { gdImage& image=GET_SELF(r, VImage).image(); - Table* table=params.as_table(1, "coordinates"); - - gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()]; - gdImage::Point *add_p=all_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*/); + if(Table* table=params.as_table(1, "coordinates")){ + gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()]; + gdImage::Point *add_p=all_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*/); + } } static void _polygon(Request& r, MethodParams& params) { gdImage& image=GET_SELF(r, VImage).image(); - Table* table=(Table*)params.as_table(1, "coordinates"); - - gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()]; - gdImage::Point *add_p=all_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))); + if(Table* table=(Table*)params.as_table(1, "coordinates")){ + gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()]; + gdImage::Point *add_p=all_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))); + } } static void _polybar(Request& r, MethodParams& params) { gdImage& image=GET_SELF(r, VImage).image(); - Table* table=(Table*)params.as_table(1, "coordinates"); - - gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()]; - gdImage::Point *add_p=all_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))); + if(Table* table=(Table*)params.as_table(1, "coordinates")){ + gdImage::Point* all_p=new(PointerFreeGC) gdImage::Point[table->count()]; + gdImage::Point *add_p=all_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))); + } } // font @@ -1330,12 +1338,12 @@ void Font::string_display(gdImage& image 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 be string"); size_t alphabet_length=alphabet.length(r.charsets.source()); if(!alphabet_length) throw Exception(PARSER_RUNTIME, 0, "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_file_name(1)); int spacebar_width=image->SX(); int monospace_width=0; // proportional @@ -1382,14 +1390,14 @@ static void _font(Request& r, MethodPara static void _text(Request& r, MethodParams& params) { int x=params.as_int(0, "x must be int", r); int y=params.as_int(1, "y must be int", r); - const String& s=params.as_string(2, "text must not be code"); + const String& s=params.as_string(2, "text must be string"); VImage& vimage=GET_SELF(r, VImage); vimage.font().string_display(vimage.image(), x, y, s); } static void _length(Request& r, MethodParams& params) { - const String& s=params.as_string(0, "text must not be code"); + const String& s=params.as_string(0, "text must be string"); VImage& vimage=GET_SELF(r, VImage); r.write(*new VInt(vimage.font().string_width(s))); @@ -1438,8 +1446,8 @@ static void _circle(Request& r, MethodPa gdImage& as_image(MethodParams& params, int index, const char* msg) { Value& value=params.as_no_junction(index, msg); - if(Value* vimage=value.as(VIMAGE_TYPE)) { - return static_cast(vimage)->image(); + if(VImage* vimage=dynamic_cast(&value)) { + return vimage->image(); } else throw Exception(PARSER_RUNTIME, 0, msg); }