mp3封面图片的嵌入与显示的代码
现在的智能手机播放器大多可以显示mp3中的封面图片,我们自编的播放器也应与时俱进,跟上潮流,能嵌能显,所以笔者研究了一下这个问题,写出代码,现贴出来与大家共享,对mp3数据结构不熟悉的请先参阅笔者的旧贴《MP3文件的数据结构以及为mp3内嵌歌词的代码》一文。
先看一下嵌入了封面图片的mp3的部分数据:
--------------------------------------------------------------------------
0000: 49 44 33 03 00 00 00 40 01 7A 41 50 49 43 0001 ID3....@.zAPIC..
0010: 00 12 00 00 00 69 6D 61 67 65 2F 6A 70 65 6700 .....image/jpeg.
0020: 03 00 FF D8 FF E0 00 10 4A 46 49 46 00 01 0100 ...?...JFIF....
---------------------------------------------------------------------------
可以看到,封面图片的数据是保存在ID3V2的“APIC”标签帧下的,在这首mp3中,从0022字节起,就是图片的数据,只要把图片的全部数据原封不动地复制到这里就行了。这首mp3的封面图片格式是jpg,其实可以是任何图片格式,只要你播放器上的图片框能显示就行。
一、显示封面图片的代码。
Private Declare Sub CopyMemory Lib "kernel32" Alias"RtlMoveMemory" (Destination As Any, Source As Any, ByVal picLen AsLong)
Private Sub 显示mp3封面图片()
Dim OpenName As String, SaveName As String
Dim ID3v As String * 3, L1 As Byte, L2 As Byte, L3 As Byte
Dim ID3V2Info() As Byte, tem() As Byte
Dim picLen As Long, ID3Len As Long, Place As Long, p As Long, annexAs String
OpenName = "(全路径mp3文件名)"
Open OpenName For Binary As #1
Get #1, , ID3v
If ID3v <> "ID3" Then Close #1: Exit Sub
Get #1, 8, L1
Get #1, , L2
Get #1, , L3
ID3Len = L1
ID3Len = ID3Len * &H4000 + L2 * &H80 + L3
ReDim ID3V2Info(ID3Len - 1)
Get #1, , ID3V2Info
Close #1
tem = StrConv("APIC", vbFromUnicode)
p = InStrB(ID3V2Info, tem): If p = 0 Then Exit Sub '如果没有图片退出
picLen = CLng(ID3V2Info(p + 4)) * 65536 + CLng(ID3V2Info(p + 5)) *256 + ID3V2Info(p + 6)
tem = StrConv("imag", vbFromUnicode)
p = InStrB(p, ID3V2Info, tem): If p = 0 Then Exit Sub
CopyMemory tem(0), ID3V2Info(p + 5), 4 '获取图片格式
annex = Replace(StrConv(tem, vbUnicode), Chr(0), "")
Place = p + IIf(Len(annex) = 4, 12, 11)
picLen = picLen - IIf(Len(annex) = 4, 14, 13)
ReDim tem(picLen - 1)
CopyMemory tem(0), ID3V2Info(Place), picLen '复制图片数据
SaveName = Environ("TEMP") & "picTem." & annex'保存到临时文件夹
Open SaveName For Binary As #100
Put #100, , tem
Close #100
Image1.Picture = LoadPicture(SaveName) '装入图像框
Kill SaveName
End Sub
二、嵌入图片的代码
被嵌入mp3的图片,可以是任何VB图片框能显示的格式。图片尺寸以200—500像素为宜。
Private Type ID3Header 'mp3的ID3头结构
ID As String * 3
Version AsInteger '版本
flag AsByte'标志
Size(3) AsByte'大小
End Type
Private Sub 嵌入封面图片()
On Error GoTo 100
Dim audioData() As Byte '音频文件数据
Dim ImageData() As Byte '图片数据
Dim Size(3) AsByte'帧内容长度
Dim flags AsInteger'标志
Dim picLen AsLong'图片长度
Dim ID3V2 As ID3Header
Dim mp3Name As String, picName As String, ID3v As String * 3, annexAs String
Dim L1 As Byte, L2 As Byte, L3 As Byte, tem() As Byte
Dim mp3Len As Long, v2Len As Long, i As Integer, k As Integer, s AsString
mp3Name = "(全路径mp3文件名)"
picName = "(全路径pic文件名)"
annex = Mid(picName, InStrRev(picName, ".") + 1)
Open picName For Binary As #1
picLen = LOF(1)
ReDim ImageData(picLen - 1)
Get #1, , ImageData
Close #1
Open mp3Name For Binary As #2
mp3Len = LOF(2)
Get #2, , ID3v
If ID3v = "ID3" Then '如果有ID3V2
Get #2, 8, L1
Get #2, , L2
Get #2, , L3
v2Len = L1
v2Len = v2Len * &H4000 + L2 * &H80 + L3+ 11
ReDim audioData(mp3Len - v2Len)
Get #2, v2Len, audioData
End If
Close #2
Select Case LCase(annex)
Case "jpg": k = 14: s ="00696D6167652F6A706567000300"
Case "gif": k = 13: s ="00696D6167652F676966000300"
Case "bmp": k = 13: s ="00696D6167652F626D70000300"
End Select
ReDim tem(k - 1)
For i = 0 To k - 1: tem(i) = Val("&H" & Mid(s, i * 2 + 1,2)): Next
picLen = picLen + k 'k 是 tem 的数量
v2Len = picLen + 10 '标签内容长度,10是帧头长度
s = Right("00000" & Hex(picLen), 6)
Size(1) = Val("&H" & Left(s, 2))
Size(2) = Val("&H" & Mid(s, 3, 2))
Size(3) = Val("&H" & Mid(s, 5))
With ID3V2
.ID = "ID3"
.Version = 3
If v2Len > &H3FFF Then
.Size(1) =v2Len &H4000
.Size(2) =(v2Len Mod &H4000) 128
.Size(3) =v2Len Mod &H4000 Mod 128
Else
.Size(2) =v2Len 128
.Size(3) =v2Len Mod 128
End If
End With
mp3Name = "(全路径新mp3文件名)"
Open mp3Name For Binary As #3Put #3, , ID3V2
Put #3, , "APIC"
Put #3, , Size
Put #3, , flags
Put #3, , tem
Put #3, , ImageData
Put #3, , audioData
100
Close
End Sub
以上的代码,能嵌入jpg、bmp、gif三种格式的图片,如果你想增加嵌入别的格式,请自行改动,作为家庭作业第一题。
以上代码有一个不足之处:把mp3原有的ID3V2信息删除了,如何既能保留原有的ID3V2信息,又能嵌入封面图片,就作为家庭作业第二题吧,如果确实做不出,到163信箱参阅同名邮件的附件。163邮箱帐号:vb62013@163.com,密码:vb620132013。
2014.9.26