如何判断图片文件的格式?

lihuifeng1 2010-10-27 10:26:01
我在使用CxImage的时候发现,如果用Load()函数加载图片的时候,参数指定的图片类型和文件实际类型不一样(例如文件后缀是.bmp,但它实际不是图片文件),会导致异常。
现在,我想在使用Load()函数之前,通过读文件头来判断文件的真正格式,而不是仅仅使用后缀名判断(目前是这么做的,有时导致我的嵌入式终端死机),例如,最简单的bmp文件,开头2个字节肯定是"BM",但是我看了几个jpg格式的文件,文件头并不是固定的,我想请教各位,jpg文件的文件头有没有什么规律?如何判断...
顺便png,gif,tga,tif,tiff,pcx,ico,wbmp,wmf,jbg这些文件头的规律我也想知道,求教各位,有知道的麻烦告知一下,急!!!
...全文
518 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
eastrise_liu 2010-10-29
  • 打赏
  • 举报
回复
楼主,谢谢你的热心回答..
我本来是想用TRY CATCH 做的,抓异常,给用户弹个消息的,可是发现积累没向上抛,直接倒掉了,没办法,我就判断一下LOAD的返回值,然后弹个消息,呵呵,有点傻.
lihuifeng1 2010-10-29
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 eastrise_liu 的回复:]
楼主,问题解决没,现在我和你遇到同样的问题了..解决的话说说也帮帮我..呵
[/Quote]

我把CxImage的库改了,原来的问题是因为图片解不开,在Load函数里面会先用后缀指定的格式解一次,解码不成功的话,会把图片格式设置成0,即未知格式,然后依次按各种支持的格式都去尝试解码,这样就会对文件解码很多次,而且每一次都会有异常抛出,异常处理会消耗CPU很多时间,所以如果加上用户的快速操作就会很容易导致死机,现在,我把那些抛出的地方都改成 return 了,具体就是先保存了错误信息,然后返回false,错误信息可以通过 CxImage::GetLastError()获得。
这样暂时解决了死机的问题,但是修改了库会不会导致其他问题目前还未知,我这个做法其实不太好,如果有高手想到更好的办法麻烦不啬赐教啊...

我本来是想在解图片的时候先打开文件检查文件头,以此来判断是不是正确的图片文件,但是这样会导致程序效率问题,损失一部分性能,所以没按以前的思路做了。

问题已解决,结贴了。如果有高手赐教麻烦发Email至 :lihuifeng110@126.com
eastrise_liu 2010-10-28
  • 打赏
  • 举报
回复
楼主,问题解决没,现在我和你遇到同样的问题了..解决的话说说也帮帮我..呵
fengbingchun 2010-10-28
  • 打赏
  • 举报
回复
看看这个帖子吧
寻找各种图像文件格式资料:GIF、JPG、PNG、PCX、PSD、TGA、TIF

http://topic.csdn.net/t/20021106/07/1151880.html
傻X 2010-10-28
  • 打赏
  • 举报
回复
用这个
IMsmMerge2::ExtractFilesEx
joey_zoy 2010-10-27
  • 打赏
  • 举报
回复
如果可以用开源的库,可以使用MediaInfo库来判断
zhxingway 2010-10-27
  • 打赏
  • 举报
回复

顶一下.
lihuifeng1 2010-10-27
  • 打赏
  • 举报
回复
感谢这位兄弟...
laviewpbt 2010-10-27
  • 打赏
  • 举报
回复
只有VB代码,仅供参考,这些我是总结的一些函数。
laviewpbt 2010-10-27
  • 打赏
  • 举报
回复



Private Type WbmpHeader
Type As Byte '指明了WBMP的型态。因为目前只有型态0(黑白,非压缩)的 WBMP 格式被定义,第一个8个位组应该为零
Null As Byte '是固定标头部分,也为0
Width As Byte '动态的字节数
Height As Byte
End Type


Public Function IsWbm(FileName As String) As Boolean
Dim FileNumber As Long, BytesRead As Long
Dim Header(5) As Byte, Index As Long
Dim High As Long, Low As Long
Dim Width As Long, Height As Long
Dim FileSize As Long
FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If FileNumber <> 0 Then
FileSize = GetFileSize(FileNumber, ByVal 0&)
ReadFile FileNumber, Header(0), 6, BytesRead, ByVal 0&
If Header(0) = 0 And Header(1) = 0 Then
Index = 2
If Header(Index) > 127 Then '大于127,则用两个字节表示,并且宽度是用两个字节的后七位拼接而成。
High = (Header(Index) * 128) And &H3F80 '取高字节的前七位
Low = Header(Index + 1) And &H7F '取底字节的前七位
Width = High Or Low '拼合
Index = Index + 2
Else
Width = Header(Index)
Index = Index + 1
End If
If Header(Index) > 127 Then
High = (Header(Index) * 128) And &H3F80
Low = Header(Index + 1) And &H7F
Height = High Or Low
Index = Index + 2
Else
Height = Header(Index)
Index = Index + 1
End If
If Width > 0 And Height > 0 Then
If FileSize - Index = ((Width + 7) \ 8) * Height Then
IsWbm = True
End If
End If
End If
End If

