ARQUIVO COM FORMATO PROPRIET?RIO

PROFESSOR 13/12/2016 16:26:01
#469701
Olá à todos.

Preciso ler uma seqüência de imagens que estão armazenadas em um arquivo de formato próprio, criado e mantido por outro aplicativo.
Esse arquivo, com extensão [Ô].iset[Ô], possui codificação UTF-8 e gravação dos dados é em formato binário, [Ô]little-endian[Ô].
Em tese, seguindo o layout que me foi informado, tudo ocorre bem até o ponto em que a rotina lê (em uma matriz) os bytes relativos à primeira imagem.
No momento em que tento gerar um novo Bitmap à partir de um MemoryStream baseado naquela matriz de bytes específica, ocorre um erro, sendo que a mensagem de erro é apenas [Ô]Parâmetros Inválidos[Ô].

A definição de layout desse arquivo é, conforme seu criador, a seguinte:

Citação:

...

1. Atualmente o header do arquivo de ImageSet tem o seguinte formato:

· 4 bytes com a assinatura 0x74657366, para confirmar que é valido.
· 4 bytes com a versão do arquivo (hoje é 0x01000000, e quando mudar o layout, eu altero esse valor).
· 4 bytes com o contador de blocos.

2. Depois desse header há um bloco por imagem, com o seguinte layout:
· 4 bytes com o tamanho da imagem.
· Imagem (tipicamente JPEG, mas eventualmente pode conter BMP).
· 4 bytes com o tamanho do template.
· Template (com tamanhos e composições variados, apenas desconsidere este campo).
· 4 bytes com o timestamp da imagem (segundos desde 01/Jan/1970). Esse campo codifica diretamente o valor, sem o prefixo de 4 bytes que aparece nos campos anteriores.
· Um array de floating points (8 bytes cada) contendo o score de cada imagem. O comprimento desse array é o mesmo definido pelo contador que aparece no cabeçalho do arquivo, e como o tamanho é bem conhecido, também dispensa o prefixo de 4 bytes.
· 4 bytes com o tamanho de eventuais comentários.
· Comentário opcional.

3. Cada um desses blocos é prefixado de um inteiro de 4 bytes contendo o tamanho Do bloco todo, e eles são armazenados em sequencia no arquivo.
...



Alguém poderia me dar um auxílio ?

O trecho de código que tenta fazer o trabalho é o seguinte:

...
Try
If IO.File.Exists(arquivo) = True Then
[ô] Formato
Dim oFmt As Encoding = Nothing
[ô] Nome:
Dim oFI As FileInfo = New FileInfo(arquivo)
ret.Arquivo = oFI.Name.Replace(oFI.Extension, [Ô][Ô])
[ô] Encoding:
Using sr = My.Computer.FileSystem.OpenTextFileReader(arquivo)
ret.Encoding = sr.CurrentEncoding
oFmt = ret.Encoding
sr.Close()
End Using
[ô] Cabeçalho:
Using oFS As New FileStream(arquivo, FileMode.Open, FileAccess.Read)
Using oBR As New BinaryReader(oFS)
[ô] Variável para a carga dos bytes.
Dim bQQ As Byte()
[ô] Assinatura:
bQQ = ReadB(oBR, 4) [ô] oBR.ReadBytes(4)
ret.Assinatura = oFmt.GetString(bQQ)
[ô] Versão:
bQQ = ReadB(oBR, 4)
ret.Versao = String.Format([Ô]{0:00}.{1:00}.{2:00}.{3:00}[Ô], bQQ(0), bQQ(1), bQQ(2), bQQ(3))
[ô] Quantidade de faces:
bQQ = ReadB(oBR, 4)
ret.QuantidadeDeFaces = Convert.ToInt64(String.Format([Ô]{0:00}{1:00}{2:00}{3:00}[Ô], bQQ(0), bQQ(1), bQQ(2), bQQ(3)))
[ô] Leitura das faces:
For iFace As Integer = 0 To ret.QuantidadeDeFaces - 1
[ô] Nova face:
Dim fc As New Face With {.Index = (iFace + 1)}
[ô] Tamanho dos blocos de faces
bQQ = ReadB(oBR, 4)
fc.TamanhoDoBloco = Convert.ToInt64(String.Format([Ô]{0:00}{1:00}{2:00}{3:00}[Ô], bQQ(0), bQQ(1), bQQ(2), bQQ(3)))
[ô]Tamanho da imagem:
bQQ = ReadB(oBR, 4)
fc.TamanhoDaImagem = Convert.ToInt64(String.Format([Ô]{0:00}{1:00}{2:00}{3:00}[Ô], bQQ(0), bQQ(1), bQQ(2), bQQ(3)))
[ô] Imagem e bytes:
fc.ImagemEmBytes = ReadB(oBR, fc.TamanhoDaImagem)
[ô] Imagem:
Using ms As MemoryStream = New MemoryStream(fc.ImagemEmBytes)
ms.Position = 0
ms.Seek(0, SeekOrigin.Begin)
Try
Using bmp As Bitmap = Image.FromStream(ms, False, False)
fc.Imagem = bmp.Clone
End Using
Catch ex As Exception
fc.Imagem = New Bitmap(1, 1)
End Try
End Using
[ô] ...
[ô] outros campos
[ô] ...
Next
oBR.Close()
End Using
oFS.Close()
End Using
End If
Catch ex As Exception
ret = Nothing
End Try
...


