读取Exif信息需要对JPEG和Exif格式有简单的了解

读取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

posted on 2013-05-10 15:57  大胡子青松  阅读(747)  评论(0编辑  收藏  举报

导航