CloseHandle FileNumber
End Function





'TGA格式从文件开始到结束的结构为:
' TGA文件头 (文件头包含了基本的图像参数)
' Image ID (这一部分的内容不是必须的,其大小由文件头的IDLength指定,不能大于255字节,可以用来保存作者信息等)
' Colormap (调色板的信息,TGA格式对于真彩色也可以有调色板的)
' Image Data (TGA的数据可能是RLE压缩后的,也可能是未压缩的,这个由头文件中的ImageType指定)
' Developer Area(这是TGA2.0格式独有的,一般无需关注)
' Extension Area(TGA2.0版本独有,可用于保存软件作者,开发时间等信息)
' Footer (TGA2.0版本独有,保留了2.0版本的签名和上面两个Area部分的起始地址)


' 注意TGA格式的压缩不是针对位,也不是针对字节,而是针对一个像素的,比如RGB色,就是把RGB看做一个整体来编码的。

Private Type TgaHeader
IDLength As Byte '在头部之后的Image ID段的长度,最大为255字节,一般为空
ColorMapType As Byte '1表示有调色板,0表示没有,其他值保留
ImageType As Byte '图像类型 0=为空, 1= 不压缩+调色板 9=RLE压缩+调色板, 2=未压缩的真彩色,10=压缩的真彩色,3=未压缩的灰度,11=压缩后的灰度, 32&33 哈夫曼编码压缩
CMapStart As Integer '调色板开始位置
CMapLength As Integer '调色板的数量
CMapDepth As Byte '每个调色板项所占用的字节数,可为 8,15,16,24,32
XOffset As Integer '一般为0
YOffset As Integer '一般为0
Width As Integer '图像像素宽度
Height As Integer '图像像素高度
PixelDepth As Byte '图像一个像素占用字节数,本类可解析 8,15,16,24,32
ImageDescriptor As Byte '图像描述符 (图像的方向,ALPHA的应用等)
End Type


Private Type TgaFooter
ExtensionOffset As Long '扩展快的位置
DeveloperOffset As Long
Signature(18) As Byte '2.0版本的标识符
End Type


Private Pal32LUT(0 To 31) As Byte ' 5位,32个调色板实体的查找表, 32 entry, palette lookup table

Public Function IsTGA(FileName As String) As Boolean
Dim FileNumber As Long, BytesRead As Long
Dim FileSize As Long
Dim Header As TgaHeader, Foot As TgaFooter
Dim Bpp As Long, ExpectedSize As Long

FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If FileNumber <> 0 Then
FileSize = GetFileSize(FileNumber, ByVal 0&)
If FileSize > 26 Then
SetFilePointer FileNumber, FileSize - 26, ByVal 0&, FILE_BEGIN 'TGA2.0里有这个标签
ReadFile FileNumber, Foot, Len(Foot), BytesRead, ByVal 0&
If InStr(1, StrConv(Foot.Signature, vbUnicode), "TRUEVISION-XFILE.", vbTextCompare) > 0 Then
IsTGA = True
CloseHandle FileNumber
Exit Function
End If
End If

If FileSize > 18 Then
SetFilePointer FileNumber, 0, ByVal 0&, FILE_BEGIN
ReadFile FileNumber, Header.IDLength, 1, BytesRead, ByVal 0&
ReadFile FileNumber, Header.ColorMapType, 1, BytesRead, ByVal 0&
ReadFile FileNumber, Header.ImageType, 1, BytesRead, ByVal 0&
ReadFile FileNumber, Header.CMapStart, 2, BytesRead, ByVal 0&
ReadFile FileNumber, Header.CMapLength, 2, BytesRead, ByVal 0& '不能直接通过结构体来读取数据,主要是存在字节对齐问题
ReadFile FileNumber, Header.CMapDepth, 1, BytesRead, ByVal 0&
ReadFile FileNumber, Header.XOffset, 10, BytesRead, ByVal 0&
Else
CloseHandle FileNumber
Exit Function
End If
End If
CloseHandle FileNumber

Select Case Header.ImageType '第一步测试,看图像类型是否合理
Case 1, 2, 3, 9, 10, 11 'Truevision保留在0到 127之间的 ImageType为自己所用,128 到 255 可由开发者所用
Case Else '0=空白图像, 32或33是合法的,但找不到相关文档
Exit Function
End Select

