我们平时常用的图片类型有jpg、bmp、png和gif等,一般情况下我们会根据图片的后缀名去判断图片的类型,其实这样做是不科学的,文件的后缀名是可以随意修改的,但文件的内容始终是不变的,不会因为后缀名的修改,就变成修改后的文件类型了。
有时我们的代码中是需要识别图片的类型的。比如对于.bmp位图文件,可能bmp格式的图片大小比较大,我们需要把这个图片通过网络发出去,为了减轻网络的发送压力,我们需要将图片转成jpg或png图片后再将图片发送出去。因为jpg或png格式的图片有着较高的压缩率,可以有效地较少图片文件的大小,这样就减轻了图片再网络传输的压力。
那如何通过代码去鉴别文件的真实图片类型呢?其实很简单,可以通过fread等函数读出文件内容最开始的若干个字节来判断,每种图片的都有对应的类型标识。
bmp图片文件的前2个字节存放bmp类型标识,识别代码如下:
BOOL IsBmpFile( LPCTSTR lpStrFilePath )
{
FILE* pFile = _tfopen( lpStrFilePath, _T("rb") );
if ( pFile == NULL )
{
return FALSE;
}
char szData[2] = {0};
int nReadNum = fread( szData, sizeof(char), 2, pFile );
if ( nReadNum < 2 )
{
fclose( pFile );
return FALSE;
}
fclose( pFile );
// bmp: 0x42, 0x4d
unsigned char szBmpFlag = { 0x42, 0x4d };
if ( !memcmp( szBmpFlag, szData, 2 ) )
{
return TRUE;
}
return FALSE;
}
jpg图片文件的前2个字节存放jpg类型标识,识别代码如下:
BOOL IsJpgFile( LPCTSTR lpStrFilePath )
{
FILE* pFile = _tfopen( lpStrFilePath, _T("rb") );
if ( pFile == NULL )
{
return FALSE;
}
char szData[2] = {0};
int nReadNum = fread( szData, sizeof(char), 2, pFile );
if ( nReadNum < 2 )
{
fclose( pFile );
return FALSE;
}
fclose( pFile );
// jpg: 0xFF, 0xD8
unsigned char szJpgFlag[] = { 0xFF, 0xD8 };
if ( !memcmp( szJpgFlag, szData, 2 ) )
{
return TRUE;
}
return FALSE;
}
png图片文件的前8个字节存放png类型标识,识别代码如下:
BOOL IsPngFile( LPCTSTR lpStrFilePath )
{
FILE* pFile = _tfopen( lpStrFilePath, _T("rb") );
if ( pFile == NULL )
{
return FALSE;
}
char szData[8] = {0};
int nReadNum = fread( szData, sizeof(char), 8, pFile );
if ( nReadNum < 8 )
{
fclose( pFile );
return FALSE;
}
fclose( pFile );
// png: 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
unsigned char szPngFlag[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
if ( !memcmp( szPngFlag, szData, 8 ) )
{
return TRUE;
}
return FALSE;
}
gif图片文件的前6个字节存放gif类型标识,识别代码如下:
BOOL IsGifFile( LPCTSTR lpStrFilePath )
{
FILE* pFile = _tfopen( lpStrFilePath, _T("rb") );
if ( pFile == NULL )
{
return FALSE;
}
char szData[6+1] = {0};
int nReadNum = fread( szData, sizeof(char), 6, pFile );
if ( nReadNum < 6 )
{
fclose( pFile );
return FALSE;
}
fclose(pFile);
// 使用字符串判断更直观
if ( strcmp( szData, "GIF89a" ) == 0 || strcmp( szData, "GIF87a" ) == 0 )
{
return TRUE;
}
return FALSE;
}
tiff图片文件的前4个字节存放tiff类型标识,识别代码如下:
BOOL32 IsTiffFile( LPCTSTR lpStrFilePath )
{
FILE* pFile = _tfopen( lpStrFilePath, _T("rb") );
if ( pFile == NULL )
{
return FALSE;
}
char szData[4] = {0};
int nReadNum = fread( szData, sizeof(char), 4, pFile );
if ( nReadNum < 4 )
{
fclose( pFile );
return FALSE;
}
fclose( pFile );
// jpg: 0x49, 0x49, 0x2A, 0x00
unsigned char szTiffFlag[] = { 0x49, 0x49, 0x2A, 0x00 };
if ( !memcmp( szTiffFlag, szData, 2 ) )
{
return TRUE;
}
return FALSE;
}
上述代码是通过C函数fopen、fread去读取文件中的内容的,也可以使用Windows API函数CreateFile、ReadFile等去读取的,比如:
BOOL IsJpgFile( LPCTSTR lpStrFilePath )
{
HANDLE hFile = ::CreateFile(lpStrFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
unsigned char szData[4] = { 0 };
DWORD dwReadNum;
if (!::ReadFile((HANDLE)hFile, szData, 4, &dwReadNum, NULL))
{
CloseHandle(hFile);
return FALSE;
}
if ( dwReadNum< 4 )
{
CloseHandle(hFile);
return FALSE;
}
CloseHandle(hFile);
unsigned char szJpgFlag[] = { 0xFF, 0xD8 };
// 0xFF,0xD8
if ( !memcmp( szJpgFlag, szData, 2 ) )
{
return TRUE;
}
return FALSE;
}