--- parser3/src/classes/image.C 2019/12/03 15:09:49 1.166 +++ parser3/src/classes/image.C 2020/11/30 16:44:24 1.168 @@ -26,7 +26,7 @@ #include "pa_table.h" #include "pa_charsets.h" -volatile const char * IDENT_IMAGE_C="$Id: image.C,v 1.166 2019/12/03 15:09:49 moko Exp $"; +volatile const char * IDENT_IMAGE_C="$Id: image.C,v 1.168 2020/11/30 16:44:24 moko Exp $"; // defines @@ -383,6 +383,34 @@ struct JPG_Exif_IFD_entry { #define JPEG_EXIF_DATE_CHARS 20 +/// WEBP file header +struct WEBP_Header { + char signature_riff[4]; // 'RIFF' + uchar file_size[4]; + char signature[4]; // 'WEBP' + char format[4]; // 'VP8 ' or 'VP8L' or 'VP8X' +}; + +struct WEBP_VP8_Chunk { + uchar size[4]; + char tag[3]; + uchar signature[3]; // 0x9D 0x01 0x2A + uchar width[2]; // 14 bits each + uchar height[2]; // 14 bits each +}; + +struct WEBP_VP8L_Chunk { + uchar size[4]; + char signature; // 0x2F + uchar width_height[4]; // 14 bits each +}; + +struct WEBP_X_Chunk { + uchar size[4]; + char reserved[4]; + uchar width[3]; + uchar height[3]; +}; #ifndef DOXYGEN struct Measure_info { @@ -405,13 +433,11 @@ inline uint x_endian_to_uint(uchar b0, u } inline ushort endian_to_ushort(bool is_big, const uchar *b/* [2] */) { - return is_big?x_endian_to_ushort(b[1], b[0]): - x_endian_to_ushort(b[0], b[1]); + return is_big ? x_endian_to_ushort(b[1], b[0]) : x_endian_to_ushort(b[0], b[1]); } inline uint endian_to_uint(bool is_big, const uchar *b /* [4] */) { - return is_big?x_endian_to_uint(b[3], b[2], b[1], b[0]): - x_endian_to_uint(b[0], b[1], b[2], b[3]); + return is_big ? x_endian_to_uint(b[3], b[2], b[1], b[0]) : x_endian_to_uint(b[0], b[1], b[2], b[3]); } static Value* parse_IFD_entry_formatted_one_value(bool is_big, ushort format, size_t component_size, const uchar *value) { @@ -790,6 +816,50 @@ static void measure_bmp(const String& or height=endian_to_ushort(false, head->height); } + +static void measure_webp(const String& origin_string, Measure_reader& reader, ushort& width, ushort& height) { + const char* buf; + + if(reader.read(buf, sizeof(WEBP_Header))signature_riff, "RIFF", 4)!=0 || strncmp(head->signature, "WEBP", 4)!=0) + throw Exception(IMAGE_FORMAT, &origin_string, "not WEBP file - wrong signature"); + + if(strncmp(head->format, "VP8 ", 4)==0){ + if(reader.read(buf, sizeof(WEBP_VP8_Chunk))signature[0] != 0x9D || chunk->signature[1] != 0x01 || chunk->signature[2] != 0x2A) + throw Exception(IMAGE_FORMAT, &origin_string, "broken WEBP file - wrong VP8 chunk signature"); + + width=endian_to_ushort(false, chunk->width) & 0x3FFF; + height=endian_to_ushort(false, chunk->height) & 0x3FFF; + } else if(strncmp(head->format, "VP8L", 4)==0){ + if(reader.read(buf, sizeof(WEBP_VP8L_Chunk))signature != 0x2F) + throw Exception(IMAGE_FORMAT, &origin_string, "broken WEBP file - wrong VP8L chunk signature"); + + uint wh=endian_to_uint(false, chunk->width_height); + width=(wh & 0x3FFF) + 1; + height=((wh >> 14) & 0x3FFF) + 1; + } else if (strncmp(head->format, "VP8X", 4)==0){ + if(reader.read(buf, sizeof(WEBP_X_Chunk))width) + 1; // we ignore third byte to simplify code + height=endian_to_ushort(false, chunk->height) + 1; // we ignore third byte to simplify code + } else throw Exception(IMAGE_FORMAT, &origin_string, "broken WEBP file - invalid chunk signature"); +} + // measure center static void measure(const String& file_name, Measure_reader& reader, Measure_info &info) { @@ -804,6 +874,8 @@ static void measure(const String& file_n measure_png(file_name, reader, info.width, info.height); else if(strcasecmp(cext, "BMP")==0) measure_bmp(file_name, reader, info.width, info.height); + else if(strcasecmp(cext, "WEBP")==0) + measure_webp(file_name, reader, info.width, info.height); else if(strcasecmp(cext, "TIF")==0 || strcasecmp(cext, "TIFF")==0) measure_tiff(file_name, reader, info); else @@ -854,7 +926,7 @@ static void _measure(Request& r, MethodP const String* file_name; if(file_name=data.get_string()) { - file_read_action_under_lock(r.absolute(*file_name), "measure", file_measure_action, &info); + 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); file_name=&vfile->fields().get(name_name)->as_string(); @@ -911,7 +983,7 @@ static void _html(Request& r, MethodPara /// @test wrap FILE to auto-object static gdImage* load(Request& r, const String& file_name){ - const char* file_name_cstr=r.absolute(file_name).taint_cstr(String::L_FILE_SPEC); + const char* file_name_cstr=r.full_disk_path(file_name).taint_cstr(String::L_FILE_SPEC); if(FILE *f=pa_fopen(file_name_cstr, "rb")) { gdImage* image=new gdImage; bool ok=image->CreateFromGif(f);