If Header.Width < 1 Or Header.Height < 1 Then Exit Function ' 第二步测试

Select Case Header.PixelDepth '第三步测试,看图像的像素深度是否合理
Case 8
Bpp = 1
Case 15, 16 '如果没有调色板也可以支持
If Header.ImageType = 1 Or Header.ImageType = 9 Then Exit Function
Bpp = 2
Case 24, 32 '如果没有调色板也可以支持
If Header.ImageType = 1 Or Header.ImageType = 9 Then Exit Function
Bpp = Header.PixelDepth \ 8
Case Else
Exit Function ' 文档里其他的也支持,这里不支持
End Select

If Header.ImageType = 1 Or Header.ImageType = 9 Then '第四步测试,看调色板的设置统一不
If Header.ColorMapType <> 1 Then Exit Function ' 1代表有调色板,0表示没有,'Truevision保留在0到 127之间的 ImageType为自己所用,128 到 255 可由开发者所用
End If

If Header.ColorMapType = 1 Then '第五步,继续验证调色板,TGA在真彩色时也是可以有调色板的
If Header.CMapLength < 1 Then Exit Function '调色板的数量不能少于1
If Header.CMapStart < 0 Then Exit Function '调色板的偏移是否正常
ExpectedSize = Header.CMapStart + Header.CMapDepth

Select Case Header.CMapDepth ' ignore unsupported palette bit depths
Case 8, 24, 32
ExpectedSize = ExpectedSize * (Header.CMapDepth \ 8)
Case 15, 16 '
ExpectedSize = ExpectedSize * 2
Case Else:
Exit Function
End Select
End If

If Header.ImageType < 8 Then ' 第六步,最小文件测试,未压缩
ExpectedSize = ExpectedSize + Bpp * Header.Width * Header.Height
End If
If ExpectedSize < FileSize Then IsTGA = True
End Function
laviewpbt 2010-10-27
  • 打赏
  • 举报
回复
Public Function IsBmp(ByVal FileName As String) As Boolean
Dim FileNumber As Long, BytesRead As Long
Dim BmpInfoHeaderSize As Long
Dim BmpFileHeader As BITMAPFILEHEADER

FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
ReadFile FileNumber, BmpFileHeader, Len(BmpFileHeader), BytesRead, ByVal 0&
If BmpFileHeader.Type = &H4D42 Then 'BmpFileHeader.OffBits和BmpFileHeader.Size都有可能是0
ReadFile FileNumber, BmpInfoHeaderSize, 4, BytesRead, ByVal 0&
If BmpInfoHeaderSize = 12 Or BmpInfoHeaderSize = 40 Or BmpInfoHeaderSize = 56 Then
IsBmp = True
End If
End If
CloseHandle FileNumber

End Function





Private Type GifHeader
Key As String * 6
End Type


Public Function IsGif(ByVal FileName As String) As Boolean
Dim FileNumber As Long
Dim BytesRead As Long
Dim Header As GifHeader
FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If FileNumber <> 0 Then
ReadFile FileNumber, Header, Len(Header), BytesRead, ByVal 0&
If (Header.Key = "GIF87a" Or Header.Key = "GIF89a") Then
IsGif = True
End If
End If
CloseHandle FileNumber
End Function





Private Type ICONDIRENTRY
Width As Byte ' 图标图片的显示宽度,以像素为单位,最大值为255
Height As Byte ' 图标图片的显示高度, 以像素为单位,最大值为255 (times 2)
ColorCount As Byte ' 图标图片的颜色数 (0 if >=8bpp)
Reserved As Byte ' 保留域总是 0
Planes As Integer ' 图标图片的位面数,1
BitCount As Integer ' 标图片的颜色深度
BytesInRes As Long ' 图标图片占用的数据量(字节为单位)
ImageOffset As Long ' 图标图片的开始位置
End Type

Private Type ICONDIR
Reserved As Integer ' 保留域,目前始终为0
Type As Integer ' 定义为资源类型,图标值为 1、光标是2
Count As Integer ' 表示的是这个文件里包含了几个图标
End Type

Private Const M_Image_ICON As Long = 1
Private Const CBM_INIT As Long = &H4


Public Function IsIcon(ByVal FileName As String) As Boolean
Dim Id As ICONDIR, IDE() As ICONDIRENTRY
Dim FileNumber As Long, Entry As Long
Dim BytesRead As Long, Length As Long
IsIcon = True
FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If FileNumber <> 0 Then
Length = GetFileSize(FileNumber, ByVal 0&)
ReadFile FileNumber, Id, Len(Id), BytesRead, ByVal 0& 'BytesRead返回从文件中实际读入的字符数
If BytesRead = Len(Id) And Id.Reserved = 0 And Id.Type = M_Image_ICON Then
ReDim IDE(0 To Id.Count - 1) As ICONDIRENTRY
For Entry = 0 To Id.Count - 1
ReadFile FileNumber, IDE(Entry), Len(IDE(Entry)), BytesRead, ByVal 0&
If BytesRead <> Len(IDE(Entry)) Then
IsIcon = False
CloseHandle FileNumber
Exit For
End If
Next
Else
IsIcon = False
End If
Else
IsIcon = False
End If
CloseHandle FileNumber
End Function



