[Closed] Biped Preview image as TGA included in .bip files
Hi
Just found out that the Biped preview image(s) are included in the .bip files.
They are encrypted as TGA’s and have DATA-TYPE 10 format ending with TRUEVISION-XFILE
So whoever (like me) wants to use this information to create previews without opening the Biped in the scene can just extract the data out of the file and safe it as a TGA to show it.
Here is a short code example:
Cheers
Hi maT-Star,
How are you taking this data and saving out a TGA from it?
You could open the file binary (openFile <filename_string> mode:“rb”), read the file with readDelimitedString <filestream> “TRUEVISION-XFILE” to read until the end tag of TGA and just define the starting position, as it is different in Biped files. Then just format it out to a different file (create a file with createFile, name it .tga and I would use openFile <filename_string> mode:“wb” afterwards to open the new file binary).
I did not test this, but I think it might work
Ok, I got it now working.
What it does:
- Reads the file and gets the end point of the TGA part
- Writes the TGA out to a seperate file which can then be loaded in an rollout (btw. the bitmap control can load TGA too)
function extractBipedTGA bipPath =
(
--// open the file to read binary
binFile = fopen bipPath "rb"
--// create saveTo file if not available
if (getFiles "C:\ est_tga.tga").count == 0 then
createFile "C:\ est_tga.tga"
--// open saveTo file binary
binSaveFile = fopen "C:\ est_tga2.tga" "wb"
--// retrieve the end of file
fseek binFile 0 #seek_end
endFile = ftell binFile
--// TGA header start
fseek binFile 24 #seek_set
--// indication of TGA
tempString = "TRUEVISION-XFILE"
TGAEnd = 0
foundTill = 1
--// going through the file and getting position of the TRUEVISION-XFILE
while ftell binFile < endFile - 1 do
(
--// checks, if the last indicator is found
if foundTill <= tempString.count then
(
--// comapres the indexed indicator with the current readed char
if tempString[foundTill] == bit.intAsChar (readByte binFile #unsigned) then
--// increase indicator to the next char
foundTill += 1
--// otherwise reset, to start from the beginning
else
foundTill = 1
)
else
(
--// set the TGA ending
TGAEnd = ftell binFile
exit
)
)
--// TGA file end
TGAEnd += 2
--// TGA header start
fseek binFile 24 #seek_set
while ftell binFile < TGAEnd do
writeByte binSaveFile (readByte binFile #unsigned) #unsigned
fclose binFile
fclose binSaveFile
)
This works only for the first preview image of the Biped file.
If you want to access the rest of them (max. 5 I think) then you need to the same steps according to the start point of the TGA).
(.max files have the preview image as bitmap format at the end of the file btw. ^^)
Here is the function to extract the bitmap from the max file.
Is quite fast too
I hope Autodesk does not change their format now
function extractMaxBMP maxPath =
(
--// open the file to read binary
binFile = fopen maxPath "rb"
--// create saveTo file if not available
if (getFiles "C:\ est_preview.bmp").count == 0 then
createFile "C:\ est_preview.bmp"
--// open saveTo file binary
binSaveFile = fopen "C:\ est_preview.bmp" "wb"
--// retrieve the end of file
fseek binFile 0 #seek_end
endFile = ftell binFile
--// rough guess where to start the search for the BMP header
fseek binFile (endFile - 70000) #seek_set
--// indication of BMP start
startIndicator = #(255, 255,255,255,3,0,0,0,1,0,128) --// FF FF FF FF 03 00 00 00 01 00 80 as integer
BMPStart = 0
foundTill = 1
--// going through the file and getting position of the BMP start indicator
while ftell binFile < endFile - 1 do
(
--// checks, if the last indicator is found
if foundTill <= startIndicator.count then
(
--// comapres the indexed indicator with the current readed char
if startIndicator[foundTill] == (readByte binFile #unsigned) then
--// increase indicator to the next char
foundTill += 1
--// otherwise reset, to start from the beginning
else
foundTill = 1
)
else
(
--// set the BMP Start
BMPStart = ftell binFile
exit
)
)
--// BMP file start
BMPStart += 37
--// BMP header start
fseek binFile BMPStart #seek_set
--// writing the BMP part to a new file
while ftell binFile < endFile do
writeByte binSaveFile (readByte binFile #unsigned) #unsigned
--// moving to the start of the BMP file
fseek binSaveFile 0 #seek_set
--// new header as the max file had funny stuff in it
local addedValues = #(66,77,0,0,0,0,0,0,0,0,54)
--// writing new header
for i = 1 to addedValues.count do
writeByte binSaveFile addedValues[i] #unsigned
--// closing binStreams
fclose binFile
fclose binSaveFile
)
Hi Mathias,
That is great stuff, brilliant. I wish you had been here before I tried to do this with DotNet! In your comments you have a part where you take a rough guess to the start of the file. I assume that is because the size of the thumb can vary?
Do you think this method could be converted to a DotNet language like c# or VB? I would love to be able to take this method and embed it into a class library, as my method involved installing a COM class to retrieve the file from IpropertyStorage. I’m not sure, but I would have thought that the method could be converted. any thoughts?
Seriously, good work my friend. thankyou.:applause::bowdown:
Here we go, a VB.net conversion – only useful if you are wanting to extract max thumbs for class libraries. This function should be pasted into a visualstudio.net project and called with the maxfile path as a string
What i’d like to look into is to to be able to extract straight to an image object, but it works. thanks again Mathias, you are a binary god.
Public Sub GetMaxThumb(ByVal file As String)
Dim SaveFileStream As New FileStream("C:\\_MThumb.bmp", FileMode.Create, FileAccess.Write)
Dim MaxFileStream = New FileStream(file, FileMode.Open, FileAccess.Read)
Dim binfile As New StreamReader(MaxFileStream)
Dim endfile As Long = binfile.BaseStream.Seek(0, SeekOrigin.End)
binfile.BaseStream.Position = endfile - 70000
Dim startIndicator As Byte() = {255, 255, 255, 255, 3, 0, 0, 0, 1, 0, 128}
Dim BMPStart As Long = 0
Dim foundTill As Long = 1
While binfile.BaseStream.Position < endfile - 1
If foundTill <= startIndicator.Length - 1 Then
If startIndicator.GetValue(foundTill) = binfile.BaseStream.ReadByte() Then
foundTill += 1
Else
foundTill = 0
End If
Else
BMPStart = binfile.BaseStream.Position
Exit While
End If
End While
BMPStart += 37
binfile.BaseStream.Position = BMPStart
Dim BinWriter As New StreamWriter(SaveFileStream)
While binfile.BaseStream.Position < endfile
BinWriter.BaseStream.WriteByte(binfile.BaseStream.ReadByte())
End While
BinWriter.BaseStream.Seek(0, SeekOrigin.Begin)
Dim addedValues As Byte() = {66, 77, 0, 0, 0, 0, 0, 0, 0, 0, 54}
'For Each addval In addedValues
' BinWriter.BaseStream.WriteByte(addval)
'Next
' this seems to be better
BinWriter.BaseStream.Write(addedValues, 0, addedValues.Length)
binfile.Close()
BinWriter.Close()
SaveFileStream.Close()
MaxFileStream.Close()
End Sub
End Sub
there’s possibly a few methods with the streamwriter class that may well do things a bit more directly, but i haven’t been able to suss them out yet. if anyone who is good with this thing could take a look and see if it’s the most efficient way, please let me know.
a ha, in vb.net i can get a bitmap from a filestream like so –
Dim newbmp As New System.Drawing.Bitmap(BinWriter.BaseStream)
I’m getting a few access issues with running my code in a loop to find all the maxthumbs from a folder of files – it seems that the previous image hasn’t finished saving before the next read is attempted. Is that a disk limitation or do i have to code it to wait until the save is performed? I’m working a bit in the dark with these methods so any pointers welcome.
p.s. whoo hoo, getting close to 4 figure post count, better think of something good to say…