[RESOLVED] Save an image file in Alternate Data Stream
I am using the ADS for normal strings very successfully, but I cannot work out how to save/retrieve an image file.
Say I had Cover.jpg and I wanted to attach it to CD1Track01.mp3 as an ADS - CD1Track01.mp3:Cover.jpg.
How do I write and then read the ADS so that I end up with Cover.jpg (or .png/.gif/.bmp) again for showing.
VB6 SP6.
Many thanks.
PS. In case you are wondering why I don't use the Tag metadata. Well I do; my favourite is AudioGenie but this stopped developing in 2010 and knows nothing of Aiff, Opus etc and cannot read/write images to half of its supported formats. The other TagsLib.dll from un4seen.com reads/writes everything, with pictures, but gives me occasional crashes. I'm just fed up with it all!
Seems simple enough. This demo adds a canned "album art" image to SomeFile.txt though an .MP3 file wouldn't be any different:
Code:
Option Explicit
Private Const FILE_NAME As String = "SomeFile.txt"
Private Declare Function DeleteFile Lib "kernel32" Alias "DeleteFileA" ( _
ByVal FileName As String) As Long
Private ArtBytes() As Byte
Private Sub DisplayArt()
Dim StdPicture As StdPicture
With New WIA.Vector
.BinaryData = ArtBytes
Set StdPicture = .Picture
End With
With Picture1
.AutoRedraw = True
With StdPicture
.Render Picture1.hDC, _
0, _
0, _
ScaleX(Picture1.ScaleWidth, Picture1.ScaleMode, vbPixels), _
ScaleY(Picture1.ScaleHeight, Picture1.ScaleMode, vbPixels), _
0, _
.Height, _
.Width, _
-.Height, _
ByVal 0&
End With
.Picture = .Image
.AutoRedraw = False
End With
End Sub
Private Sub cmdAdd_Click()
Dim F As Integer
cmdAdd.Enabled = False
F = FreeFile(0)
Open "Resources\CWB.gif" For Binary Access Read As #F
ReDim ArtBytes(LOF(F) - 1)
Get #F, , ArtBytes
Close #F
F = FreeFile(0)
Open FILE_NAME & ":Art" For Binary Access Write As #F
Put #F, , ArtBytes
Close #F
DisplayArt
cmdRemove.Enabled = True
End Sub
Private Sub cmdRemove_Click()
cmdRemove.Enabled = False
'Note that VB6 "Kill" will not accept an alternate data stream name:
DeleteFile FILE_NAME & ":Art"
Picture1.Picture = Nothing
cmdAdd.Enabled = True
End Sub
Private Sub Form_Load()
Dim F As Integer
On Error Resume Next
GetAttr FILE_NAME
If Err Then Exit Sub
Err.Clear
GetAttr FILE_NAME & ":Art"
If Err Then
cmdAdd.Enabled = True
Else
On Error GoTo 0
F = FreeFile(0)
Open FILE_NAME & ":Art" For Binary Access Read As #F
ReDim ArtBytes(LOF(F) - 1)
Get #F, , ArtBytes
Close #F
DisplayArt
cmdRemove.Enabled = True
End If
End Sub
As always - many thanks dil. I haven't been using the wia due to quality issues. I have been using a routine (which I think came from you) using GDI+. This works extremely well but needs a filename, unless you knowe a different method.
Code:
Private Sub DrawThumbnail(ByVal sFileName As String)
Dim Graphics As Long, img As Long
Dim W As Single, H As Single, wNew As Single, hNew As Single, Ratio As Double
Dim wMax As Long, hMax As Long
GdiStartup
GdipLoadImageFromFile StrPtr(sFileName), img 'Load the image into memory
Pic1.Cls
If img > 0 Then
GdipGetImageDimension img, W, H
If W > 0 And H > 0 Then
Dimensions = "Picture size: " & W & " x " & H
PicFileName = sFileName
wMax = Pic1.ScaleWidth: hMax = Pic1.ScaleHeight
Ratio = Min(wMax / W, hMax / H) 'Resize keeping Ratio
wNew = W * Ratio: hNew = H * Ratio
GdipCreateFromHDC Pic1.hDC, Graphics 'Initialize the graphics class - required for all drawing
GdipSetInterpolationMode Graphics, 7 'QualityModeHigh = 2 : InterpolationModeHighQualityBicubic = 7
GdipSetSmoothingMode Graphics, SmoothingModeAntiAlias '<-- is ignored in ClipPath :/
GdipDrawImageRectI Graphics, img, (wMax - wNew) / 2, (hMax - hNew) / 2, wNew, hNew
Else
Dimensions = "Image Corrupt"
End If
Else
Dimensions = "No Image found!"
End If
GdipDisposeImage img 'Delete the image
GdipDeleteGraphics Graphics 'Delete the graphics
GdiShutdown
fraPic.Caption = Dimensions
cmdCopyArt.Enabled = InStrB(Dimensions, "Picture size:")
End Sub
You can extract what you need from Stream.cls to create a stream on memory or a resource, see the CreateMemStream() and CreateResStream() methods. Or you could just use the class as is.
Here is a Project I had handy with that class in it, though the Project itself does not address your situation.