E a função ReadB, bem simples e que em teoria faz a leitura dos bytes usando a [Ô]little endian[Ô] é a seguinte:

    Private Shared Function ReadB(ByRef oBR As BinaryReader, lenght As Integer) As Byte()
Dim b As Byte() = Nothing
b = oBR.ReadBytes(lenght) [ô].Reverse.ToArray
If BitConverter.IsLittleEndian Then Array.Reverse(b)
Return b
End Function



Grato !
OCELOT 14/12/2016 14:24:54
#469731
Resposta escolhida
Eu diria para você esquecer essa sua função ReadB, ela provavelmente não é necessária pois você já deve estar usando um processador que usa Little Endian, então é só ler os dados normalmente sem precisar inverter a ordem dos bytes

Esse trecho da documentação que você postou está meio confusa para mim, eu não sei se os valores que ela mostra como 0x74657366 e 0x01000000 é realmente um valor em hexadecimal ou é os bytes no arquivo, eu diria para você abrir o arquivo em um editor hexadecimal para conferir, pois veja que se você tiver em um arquivo os bytes em ordem

01 00 00 00

Quando você ler eles como se fosse um inteiro de 32 bits na verdade o seu valor seria o equivalente de escrever no VB

Dim i as Integer = 0x00000001

Pois em memória, e por consequência nos arquivos gravados os bytes ficam em little endian, onde o byte menos significativo é gravado primeiro, porém a representação em hexadecimal quando estamos programando usa o formato que faz mais sentido para a gente, onde o digito mais significativo é vem primeiro, e isso é o que mais confunde quando se começa a ver falar de little endian.

Então eu diria que onde a documentação fala para ler um valor de 4 bytes você pode simplesmente usar o ReadInt32() do BinaryReader, e na hora de ler a imagem simplesmente chame o ReadBytes(tamanho) do BinaryReader
PROFESSOR 15/12/2016 09:24:07
#469746
Grato por sua atenção !

Pois é, ocorre que para algumas informações (por exemplo, a assinatura) o Big Endian é usado, e em outras, o Little Endian. O que está errado na ReadB é checar LittleEndian na BitConverter. esse booleano deveria vir como parâmetro.
PROFESSOR 05/01/2017 16:49:04
#470411
Agradeço a atenção e o tempo dispensado, sobretudo ao OCELOT.

O problema não estava no código: Eu estava lendo arquivos da versão mais recente com essa estrutura de leitura, que usa uma das versões iniciais do padrão.
Bastou ler os arquivos corretos, e tudo funcionou perfeitamente.
Tópico encerrado , respostas não são mais permitidas