--- parser3/src/classes/image.C 2002/11/21 09:18:18 1.77 +++ parser3/src/classes/image.C 2002/11/21 11:04:39 1.79 @@ -5,7 +5,7 @@ Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char* IDENT_IMAGE_C="$Date: 2002/11/21 09:18:18 $"; +static const char* IDENT_IMAGE_C="$Date: 2002/11/21 11:04:39 $"; /* jpegsize: gets the width and height (in pixels) of a jpeg file @@ -45,7 +45,8 @@ public: // Methoded class Measure_reader { public: virtual size_t read(const void *&buf, size_t limit)=0; - virtual void seek(long delta)=0; + virtual void seek(long value, int whence)=0; + virtual long tell()=0; }; class Measure_file_reader: public Measure_reader { @@ -69,14 +70,16 @@ public: return read_size; } - /*override*/void seek(long delta) { - if(lseek(f, delta, SEEK_CUR)<0) + /*override*/void seek(long value, int whence) { + if(lseek(f, value, whence)<0) throw Exception("file.seek", &file_name, - "seek(delta=%ld) failed: %s (%d), actual filename '%s'", - delta, strerror(errno), errno, fname); + "seek(value=%ld, whence=%d) failed: %s (%d), actual filename '%s'", + value, whence, strerror(errno), errno, fname); } + /*override*/long tell() { return ::tell(f); } + private: Pool& pool; const String& file_name; const char *fname; @@ -96,16 +99,24 @@ public: return to_read; } - /*override*/void seek(long delta) { - size_t new_offset=offset+delta; + /*override*/void seek(long value, int whence) { + size_t new_offset; + switch(whence) { + case SEEK_CUR: new_offset=offset+value; break; + case SEEK_SET: new_offset=(size_t)value; break; + default: throw Exception("file.seek", 0, "whence #%d not supported", 0, whence); break; + } + if((ssize_t)new_offset<0 || new_offset>size) throw Exception("file.seek", &file_name, - "seek(offset=%l) failed: out of buffer, new_offset>size (%l>%l) or new_offset<0", - delta, new_offset, size); + "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; } + private: const void *buf; size_t size; @@ -151,22 +162,27 @@ struct JPG_Size_segment_body { char numComponents; //< number of color components }; +/// JPEG frame header +struct JPG_Exif_segment_start { + char signature[6]; // Exif\0\0 +}; + // -inline short x_endian_to_int(unsigned char L, unsigned char H) { +inline ushort x_endian_to_ushort(unsigned char L, unsigned char H) { 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 ushort big_endian_to_ushort(unsigned char b[2]) { + return x_endian_to_ushort(b[1], b[0]); } -inline short little_endian_to_int(unsigned char b[2]) { - return x_endian_to_int(b[0], b[1]); +inline ushort little_endian_to_ushort(unsigned char b[2]) { + return x_endian_to_ushort(b[0], b[1]); } void measure_gif(Pool& pool, const String *origin_string, - Measure_reader& reader, int& width, int& height) { + Measure_reader& reader, ushort& width, ushort& height) { void *buf; const int head_size=sizeof(GIF_Header); @@ -181,17 +197,20 @@ void measure_gif(Pool& pool, const Strin origin_string, "not GIF file - wrong signature"); - width=little_endian_to_int(head->width); - height=little_endian_to_int(head->height); + width=little_endian_to_ushort(head->width); + height=little_endian_to_ushort(head->height); } /// @test remove ugly mech in reader - 20K limit void measure_jpeg(Pool& pool, const String *origin_string, - Measure_reader& reader, int& width, int& height) { + Measure_reader& reader, ushort& width, ushort& height) { // JFIF format markers const unsigned char MARKER=0xFF; - const unsigned char CODE_SIZE_FIRST=0xC0; - const unsigned char CODE_SIZE_LAST=0xC3; + const unsigned char CODE_SIZE_A=0xC0; + const unsigned char CODE_SIZE_B=0xC1; + const unsigned char CODE_SIZE_C=0xC2; + const unsigned char CODE_SIZE_D=0xC3; + const unsigned char CODE_EXIF=0xE1; void *buf; const size_t prefix_size=2; @@ -206,43 +225,63 @@ void measure_jpeg(Pool& pool, const Stri origin_string, "not JPEG file - wrong signature"); - bool found=false; while(true) { - void *buf; - // Extract the segment header. + long segment_base_offset=reader.tell()+2/*marker,code*/; if(reader.read(buf, sizeof(JPG_Segment_head))marker!=MARKER) - break; + throw Exception("image.format", + origin_string, + "not JPEG file - marker not found"); + + switch(head->code) { + // http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html + case CODE_EXIF: + { + if(reader.read(buf, sizeof(JPG_Exif_segment_start))signature, "Exif\0\0", 4+2)!=0) //signature invalid? + break; // ignore invalid block - if(head->code >= CODE_SIZE_FIRST && head->code <= CODE_SIZE_LAST) { - // Segments that contain size info - if(reader.read(buf, sizeof(JPG_Size_segment_body))width); - height=big_endian_to_int(body->height); - found=true; + // parse Exif block + } break; - } else { - // Dummy read to skip over data - long offset=big_endian_to_int(head->length) - 2; - reader.seek(offset); - } + + case CODE_SIZE_A: + case CODE_SIZE_B: + case CODE_SIZE_C: + case CODE_SIZE_D: + { + // Segments that contain size info + if(reader.read(buf, sizeof(JPG_Size_segment_body))width); + height=big_endian_to_ushort(body->height); + return; + } + }; + + reader.seek(segment_base_offset+big_endian_to_ushort(head->length), SEEK_SET); } - if(!found) - 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"); } void measure_png(Pool& pool, const String *origin_string, - Measure_reader& reader, int& width, int& height) { + Measure_reader& reader, ushort& width, ushort& height) { void *buf; const int head_size=sizeof(PNG_Header); @@ -257,14 +296,14 @@ void measure_png(Pool& pool, const Strin origin_string, "not PNG file - wrong signature"); - width=big_endian_to_int(head->width); - height=big_endian_to_int(head->height); + width=big_endian_to_ushort(head->width); + height=big_endian_to_ushort(head->height); } // measure center void measure(Pool& pool, const String& file_name, - Measure_reader& reader, int& width, int& height) { + Measure_reader& reader, ushort& width, ushort& height) { if(const char *cext=strrchr(file_name.cstr(String::UL_FILE_SPEC), '.')) { cext++; if(strcasecmp(cext, "GIF")==0) @@ -287,8 +326,8 @@ void measure(Pool& pool, const String& f #ifndef DOXYGEN struct File_measure_action_info { - int *width; - int *height; + ushort *width; + ushort *height; const String *file_name; }; #endif @@ -307,8 +346,8 @@ static void _measure(Request& r, const S Value& data=params->as_no_junction(0, "data must not be code"); - int width=0; - int height=0; + ushort width=0; + ushort height=0; const String *file_name; if(file_name=data.get_string()) { File_measure_action_info info={&width, &height, file_name};