Added code to display some info about the IHDR, pHYs, and tEXt chunks.

This commit is contained in:
moosecrab 2023-10-24 23:57:49 -07:00
parent 9d69cb51bd
commit 4ad99d6769

View File

@ -24,10 +24,13 @@
If Not FileIO.FileSystem.FileExists(filename) Then If Not FileIO.FileSystem.FileExists(filename) Then
Console.WriteLine("File {0} not found!", filename) Console.WriteLine("File {0} not found!", filename)
Exit Sub
End If End If
Dim fs As New IO.FileStream(filename, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read) Dim fs As New IO.FileStream(filename, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
Dim fi As New IO.FileInfo(filename) Dim fi As New IO.FileInfo(filename)
Dim sizedigits As Integer = Math.Ceiling(Math.Log10(fs.Length))
While Not fs.Position = fs.Length While Not fs.Position = fs.Length
Dim startposition As Long = fs.Position Dim startposition As Long = fs.Position
FindHeader(fs) FindHeader(fs)
@ -59,40 +62,54 @@
End If End If
Dim buf() As Byte Dim lenbuf(3), nameanddatabuf(), databuf(), crcbuf(3) As Byte
Dim len As Integer Dim len As Integer
Dim chunklength As UInt32 Dim chunklength As UInt32
Dim chunktype As String = String.Empty Dim chunktype As String = String.Empty
While chunktype <> "IEND" AndAlso fs.Position <> fs.Length While chunktype <> "IEND" AndAlso fs.Position <> fs.Length
ReDim buf(3) Console.ForegroundColor = ConsoleColor.White
len = fs.Read(buf, 0, 4)
'read chunk length
len = fs.Read(lenbuf, 0, 4)
If len <> 4 Then If len <> 4 Then
Console.WriteLine("Incomplete chunk length header") Console.WriteLine("Incomplete chunk length header")
Exit While Exit While
End If End If
'big endian 'read and print chunk length and offset in the file
chunklength = &H1000000L * buf(0) + &H10000L * buf(1) + &H100L * buf(2) + buf(3) chunklength = BigEndianUInt32(lenbuf)
Console.Write("{0,10}:", chunklength) Console.Write("{0," & sizedigits & "} @ {1,-" & sizedigits & "}:", chunklength, fs.Position - 4)
ReDim buf(chunklength + 3) 'read in the chunk data and type
len = fs.Read(buf, 0, chunklength + 4) ReDim nameanddatabuf(chunklength + 3)
ReDim databuf(chunklength - 1)
len = fs.Read(nameanddatabuf, 0, chunklength + 4)
'rewind and read only the chunk data
fs.Seek(-chunklength, IO.SeekOrigin.Current)
fs.Read(databuf, 0, chunklength)
'check for incomplete reads
If len <> chunklength + 4 Then If len <> chunklength + 4 Then
Console.WriteLine("Incomplete chunk data") Console.WriteLine("Incomplete chunk data")
Exit While Exit While
End If End If
chunktype = System.Text.Encoding.ASCII.GetString(buf, 0, 4)
Console.Write(chunktype & " ")
Dim datachecksum As UInt32 = Crc32.ComputeChecksum(buf)
ReDim buf(3) 'get chunk type as string
len = fs.Read(buf, 0, 4) chunktype = System.Text.Encoding.ASCII.GetString(nameanddatabuf, 0, 4)
Console.Write(chunktype & " ")
'compute checksum of the chunk
Dim datachecksum As UInt32 = Crc32.ComputeChecksum(nameanddatabuf)
'read reported checksum and compare it to the file
len = fs.Read(crcbuf, 0, 4)
If len <> 4 Then If len <> 4 Then
Console.WriteLine("Incomplete CRC data") Console.WriteLine("Incomplete CRC data")
End If End If
Dim chunkchecksum As UInt32 = &H1000000L * buf(0) + &H10000L * buf(1) + &H100L * buf(2) + buf(3) Dim chunkchecksum As UInt32 = BigEndianUInt32(crcbuf)
If chunkchecksum = datachecksum Then If chunkchecksum = datachecksum Then
Console.Write("ok") Console.Write("ok")
Else Else
@ -100,6 +117,10 @@
End If End If
Console.WriteLine() Console.WriteLine()
'print info for some chunks
Console.ForegroundColor = ConsoleColor.Gray
PrintChunkInfo(chunktype, databuf)
End While End While
If extract Then If extract Then
@ -110,6 +131,10 @@
End While End While
fs.Close() fs.Close()
#If CONFIG = "Debug" Then
Console.ReadKey()
#End If
End Sub End Sub
Public Sub FindHeader(fs As IO.FileStream) Public Sub FindHeader(fs As IO.FileStream)
@ -128,6 +153,10 @@
End While End While
End Sub End Sub
Private Function BigEndianUInt32(ByRef buf As Byte(), Optional offset As Integer = 0) As UInt32
Return &H1000000L * buf(0 + offset) + &H10000L * buf(1 + offset) + &H100L * buf(2 + offset) + buf(3 + offset)
End Function
Public Sub CopyPart(srcfile As String, destfile As String, offset As Long, bytes As Long) Public Sub CopyPart(srcfile As String, destfile As String, offset As Long, bytes As Long)
Dim srcfs As New IO.FileStream(srcfile, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read) Dim srcfs As New IO.FileStream(srcfile, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
Dim destfs As New IO.FileStream(destfile, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.Read) Dim destfs As New IO.FileStream(destfile, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.Read)
@ -139,6 +168,110 @@
destfs.Close() destfs.Close()
End Sub End Sub
Private Sub PrintChunkInfo(chunktype As String, ByRef data As Byte())
Select Case chunktype
Case "IHDR"
'image width
Console.WriteLine("width: {0} px", BigEndianUInt32(data, 0))
'image height
Console.WriteLine("height: {0} px", BigEndianUInt32(data, 4))
'bit depth
Dim bitdepth As Byte = data(8)
If {1, 2, 4, 8, 16}.Contains(bitdepth) Then
Console.WriteLine("bit depth: {0} bits/sample", bitdepth)
Else
Console.WriteLine("bit depth: {0} bits/sample INVALID", bitdepth)
End If
'color types
Dim colortype As Byte = data(9)
Dim colortypename As String
Select Case colortype
Case 0
colortypename = "greyscale"
If Not {1, 2, 4, 8, 16}.Contains(bitdepth) Then
colortypename &= ", INVALID BIT DEPTH"
End If
Case 2
colortypename = "truecolor"
If Not {8, 16}.Contains(bitdepth) Then
colortypename &= ", INVALID BIT DEPTH"
End If
Case 3
colortypename = "indexed"
If Not {1, 2, 4, 8}.Contains(bitdepth) Then
colortypename &= ", INVALID BIT DEPTH"
End If
Case 4
colortypename = "greyscale with alpha"
If Not {8, 16}.Contains(bitdepth) Then
colortypename &= ", INVALID BIT DEPTH"
End If
Case 6
colortypename = "truecolor with alpha"
If Not {8, 16}.Contains(bitdepth) Then
colortypename &= ", INVALID BIT DEPTH"
End If
Case Else
colortypename = "UNKNOWN"
End Select
Console.WriteLine("color type: {0} ({1})", colortype, colortypename)
'compression method
If data(10) = 0 Then
Console.WriteLine("compression method: 0 (deflate)")
Else
Console.WriteLine("compression method: {0} (UNKNOWN)", data(10))
End If
'filter method
If data(11) = 0 Then
Console.WriteLine("filter method: 0 (adaptive)")
Else
Console.WriteLine("filter method: {0} (UNKNOWN)", data(11))
End If
'interlace method
If data(12) = 0 Then
Console.WriteLine("interlace method: 0 (no interlace)")
ElseIf data(12) = 1 Then
Console.WriteLine("interlace method: 1 (Adam7)")
Else
Console.WriteLine("interlace method: {0} (UNKNOWN)", data(12))
End If
'end IHDR
Case "pHYs"
Dim unitsaremetres As Boolean = (data(8) = 1)
If unitsaremetres Then
Console.WriteLine("pixels per unit, x: {0} px ({1:g} ppi)", BigEndianUInt32(data, 0), BigEndianUInt32(data, 0) * 0.0254)
Console.WriteLine("pixels per unit, y: {0} px ({1:g} ppi)", BigEndianUInt32(data, 4), BigEndianUInt32(data, 0) * 0.0254)
Else
Console.WriteLine("pixels per unit, x: {0} px", BigEndianUInt32(data, 0))
Console.WriteLine("pixels per unit, y: {0} px", BigEndianUInt32(data, 4))
End If
If data(8) = 0 Then
Console.WriteLine("units: 0 (unknown)")
ElseIf data(8) = 1 Then
Console.WriteLine("units: 1 (metre)")
Else
Console.WriteLine("units: {0} (UNKNOWN)", data(8))
End If
Case "tEXt"
Dim keywordlength As Integer = Array.FindIndex(data, Function(x) x = &H0) - 1
Dim keyword(keywordlength - 1) As Byte
Dim textstring(data.Length - keywordlength - 1 - 1) As Byte
Array.Copy(data, 0, keyword, 0, keywordlength)
Array.Copy(data, keywordlength + 1, textstring, 0, data.Length - keywordlength - 1)
Console.WriteLine("keyword: {0}", System.Text.Encoding.GetEncoding("ISO-8859-1").GetString(keyword))
Console.WriteLine("value: {0}", System.Text.Encoding.GetEncoding("ISO-8859-1").GetString(textstring))
End Select
End Sub
Public Class Crc32 Public Class Crc32
Shared table As UInteger() Shared table As UInteger()