我有二进制文件,一次包含每个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);
}
我还首先考虑使用二进制方法获取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(); */
答案 0 :(得分: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);
}
答案 1 :(得分:5)
PNG文件是二进制文件。如果您使用某些编码读取它们,您将丢失信息,并且程序的输出不再是有效的PNG文件。有关更多说明和代码示例,请参阅Using Chunks in a PNG。
另请阅读PNG Specifiaction: File structure了解详细信息。
答案 2 :(得分:1)
使用File.ReadAllBytes
和File.WriteAllBytes
。阅读和写作文本可能会受到编码的影响。
您可以使用Jb Evain algorithm在Byte Array
中查找模式,如下所示:
static void Main()
{
// PNG file signature
var startPattern = new byte[] { 137, 80, 78, 71, 13, 10, 26, 105 };
var data = File.ReadAllBytes("png file");
var start = data.Locate(startPattern);
// and end like this
}
public static int[] Locate(this byte[] self, byte[] candidate)
{
if (IsEmptyLocate(self, candidate))
return Empty;
var list = new List<int>();
for (int i = 0; i < self.Length; i++)
{
if (!IsMatch(self, i, candidate))
continue;
list.Add(i);
}
return list.Count == 0 ? Empty : list.ToArray();
}
static bool IsMatch(byte[] array, int position, byte[] candidate)
{
if (candidate.Length > (array.Length - position))
return false;
for (int i = 0; i < candidate.Length; i++)
if (array[position + i] != candidate[i])
return false;
return true;
}
static readonly int[] Empty = new int[0];
static bool IsEmptyLocate(byte[] array, byte[] candidate)
{
return array == null
|| candidate == null
|| array.Length == 0
|| candidate.Length == 0
|| candidate.Length > array.Length;
}