Public Function IsJpg(ByVal FileName As String) As Boolean
Dim FileNumber As Long
Dim BytesRead As Long
Dim FileSize As Long
Dim SOI As Integer 'JPG文件开始的标志
Dim EOI As Integer 'JPG文件结束的标志

FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If FileNumber <> 0 Then
FileSize = GetFileSize(FileNumber, ByVal 0&)
ReadFile FileNumber, SOI, 2, BytesRead, ByVal 0&
SetFilePointer FileNumber, FileSize - 2, ByVal 0&, FILE_BEGIN
ReadFile FileNumber, EOI, 2, BytesRead, ByVal 0&
If SOI = &HD8FF And EOI = &HD9FF Then
IsJpg = True
End If
End If
CloseHandle FileNumber
End Function



Private Type PCXHeader
Manufacturer As Byte '固定为10=ZSoft
Version As Byte
'0 = 2.5
'2 = 2.8 with palette
'3 = 2.8 without palette
'4 = Pc paintbrush for windows
'5 = Pc Paintbrush ver 3.0+24位固定为5

Encoding As Byte '1 = .PCX RLE,固定为1
Bpp As Byte '1, 2, 4, 8,每像素所需位数
Left As Integer '图像相对于屏幕左上角X坐标(像素为单位)
Top As Integer '图像相对于屏幕左上角Y坐标(像素为单位)
Right As Integer '图像相对于屏幕右下角X坐标(像素为单位)
Bottom As Integer '图像相对于屏幕右下角Y坐标(像素为单位)
HoriResolution As Integer '图像水平分辨率(像素/英寸)
VertResolution As Integer '图像垂直分辨率(像素/英寸)
Palette(0 To 15) As PcxPalette '指明调色板数据,只对16色以下有用
Reserved As Byte '保留,固定为0
Planes As Byte '指定图像色彩平面数,24位真彩色为3个平面
BytesPerLine As Integer '图像宽度(字节),且必须为偶数
PaletteType As Integer '调色板类型,彩色或单色图像为1,灰度图像为2
HScreenSize As Integer '图像的屏幕宽度(像素为单位),0为基准
VScreenSize As Integer '图像的屏幕高度(像素为单位),0为基准
Filter(0 To 53) As Byte '保留域,固定为0
End Type


Public Function IsPcx(FileName As String) As Boolean
Dim FileNumber As Long, BytesRead As Long
Dim Header As PCXHeader

FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If FileNumber <> 0 Then
ReadFile FileNumber, Header, Len(Header), BytesRead, ByVal 0&
If Header.Manufacturer = 10 Then
If Header.Encoding = 1 Then
If Header.Version = 0 Or Header.Version = 2 Or Header.Version = 3 Or Header.Version = 4 Or Header.Version = 5 Then
IsPcx = True
End If
End If
End If
End If
CloseHandle FileNumber
End Function






Private Const II_ORDER As Integer = &H4949 ' Intel 类型的字节顺序
Private Const MM_ORDER As Integer = &H4D4D ' Mortorola 类型的字节顺序

Private Type TiffHeader
ByteOrder As Integer '规定为 'II' 或者 'MM' Intel /Mortorola 类型的字节顺序
Version As Integer 'TIFF文件的版本,为与以前的兼容,为42
IFDOffset As Long 'TIFF文件的第一个IFD在文件中的偏移量,肯定不小于8
End Type


Public Function IsTif(ByVal FileName As String) As Boolean
Dim FileNumber As Long
Dim BytesRead As Long
Dim Header As TiffHeader
FileNumber = CreateFile(FileName, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If FileNumber <> 0 Then
ReadFile FileNumber, Header, Len(Header), BytesRead, ByVal 0&
If Header.ByteOrder = II_ORDER Or Header.ByteOrder = MM_ORDER Then
If Header.Version = &H2A And Header.IFDOffset >= 8 Then
IsTif = True
End If
End If
End If
CloseHandle FileNumber
End Function


hastings 2010-10-27
  • 打赏
  • 举报
回复
把类型设为0,它会自己帮你判断的~~~
另外我发现CxImage类不支持BITMAPV4HEADER类型的位图,
并且里面的UNOCODE和MBCS很混乱,似乎还有越界的情况。

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