以正确的方式从二进制文件中提取存储的png图像

fee*_*all 2 c# binary png binaryfiles binary-data

我有二进制文件,每次包含每个PNG文件(二进制文件不是DLL,不是EXE,没什么常见的,只是包含不同文本信息的文件,PNG文件和其他一些东西.格式文件对我来说是未知的.PNG文件可以显示一个执行此类文件的程序).我没有这个程序的来源做这些文件.我的任务是从二进制文件中提取此PNG文件以显示它或将其保存为PNG.我写了一个代码,它可以处理这些文件中的一部分(比如大约50%的文件),但不是.在不工作的文件上,创建此文件的程序仍然可以显示包含的图像,因此图像在每个文件内部确实有效 - 但无论如何我的代码对某些文件不起作用.

有些图像似乎可能有另一种格式,可能是编码类型(我已尝试过所有不同的编码类型,没有成功).这是我的代码(我希望有人可以告诉我改变什么,图像变得可读).

我的代码是什么:它找到PNG图像"‰PNG"的已知起始字符串和已知的结束字符串"IEND®B`".这个字符串在我的任何二进制文件中都包含PNG.然后我的代码获取开始和结束之间的字符串+开始和结束序列,并使用Encoding.Default将其保存到文件中.大多数通过这种方式提取的PNG文件可以使用图像查看器显示,但大约50%是无效的.如果我用编辑器打开它并将字符与工作图像进行比较,则图像看起来没问题.Sofar我不知道哪个符号是错误图像格式的原因.

如果需要我会提供更多信息,这里是我的代码:

private void button2_Click(object sender, EventArgs e)
    {
        string ReadFile1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "file.dat");
        string WriteFile1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "test.png");
        string TMP = File.ReadAllText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), ReadFile1), Encoding.Default); //System.Text.Encoding.GetEncoding(1251)
        int start1 = TMP.IndexOf("PNG", 0 ,StringComparison.Ordinal);
        if (start1 == 0) { return; }
        int end1 = TMP.IndexOf("IEND", StringComparison.Ordinal);
        string PNG = TMP.Substring(start1 - 1, (end1 + 9) - start1);
        File.WriteAllText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "test.png"), PNG, Encoding.Default);
    }
Run Code Online (Sandbox Code Playgroud)

我还首先考虑使用二进制方法获取PNG并使用此代码,但我只是读取字符串时得到了完全相同的结果.这是我早期的代码.我使用字符串来搜索字节数组中的位置进行比较.我对二进制代码没有运气...

 byte[] by;
        // 1.
        // Open file with a BinaryReader.
        using (BinaryReader b = new BinaryReader(File.Open(ReadFile1, FileMode.Open), Encoding.Default))
        {
            // 2.
            // Variables for our position.
            int pos = start1 - 1;           //I determine the right positions before doing this
            int required = (end1 + 9) - start1; 

            // 3.
            // Seek to our required position.
            b.BaseStream.Seek(pos, SeekOrigin.Begin);

            // 4.
            // Read the next 2000 bytes.
            by = b.ReadBytes(required);
            b.Close();
        }

        FileStream writeStream;
        writeStream = new FileStream(WriteFile1, FileMode.Create);
        BinaryWriter writeBinay = new BinaryWriter(writeStream, Encoding.Default);
        writeBinay.Write(by);
        writeBinay.Close(); */
Run Code Online (Sandbox Code Playgroud)

Mon*_*mas 5

您不应该将文件作为文本文件读取; 内容可能会发生转换.您应该尝试使用File.ReadAllBytes,然后搜索PNG文件的开头和结尾的字节序列,然后写出该字节区域.

要在字节数组中查找字节序列,可以使用如下代码:

private static int IndexOf(byte[] array, byte[] sequence, int startIndex)
{
    if (sequence.Length == 0)
        return -1;

    int found = 0;
    for (int i = startIndex; i < array.Length; i++)
    {
        if (array[i] == sequence[found])
        {
            if (++found == sequence.Length)
            {
                return i - found + 1;
            }
        }
        else
        {
            found = 0;
        }
    }

    return -1;
}

private void button2_Click(object sender, EventArgs e) 
{ 
    string ReadFile1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "file.dat"); 
    string WriteFile1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "test.png"); 

    byte[] TMP = File.ReadAllBytes(ReadFile1);

    byte[] pngStartSequence = new byte[] { 0x89, 0x50, 0x4E, 0x47 };
    byte[] pngEndSequence = new byte[] { 0x49, 0x46, 0x4E, 0x44 };

    int start1 = IndexOf(TMP, pngStartSequence, 0);
    if (start1 == -1)
    {
       // no PNG present
       MessageBox.Show("Could not find PNG header");
       return;
    }

    int end1 = IndexOf(TMP, pngEndSequence, start1 + pngStartSequence.Length);
    if (end1 == -1)
    {
       // no IEND present
       MessageBox.Show("Could not find PNG footer");
       return;
    }

    int pngLength = end1 - start1 + 8;
    byte[] PNG = new byte[pngLength];

    Array.Copy(TMP, start1, PNG, 0, pngLength);

    File.WriteAllBytes(WriteFile1, PNG); 
} 
Run Code Online (Sandbox Code Playgroud)


Arn*_*rne 5

PNG文件是二进制文件.如果您使用某些编码读取它们,您将丢失信息,并且程序的输出不再是有效的PNG文件.有关更多说明和代码示例,请参阅在PNG中使用块.

另请阅读PNG规范:文件结构以获取详细信息.