--- parser3/src/classes/image.C 2002/11/25 15:37:12 1.83 +++ parser3/src/classes/image.C 2003/01/28 15:42:39 1.90.2.2 @@ -1,11 +1,11 @@ /** @file Parser: @b image parser class. - Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) + Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char* IDENT_IMAGE_C="$Date: 2002/11/25 15:37:12 $"; +static const char* IDENT_IMAGE_C="$Date: 2003/01/28 15:42:39 $"; /* jpegsize: gets the width and height (in pixels) of a jpeg file @@ -24,12 +24,13 @@ static const char* IDENT_IMAGE_C="$Date: #include "pa_request.h" #include "pa_vfile.h" #include "pa_vimage.h" +#include "pa_vdate.h" // class class MImage : public Methoded { public: // VStateless_class - Value *create_new_value(Pool& pool) { return new(pool) VImage(pool); } + ValuePtr create_new_value() { return ValuePtr(new VImage()); } public: MImage(Pool& pool); @@ -41,6 +42,10 @@ public: // Methoded // helpers +/// value of exif tag -> it's value +Hash exif_tag_value2name; + + #ifndef DOXYGEN class Measure_reader { public: @@ -72,7 +77,7 @@ public: /*override*/void seek(long value, int whence) { if(lseek(f, value, whence)<0) - throw Exception("file.seek", + throw Exception("image.format", &file_name, "seek(value=%ld, whence=%d) failed: %s (%d), actual filename '%s'", value, whence, strerror(errno), errno, fname); @@ -104,11 +109,11 @@ public: 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; + default: throw Exception(0, 0, "whence #%d not supported", 0, whence); break; // never } if((ssize_t)new_offset<0 || new_offset>size) - throw Exception("file.seek", + 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); @@ -189,6 +194,8 @@ struct JPG_Exif_IFD_entry { #define JPG_IFD_TAG_EXIF_OFFSET 0x8769 +#define JPEG_EXIF_DATE_CHARS 20 + // inline ushort x_endian_to_ushort(uchar b0, uchar b1) { @@ -275,6 +282,9 @@ static Value *parse_IFD_entry_formatted_ return 0; } +// date.C +time_t cstr_to_time_t(char *cstr, const String *report_error_origin); + static Value *parse_IFD_entry_formatted_value(Pool& pool, bool is_big, ushort format, size_t component_size, uint components_count, @@ -282,6 +292,18 @@ static Value *parse_IFD_entry_formatted_ if(format==2) { // ascii string, exception: the only type with varying size const char *cstr=(const char *)value; size_t size=components_count; + // Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes + if(size==JPEG_EXIF_DATE_CHARS + && isdigit(cstr[0]) + && cstr[JPEG_EXIF_DATE_CHARS-1]==0) { + char cstr_writable[JPEG_EXIF_DATE_CHARS]; + strcpy(cstr_writable, cstr); + + time_t t=cstr_to_time_t(cstr_writable, 0/* do not throw exception, just return bad result */); + if(t>=0) + return new(pool) VDate(pool, t); + } + if(const char *premature_zero_pos=(const char *)memchr(cstr, 0, size)) size=premature_zero_pos-cstr; return new(pool) VString(*new(pool) String(pool, cstr, size, true/*tainted*/)); @@ -891,10 +913,10 @@ static void _polybar(Request& r, const S // font -#define Y(y)(y+index*height+1) +#define Y(y)(y+index*height) /// simple gdImage-based font storage & text output -class Font : public Pooled { +class Font: public Pooled { public: const static int letter_spacing; @@ -906,7 +928,7 @@ public: Font(Pool& pool, const String& aalphabet, - gdImage& aifont, int aheight, int amonospace, int aspacebarspace) : Pooled(pool), + gdImage& aifont, int aheight, int amonospace, int aspacebarspace): Pooled(pool), alphabet(aalphabet), height(aheight), monospace(amonospace), spacebarspace(aspacebarspace), ifont(aifont) { @@ -924,7 +946,7 @@ public: return spacebarspace; int tr=ifont.GetTransparent(); for(int x=ifont.SX()-1; x>=0; x--) { - for(int y=0; y=0) - ifont.Copy(image, x, y, 0, Y(0), index_width(index), height-1); + ifont.Copy(image, x, y, 0, Y(0), index_width(index), height); } /* ******************************** string ********************************** */ + int step_width(int index) { + return letter_spacing + (monospace ? monospace : index_width(index)); + } + + // counts trailing letter_spacing, consider this OK. useful for contiuations int string_width(const String& s){ const char *cstr=s.cstr(); int result=0; for(; *cstr; cstr++) - result+=index_width(index_of(*cstr)); + result+=step_width(index_of(*cstr)); return result; } @@ -951,7 +978,7 @@ public: if(cstr) for(; *cstr; cstr++) { int index=index_of(*cstr); index_display(image, x, y, index); - x+=letter_spacing + (monospace ? monospace : index_width(index)); + x+=step_width(index); } } @@ -976,6 +1003,12 @@ static void _font(Request& r, const Stri throw Exception("parser.runtime", &method_name, "alphabet must not be empty"); + + if(int remainder=image.SY() % alphabet.size()) + throw Exception("parser.runtime", + &method_name, + "font-file height(%d) not divisable by alphabet size(%d), remainder=%d", + image.SY(), alphabet.size(), remainder); static_cast(r.get_self())->font=new(pool) Font(pool, alphabet, @@ -1205,5 +1238,101 @@ Methoded *image_class; // creator Methoded *MImage_create(Pool& pool) { + // image JPEG Exif + #define EXIF_TAG(tag, name) \ + exif_tag_value2name.put(tag, #name); + // Tags used by IFD0 (main image) + EXIF_TAG(0x010e, ImageDescription); + EXIF_TAG(0x010f, Make); + EXIF_TAG(0x0110, Model); + EXIF_TAG(0x0112, Orientation); + EXIF_TAG(0x011a, XResolution); + EXIF_TAG(0x011b, YResolution); + EXIF_TAG(0x0128, ResolutionUnit); + EXIF_TAG(0x0131, Software); + EXIF_TAG(0x0132, DateTime); + EXIF_TAG(0x013e, WhitePoint); + EXIF_TAG(0x013f, PrimaryChromaticities); + EXIF_TAG(0x0211, YCbCrCoefficients); + EXIF_TAG(0x0213, YCbCrPositioning); + EXIF_TAG(0x0214, ReferenceBlackWhite); + EXIF_TAG(0x8298, Copyright); + EXIF_TAG(0x8769, ExifOffset); + // Tags used by Exif SubIFD + EXIF_TAG(0x829a, ExposureTime); + EXIF_TAG(0x829d, FNumber); + EXIF_TAG(0x8822, ExposureProgram); + EXIF_TAG(0x8827, ISOSpeedRatings); + EXIF_TAG(0x9000, ExifVersion); + EXIF_TAG(0x9003, DateTimeOriginal); + EXIF_TAG(0x9004, DateTimeDigitized); + EXIF_TAG(0x9101, ComponentsConfiguration); + EXIF_TAG(0x9102, CompressedBitsPerPixel); + EXIF_TAG(0x9201, ShutterSpeedValue); + EXIF_TAG(0x9202, ApertureValue); + EXIF_TAG(0x9203, BrightnessValue); + EXIF_TAG(0x9204, ExposureBiasValue); + EXIF_TAG(0x9205, MaxApertureValue); + EXIF_TAG(0x9206, SubjectDistance); + EXIF_TAG(0x9207, MeteringMode); + EXIF_TAG(0x9208, LightSource); + EXIF_TAG(0x9209, Flash); + EXIF_TAG(0x920a, FocalLength); + EXIF_TAG(0x927c, MakerNote); + EXIF_TAG(0x9286, UserComment); + EXIF_TAG(0x9290, SubsecTime); + EXIF_TAG(0x9291, SubsecTimeOriginal); + EXIF_TAG(0x9292, SubsecTimeDigitized); + EXIF_TAG(0xa000, FlashPixVersion); + EXIF_TAG(0xa001, ColorSpace); + EXIF_TAG(0xa002, ExifImageWidth); + EXIF_TAG(0xa003, ExifImageHeight); + EXIF_TAG(0xa004, RelatedSoundFile); + EXIF_TAG(0xa005, ExifInteroperabilityOffset); + EXIF_TAG(0xa20e, FocalPlaneXResolution); + EXIF_TAG(0xa20f, FocalPlaneYResolution); + EXIF_TAG(0xa210, FocalPlaneResolutionUnit); + EXIF_TAG(0xa215, ExposureIndex); + EXIF_TAG(0xa217, SensingMethod); + EXIF_TAG(0xa300, FileSource); + EXIF_TAG(0xa301, SceneType); + EXIF_TAG(0xa302, CFAPattern); + // Misc Tags + EXIF_TAG(0x00fe, NewSubfileType); + EXIF_TAG(0x00ff, SubfileType); + EXIF_TAG(0x012d, TransferFunction); + EXIF_TAG(0x013b, Artist); + EXIF_TAG(0x013d, Predictor); + EXIF_TAG(0x0142, TileWidth); + EXIF_TAG(0x0143, TileLength); + EXIF_TAG(0x0144, TileOffsets); + EXIF_TAG(0x0145, TileByteCounts); + EXIF_TAG(0x014a, SubIFDs); + EXIF_TAG(0x015b, JPEGTables); + EXIF_TAG(0x828d, CFARepeatPatternDim); + EXIF_TAG(0x828e, CFAPattern); + EXIF_TAG(0x828f, BatteryLevel); + EXIF_TAG(0x83bb, IPTC/NAA); + EXIF_TAG(0x8773, InterColorProfile); + EXIF_TAG(0x8824, SpectralSensitivity); + EXIF_TAG(0x8825, GPSInfo); + EXIF_TAG(0x8828, OECF); + EXIF_TAG(0x8829, Interlace); + EXIF_TAG(0x882a, TimeZoneOffset); + EXIF_TAG(0x882b, SelfTimerMode); + EXIF_TAG(0x920b, FlashEnergy); + EXIF_TAG(0x920c, SpatialFrequencyResponse); + EXIF_TAG(0x920d, Noise); + EXIF_TAG(0x9211, ImageNumber); + EXIF_TAG(0x9212, SecurityClassification); + EXIF_TAG(0x9213, ImageHistory); + EXIF_TAG(0x9214, SubjectLocation); + EXIF_TAG(0x9215, ExposureIndex); + EXIF_TAG(0x9216, TIFF/EPStandardID); + EXIF_TAG(0xa20b, FlashEnergy); + EXIF_TAG(0xa20c, SpatialFrequencyResponse); + EXIF_TAG(0xa214, SubjectLocation); + #undef EXIF_TAG + return image_class=new(pool) MImage(pool); }