读取Exif信息需要对JPEG和Exif格式有简单的了解
JEGP格式请查看云风的文章http://blog.csdn.net/glock18/archive/2004/09/05/95268.aspx
Exif格式请查看猛禽的文章http://dev.csdn.net/article/27/27594.shtm
下面给出了一个读取Exif信息的类:
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');
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 : PChar; //数据在内存中的地址
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 : PChar;//存放所有Exif value的内存
FBufused : U32;//
FInfCount : S32;
procedure GetEntryData( var ie: YIFDEntry; TiffHdrPos: U32 );
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function ReadExif( JpgFileName: string ): string;
function ExifInf( i: S32 ):string;
property ExifInfoCount: S32 read FInfCount;
end;
implementation
uses Winsock;
const
EXIF_ATTR_DEF_FILE = 'ExifInf.Ini';
CLRF = #13#10;
//计算一个Entry数据的真实大小
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[i].Tag then
begin
ie.sDescript := iti[i].Mean;
b := True; break;
end;
end;
if not b then
ie.sDescript := format( 'Unknow Tag: %.4x', [ie.u16tag] );
end;
constructor YExifReader.Create(AOwner: TComponent);
var
s : string;
i,j : S32;
lst : TStringList;
begin
inherited Create(AOwner);
FStream := nil;
FExifBuf := AllocMem( 1024 * 100 );//先分配100KB内存备用...足够存放所有信息了
s := ExtractFilePath( ParamStr(0) );
if s[Length(s)] <> '/' then
s := s + '/';
lst := TStringList.Create;
lst.LoadFromFile( s + EXIF_ATTR_DEF_FILE );
for i:=0 to lst.Count-1 do
begin
s := lst.Strings[i];
if s[1] <> ';' then
begin
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;
end;
destructor YExifReader.Destroy;
begin
if FStream <> nil then
FStream.Free;
FreeMem( FExifBuf );
inherited Destroy;
end;
procedure YExifReader.GetEntryData( var ie: YIFDEntry; TiffHdrPos: U32 );
begin
ie.u32maddr := FExifBuf + FBufUsed;
if ie.u32count <= 4 then
begin
Move( ie.u32value, ie.u32maddr^, ie.u32rsize );
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;
//JEPG file header
FStream.Read( w, sizeof(w) );
if JPEG_BEGIN <> ntohs(w) then
begin
result := 'Not A Jpeg Image.' + CLRF;
FreeAndNil( FStream );
Exit;
end;
//search segment 'app1' ---Exif attribute information
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 + 'Segment APP1 length: ' + format('%.4x',[w]) + CLRF;
//search Exif sign ---'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) ); //two zero
//TIFF Header
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 + 'TIFF Header byte order is Motolora.' +CLRF;
FreeAndNil( FStream );
Exit;
end;
FStream.Read( w, sizeof(w) );//TIFF文件格式的标志,总是为0x002A
FStream.Read( dw, sizeof(dw) );//第一个IFD的起始位置,其偏移量的计算起点是TIFF Header的起点
FStream.Seek( dw-8, soFromCurrent );//8==size of Image File Header
FStream.Read( w, sizeof(w) );//IFD.0 Entry Count
result := result + 'TIFF IFD0 Entry count: ' + format('%.4x',[w]) +CLRF;
IFD_0_EntryCount := w;
SetLength( FEntrys, IFD_0_EntryCount );
//read ifd entry
for i:=0 to IFD_0_EntryCount-1 do
begin
FStream.Read( FEntrys[i].u16tag, sizeof(u16) );
FStream.Read( FEntrys[i].u16type, sizeof(u16) );
FStream.Read( FEntrys[i].u32count, sizeof(u32) );
FStream.Read( FEntrys[i].u32value, sizeof(u32) );
GetEntrySize( FEntrys[i] );
end;
//read ifd value
for i:=0 to IFD_0_EntryCount-1 do
begin
GetEntryDescript( FEntrys[i], FTagInfo );
GetEntryData( FEntrys[i], TiffHeaderPos );
end;
//Offset of Exif IFD = The last TIFF IFDEntry value + TIFF header offset
FStream.Position := TiffHeaderPos + FEntrys[IFD_0_EntryCount-1].u32value;
FStream.Read( w, sizeof(w) );//IFD.1 Entry Count
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[i].u16tag, sizeof(u16) );
FStream.Read( FEntrys[i].u16type, sizeof(u16) );
FStream.Read( FEntrys[i].u32count, sizeof(u32) );
FStream.Read( FEntrys[i].u32value, sizeof(u32) );
GetEntrySize( FEntrys[i] );
end;
for i:=IFD_0_EntryCount to Length(FEntrys)-1 do
begin
GetEntryDescript( FEntrys[i], FTagInfo );
GetEntryData( FEntrys[i], TiffHeaderPos );
end;
FInfCount := Length(FEntrys);
FreeAndNil( FStream );
end;
function YExifReader.ExifInf( i: S32 ):string;
var
s : string;
p : PChar;
begin
if i >= Length(FEntrys) then
begin
result := '';
Exit;
end;
result := FEntrys[i].sDescript + ' ';
s := '';
if (FEntrys[i].u16type = 2) or //Ascii or ExifVersion or FlashPixVersion
(FEntrys[i].u16tag = $9000) or (FEntrys[i].u16tag = $A000) then
begin
SetLength( s, FEntrys[i].u32rsize );
Move( FEntrys[i].u32maddr^, s[1], FEntrys[i].u32rsize );
end else
begin
if (FEntrys[i].u16tag = $927C) or (FEntrys[i].u16tag = $9286) then
begin //MakerNote or UserComment
s := 'Not Read.';
result := result + s;
Exit;
end;
p := AllocMem( FEntrys[i].u32rsize * 2 + 1 );
BinToHex( FEntrys[i].u32maddr, p, FEntrys[i].u32rsize );
s := p;
FreeMem( p );
end;
result := result + s;
end;
end.
;*********************************************************************
;
; TIFF Rev. 6.0 Attribute Information
;
;*********************************************************************
;
;
; A. Tags relating to image data structure
;
256 100 Image width -
257 101 Image height -
258 102 Number of bits per component -
259 103 Compression -
262 106 Pixel composition -
274 112 Orientation of image -
277 115 Number of components -
284 11C Image data arrangement -
530 212 Subsampling ratio of Y to C -
531 213 Y and C positioning -
282 11A Image resolution in width direct -
283 11B Image resolution in height direct -
296 128 Unit of X and Y resolution -
;
; B. Tags relating to recording offset
;
273 111 Image data location -
278 116 Number of rows per strip -
279 117 Bytes per compressed strip -
513 201 Offset to JPEG SOI -
514 202 Bytes of JPEG data -
;
; C. Tags relating to image data characteristics
;
301 12D Transfer function -
318 13E White point chromaticity -
319 13F Chromaticities of primaries -
529 211 Color space transformation matrix -
532 214 Pair of black and white reference -
;
; D. Other tags
;
306 132 File change date and time -
270 10E Image Description -
271 10F Image input equipment maker -
272 110 Image input equipment model -
305 131 Software used -
315 13B Person who created the image -
3432 8298 Copyright holder -
;
;
;*********************************************************************
;
; Exif IFD Attribute Information v2.1
;
;*********************************************************************
;
; A. Tags Relating to Version
;
36864 9000 Exif version -
40960 A000 Supported FlashPix version -
;
; B. Tag Relating to Image Data Characteristics
;
40961 A001 Color space information -
;
; C. Tags Relating to Image Configuration
;
37121 9101 Meaning of each component -
37122 9102 Image compression mode -
40962 A002 Valid image width -
40963 A003 Valid image height -
;
; D. Tags Relating to User Information
;
37500 927C Manufacturer notes -
37510 9286 User comments -
;
; E. Tag Relating to Related File Information
;
40964 A004 Related audio file -
;
; F. Tags Relating to Date and Time
;
36867 9003 Date and time of original data -
36868 9004 Date and time of digital data -
37520 9290 DateTime subseconds -
37521 9291 DateTimeOriginal subseconds -
37522 9292 DateTimeDigitized subseconds -
;
; G. Tags Relating to Picture- Taking Conditions
;
33434 829A Exposure time -
33437 829D F number -
34850 8822 Exposure program -
34852 8824 Spectral sensitivity -
34855 8827 ISO speed rating -
34856 8828 Optoelectric conversion factor -
37377 9201 Shutter speed -
37378 9202 Aperture -
37379 9203 Brightness -
37380 9204 Exposure bias -
37381 9205 Maximum lens aperture -
37382 9206 Subject distance -
37383 9207 Metering mode -
37384 9208 Light source -
37385 9209 Flash -
37386 920A Lens focal length -
41483 A20B Flash energy -
41484 A20C Spatial frequency response -
41486 A20E Focal plane X resolution -
41487 A20F Focal plane Y resolution -
41488 A210 Focal plane resolution unit -
41492 A214 Subject location -
41493 A215 Exposure index ExposureIndex -
41495 A217 Sensing method -
41728 A300 File source -
41729 A301 Scene type -
41730 A302 CFA pattern -
;
; H. Tags Relating to Date and Time
;
40965 A005 Pointer of Interoperability IFD -
;
34665 8769 Exif IFD Pointer -
34853 8825 GPS Info IFD Pointer -
40965 A005 Interoperability IFD Pointer -
; END