unit exif;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Dialogs,Winsock,StdCtrls,Jpeg,ExtCtrls,ExtDlgs;
type
U32= DWORD;
U16= WORD;
S32= Integer;
U8= Byte;
PIFDEntry= ^YIFDEntry;
YIFDEntry= record
u16tag :U16;
u16type :U16;
u32count :U32;
u32value :U32;
u32rsize :U32; //数据真实大小---bytes
u32maddr
Char; //数据在内存中的地址
sDescript :string;
end;
YIFDTagInfo= record
Tag :U16;
Mean :string;
end;
YExifReader= class(TComponent)
private
FStream :TFileStream;
FTagInfo :Array of YIFDTagInfo;
FEntrys :Array of YIFDEntry;
FExifBuf
Char; //存放所有Exifvalue的内存
FBufused :U32; //
FInfCount :S32;
public
procedure GetEntryData(var ie :YIFDEntry; TiffHdrPos :U32);
constructor Create(AOwner :TComponent); override;
destructor Destroy; override;
function ReadExif(JpgFileName :string):string;
function ExifInf(i :S32) :string;
property ExifInfoCount :S32 read FInfCount;
end;
const
JPEG_BEGIN = $FFD8;
JPEG_APP1 = $FFE1;
JPEG_END = $FFD9;
JPEG_EXIF = (Byte('E') shl 24) + (Byte('x') shl 16) + (Byte('i') shl 8) + Byte('f');
BYTE_ODR_I = (Byte('I') shl 8)+Byte('I');
BYTE_ODR_M = (Byte('M') shl 8)+Byte('M');
implementation
const
CLRF= #13#10;
procedure GetEntrySize(var ie :YIFDEntry);
begin
case ie.u16type of
1,2,7 : ie.u32rsize := 1;
3 : ie.u32rsize := 2;
4,9 : ie.u32rsize := 4;
5,10 : ie.u32rsize := 8;
else
ie.u32rsize := 1;
end;
ie.u32rsize := ie.u32rsize * ie.u32count;
end;
//获得一个Entry的含义
procedure GetEntryDescript(var ie :YIFDEntry; const iti :Array of YIFDTagInfo);
var
i :U16;
b :BOOL;
begin
b := False;
for i := 0 to Length(iti)-1 do begin
if ie.u16tag = iti
.Tag then begin
ie.sDescript := iti.Mean;
b := True;
break;
end;
end;
if not b then
ie.sDescript := format('UnknowTag :%.4x',[ie.u16tag]);
end;
constructor YExifReader.Create(AOwner : TComponent);
var
s :string;
i,j :S32;
lst :TStringList;
begin
//inheritedCreate(AOwner);
FStream := nil;
FExifBuf := AllocMem(1024*100); //先分配100KB内存备用...足够存放所有信息了
lst := TStringList.Create;
lst.add('256 100 Image width -');
lst.add('257 101 Image height -');
lst.add('258 102 Number of bits per component -');
lst.add('259 103 Compression -');
lst.add('262 106 Pixel composition -');
lst.add('274 112 Orientation of image -');
lst.add('277 115 Number of components -');
lst.add('284 11C Image data arrangement -');
lst.add('530 212 Subsampling ratio of Y to C -');
lst.add('531 213 Y and C positioning -');
lst.add('282 11A Image resolution in width direct -');
lst.add('283 11B Image resolution in height direct -');
lst.add('296 128 Unit of X and Y resolution -');
lst.add('273 111 Image data location -');
lst.add('278 116 Number of row sperstrip -');
lst.add('279 117 Bytes per compressed strip -');
lst.add('513 201 Offset to JPEG SOI -');
lst.add('514 202 Bytes of JPEG data -');
lst.add('301 12D Transfer function -');
lst.add('318 13E White point chromaticity -');
lst.add('319 13F Chromaticities of primaries -');
lst.add('529 211 Color space transformation matrix -');
lst.add('532 214 Pair of black and white reference -');
lst.add('306 132 File change date and time -');
lst.add('270 10E Image Description -');
lst.add('271 10F Image input equipment maker -');
lst.add('272 110 image input equipment mode -');
lst.add('305 131 Software used -');
lst.add('315 13B Person who created the image -');
lst.add('3432 8298 Copyright holder -');
lst.add('36864 9000 Exif version -');
lst.add('40960 A000 Supported Flash Pix version -');
lst.add('40961 A001 Color space information -');
lst.add('37121 9101 Meaning of each component -');
lst.add('37122 9102 Image compression mode -');
lst.add('40962 A002 Valid image width -');
lst.add('40963 A003 Valid image height -');
lst.add('37500 927C Manufacturer notes -');
lst.add('37510 9286 User comments -');
lst.add('40964 A004 Related audio file -');
lst.add('36867 9003 Date and time of original data -');
lst.add('36868 9004 Date and time of digital data -');
lst.add('37520 9290 DateTime subseconds -');
lst.add('37521 9291 DateTime Original subseconds -');
lst.add('37522 9292 DateTimeDigitized subseconds -');
lst.add('33434 829A Exposure time -');
lst.add('33437 829D F number -');
lst.add('34850 8822 Exposure program -');
lst.add('34852 8824 Spectral sensitivity -');
lst.add('34855 8827 ISO speed rating -');
lst.add('34856 8828 Optoelectric conversion factor -');
lst.add('37377 9201 Shutter speed -');
lst.add('37378 9202 Aperture -');
lst.add('37379 9203 Brightness -');
lst.add('37380 9204 Exposure bias -');
lst.add('37381 9205 Maximum lens aperture -');
lst.add('37382 9206 Subject distance -');
lst.add('37383 9207 Metering mode -');
lst.add('37384 9208 Light source -');
lst.add('37385 9209 Flash -');
lst.add('37386 920A Lens focal length -');
lst.add('41483 A20B Flash energy -');
lst.add('41484 A20C Spatial frequency response -');
lst.add('41486 A20E Focal plane X resolution -');
lst.add('41487 A20F Focal plane Y resolution -');
lst.add('41488 A210 Focal plane resolution unit -');
lst.add('41492 A214 Subject location -');
lst.add('41493 A215 Exposure index ExposureIndex -');
lst.add('41495 A217 Sensing method -');
lst.add('41728 A300 File source -');
lst.add('41729 A301 Scene type -');
lst.add('41730 A302 CFA pattern -');
lst.add('40965 A005 Pointer of Interoperability IFD -');
lst.add('34665 8769 Exif IFD Pointer -');
lst.add('34853 8825 GPS Info IFD Pointer -');
lst.add('40965 A005 Interoperability IFD Pointer -');
for i := 0 to lst.Count-1 do begin
s := lst.Strings;
SetLength(FTagInfo, Length(FTagInfo) + 1);
j := Pos(' ',s);
FTagInfo[Length(FTagInfo)-1].Tag := StrToInt(Copy(s,1,j-1));
FTagInfo[Length(FTagInfo)-1].Mean := Copy(s,j+1,Length(s)-j);
end;
end;
function YExifReader.ExifInf(i :S32) : string;
var
s :string;
p Char;
begin
if i >= Length(FEntrys) then begin
result := '';
Exit;
end;
result := FEntrys.sDescript + ' ';
s := '';
if (FEntrys.u16type= 2) or //AsciiorExifVersionorFlashPixVersion
(FEntrys.u16tag= $9000) or (FEntrys.u16tag= $A000) then begin
SetLength(s, FEntrys.u32rsize);
Move(FEntrys.u32maddr^,s[1],FEntrys.u32rsize);
end else begin
if (FEntrys.u16tag= $927C) or (FEntrys.u16tag= $9286) then begin //MakerNoteorUserComment
s := 'Not Read.';
result := result + s;
Exit;
end;
p := AllocMem(FEntrys.u32rsize * 2 + 1);
BinToHex( FEntrys.u32maddr, p, FEntrys.u32rsize);
s := p;
FreeMem(p);
end;
result := result+s;
end;
procedure YExifReader.GetEntryData(var ie : YIFDEntry; TiffHdrPos : U32);
begin
ie.u32maddr := FExifBuf + FBufUsed;
if ie.u32count <= 4 then begin
try
Move(ie.u32value,ie.u32maddr^,ie.u32rsize);
except
end;
Inc(FBufUsed,ie.u32rsize);
Exit;
end;
FStream.Position := TiffHdrPos+ie.u32value;
FStream.Read(ie.u32maddr^,ie.u32rsize);
Inc(FBufUsed,ie.u32rsize);
end;
function YExifReader.ReadExif(JpgFileName : string) :string;
var
i,w,TiffHeaderPos,IFD_0_EntryCount,IFD_1_EntryCount :U16;
dw :U32;
begin
FStream := TFileStream.Create(JpgFileName,fmOpenRead);
FBufUsed := 0;
FInfCount := 0;
//JEPGfileheader
FStream.Read(w,sizeof(w));
if JPEG_BEGIN <> ntohs(w) then begin
result := 'NotAJpegImage.' + CLRF;
FreeAndNil(FStream);
Exit;
end;
//searchsegment'app1'---Exifattributeinformation
FStream.Read(w,sizeof(w));
w := ntohs(w);
while JPEG_APP1 <> w do begin
FStream.Read(w,sizeof(w));
FStream.Seek(ntohs(w) - sizeof(w),soFromCurrent);
FStream.Read(w,sizeof(w));
w := ntohs(w);
if JPEG_END= w then begin
result := result + 'No Exif info.' + CLRF;
FreeAndNil(FStream);
Exit;
end;
end;
result := result + 'Segment APP1 found.' + CLRF;
FStream.Read(w,sizeof(w));
w := ntohs(w);
result := result + 'SegmentAPP1length :' + format('%.4x',[w]) + CLRF;
//searchExifsign---'Exif'
FStream.Read(dw,sizeof(dw));
dw := ntohl(dw);
if JPEG_EXIF <> dw then begin
result := result + 'No Exif in this segment.'+CLRF;
FreeAndNil(FStream);
Exit;
end;
result := result + 'Exif sign found...' + CLRF;
FStream.Read(w,sizeof(w)); //twozero
//TIFFHeader
TiffHeaderPos := FStream.Position;
FStream.Read(w,sizeof(w));
if BYTE_ODR_I = w then begin
result := result + 'TIFF Header byte order is Intel.' + CLRF;
end else begin
//如果是Motolora格式的就不处理了~~~~~~`result := result+'TIFFHeaderbyteorderisMotolora.'+CLRF;
FreeAndNil(FStream);
Exit;
end;
FStream.Read(w, sizeof(w)); //TIFF文件格式的标志,总是为0x002A
FStream.Read(dw, sizeof(dw)); //第一个IFD的起始位置,其偏移量的计算起点是TIFFHeader的起点
FStream.Seek(dw - 8, soFromCurrent); // 8= = sizeofImageFileHeader
FStream.Read(w,sizeof(w)); //IFD.0EntryCount
result := result + 'TIFFIFD0Entrycount : ' + format('%.4x',[w]) + CLRF;
IFD_0_EntryCount := w;
SetLength(FEntrys, IFD_0_EntryCount); //read ifdentry
for i := 0 to IFD_0_EntryCount - 1 do begin
FStream.Read(FEntrys.u16tag, sizeof(u16));
FStream.Read(FEntrys.u16type, sizeof(u16));
FStream.Read(FEntrys.u32count, sizeof(u32));
FStream.Read(FEntrys.u32value, sizeof(u32));
GetEntrySize(FEntrys);
end;
//read ifd value
for i := 0 to IFD_0_EntryCount - 1 do begin
GetEntryDescript(FEntrys,FTagInfo);
GetEntryData(FEntrys, TiffHeaderPos);
end;
//Offset of ExifIFD = The last TIFFI FDEntry value + TIFFheader offset
FStream.Position := TiffHeaderPos + FEntrys[IFD_0_EntryCount-1].u32value;
FStream.Read(w,sizeof(w)); //IFD.1EntryCount
result := result + 'TIFF IFD1 Entry count : ' + format('%.4x',[w]) + CLRF;
IFD_1_EntryCount := w;
SetLength(FEntrys, IFD_0_EntryCount + IFD_1_EntryCount);
for i := IFD_0_EntryCount to Length(FEntrys) - 1 do begin
FStream.Read(FEntrys.u16tag,sizeof(u16));
FStream.Read(FEntrys.u16type,sizeof(u16));
FStream.Read(FEntrys.u32count,sizeof(u32));
FStream.Read(FEntrys.u32value,sizeof(u32));
GetEntrySize(FEntrys);
end;
sleep(0);
{ for i := IFD_0_EntryCount to Length(FEntrys) - 1 do begin
GetEntryDescript(FEntrys, FTagInfo);
GetEntryData(FEntrys, TiffHeaderPos);
end;}
FInfCount := Length(FEntrys);
FreeAndNil(FStream);
end;
destructor YExifReader.Destroy;
begin
if FStream <> nil then
FStream.Free;
FreeMem(FExifBuf);
inherited Destroy;
end;
end.