创建一个代码来解压缩面向字节的 RLE 图像
Creating a code to decompress byte-oriented RLE image
我正在尝试创建一个代码来从 PostScript 文件中解压一个面向字节的 RLE 图像但是 none 产生了我需要的结果。
解压缩rle图像后,我应该有一个可以在photoshop上打开的RAW图像(告知宽度,高度和通道数)。但是,当我尝试打开提取的图像时,它不起作用;仅显示黑色输出。
我的输入是一个二进制 ASCII 编码文件(编码为十六进制字符串)和一个二进制文件;两者都是 RLE 字节导向的压缩(在十六进制文件的情况下,它只是在尝试 rle 解压缩之前将其转换为字节的问题)。
https://drive.google.com/drive/u/0/folders/1Q476HB9SvOG_RDwK6J7PPycbw94zjPYU
我在这里发布了示例。
WorkingSample.raw -> 我使用其他软件获得的图像样本及其尺寸。
MySample.raw -> 我使用我的代码构建的图像样本及其尺寸。
OriginalFile.ppf -> 包含原始图像数据和其他所有内容的文件。
ExtractedBinary.bin -> 只有 OriginalFile.ppf 的二进制部分 - 更易于阅读和使用数据。
此代码由用户 nyerguds 提供,他是 SO 社区的一员。
原始来源:http://www.shikadi.net/moddingwiki/RLE_Compression#Types_of_RLE
它是我尝试使用的那个,但结果不正确。老实说,我很难理解他的代码(他告诉我要更改一些内容以使其适用于我的情况,但我无法做到)。
这是我根据 PostScript 红皮书尝试做的事情:
书:https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
那个部分:
“RunLengthEncode 过滤器根据 运行 长度以面向简单字节的格式对数据进行编码。
压缩数据格式是 运行 的序列,其中每个 运行 包含一个长度字节,后跟 1 到 128 个字节的数据。如果长度字节在 0 到 127 范围内,则在解压缩时将按字面复制以下长度 + 1 个字节(1 到 128 字节)。如果长度在 129 到 255 的范围内,则在解压缩时将复制以下单个字节 257 - length 次(2 到 128 次)。”
第 142 页,RunLengthEncode 过滤器。
List<byte> final = new List<byte>();
var split01 = ArraySplit(bytefile, 2);
foreach (var binPart in split01)
{
try
{
if (binPart.ElementAt(0) <= 127)
{
int currLen = binPart[0] + 1;
for (int i = 0; i <= binPart[0]; i++)
{
final.Add(binPart[1]);
//Console.WriteLine(binPart[1]);
}
}
else if (binPart[0] >= 128)
{
int currLen = 257 - binPart[0];
for (int i = 0; i < currLen; i++)
{
final.Add(binPart[1]);
// Console.WriteLine(binPart[1]);
}
}
}
catch(Exception)
{
break;
}
}
File.WriteAllBytes(@"C:\test\again.raw", final.ToArray());
private static IEnumerable<byte[]> ArraySplit(byte[] bArray, int intBufforLengt)
{
int bArrayLenght = bArray.Length;
byte[] bReturn = null;
int i = 0;
for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
{
bReturn = new byte[intBufforLengt];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
yield return bReturn;
}
int intBufforLeft = bArrayLenght - i * intBufforLengt;
if (intBufforLeft > 0)
{
bReturn = new byte[intBufforLeft];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
yield return bReturn;
}
}
private static byte[] StringToByteArray(String hex)
{
int iValue = 0;
int NumberChars = hex.Length;
if (NumberChars % 2 != 0)
{
string m = string.Empty;
}
byte[] bytes = new byte[NumberChars / 2];
try
{
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
iValue = i;
}
}
catch (Exception e)
{
var value = iValue;
Console.WriteLine(e.Message);
}
return bytes;
}
所需的输出将是 TIFF 灰度。但是,我也可以处理 PNG。
我已经设法从这种文件中提取 未压缩的 数据;使用 Emgu(OpenCV Wrapper)我能够创建一个可视图像并在其上执行我的逻辑。
我的 RLE 压缩的实际结果只是无效的 RAW 文件,即使在 photoshop 或 IrfanViewer 上也无法查看。
欢迎任何意见。谢谢。
EDIT1:停留在这部分
for(int i=0; i < bytefile.Length; i+=2)
{
try
{
var lengthByte = bytefile[i];
if (lengthByte <= 127)
{
int currLen = lengthByte + 1;
for (int j = 0; j < currLen; j++)
{
final.Add(bytefile[i]);
i++;
}
}
if (bytefile[i] >= 128)
{
int currLen = 257 - bytefile[i];
for (int k = 0; k < currLen; k++)
{
final.Add(bytefile[i + 1]);
}
}
}
catch(Exception)
{
break;
}
}
这就是我遵循的逻辑。在引发异常之前,但我想通了(这是因为我忘记添加结束字节;对最终结果没有影响)。
虽然没有明确说明,但我相信您正试图从 Postscript 文件中提取 RunLength 编码图像并将其保存为灰度 TIFF。
作为此类事情的起点,您是否尝试过简单地从 Postscript 文件中保存一个 未压缩的 图像作为灰度 TIFF,以确保您的应用程序逻辑负责构建TIFF 图像数据确实如您所愿?我要提醒的是,在继续支持解压缩 RLE 数据然后将其转换为 TIFF 之前,这将是一个很好的第一步。
我认为这很重要的原因是因为你的问题可能与如何你解压缩 RLE 数据无关,而是你如何从中创建输出 TIFF大概是正确解码的数据。
试试这个基本大纲:
int i = 0;
while (i < bytefile.length)
{
var lengthByte = bytefile[i++];
if (lengthByte <= 127)
{
int currLen = lengthByte + 1;
for (int j = 0; j < currLen; j++)
final.Add(bytefile[i++]);
}
else
{
int currLen = 257 - lengthByte;
byte byteToCopy = bytefile[i++];
for (int j = 0; j < currLen; j++)
final.Add(byteToCopy);
}
}
无论如何,这就是我对上面指定内容的理解。
我正在尝试创建一个代码来从 PostScript 文件中解压一个面向字节的 RLE 图像但是 none 产生了我需要的结果。
解压缩rle图像后,我应该有一个可以在photoshop上打开的RAW图像(告知宽度,高度和通道数)。但是,当我尝试打开提取的图像时,它不起作用;仅显示黑色输出。
我的输入是一个二进制 ASCII 编码文件(编码为十六进制字符串)和一个二进制文件;两者都是 RLE 字节导向的压缩(在十六进制文件的情况下,它只是在尝试 rle 解压缩之前将其转换为字节的问题)。
https://drive.google.com/drive/u/0/folders/1Q476HB9SvOG_RDwK6J7PPycbw94zjPYU 我在这里发布了示例。
WorkingSample.raw -> 我使用其他软件获得的图像样本及其尺寸。
MySample.raw -> 我使用我的代码构建的图像样本及其尺寸。
OriginalFile.ppf -> 包含原始图像数据和其他所有内容的文件。
ExtractedBinary.bin -> 只有 OriginalFile.ppf 的二进制部分 - 更易于阅读和使用数据。
此代码由用户 nyerguds 提供,他是 SO 社区的一员。 原始来源:http://www.shikadi.net/moddingwiki/RLE_Compression#Types_of_RLE 它是我尝试使用的那个,但结果不正确。老实说,我很难理解他的代码(他告诉我要更改一些内容以使其适用于我的情况,但我无法做到)。
这是我根据 PostScript 红皮书尝试做的事情: 书:https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf 那个部分: “RunLengthEncode 过滤器根据 运行 长度以面向简单字节的格式对数据进行编码。 压缩数据格式是 运行 的序列,其中每个 运行 包含一个长度字节,后跟 1 到 128 个字节的数据。如果长度字节在 0 到 127 范围内,则在解压缩时将按字面复制以下长度 + 1 个字节(1 到 128 字节)。如果长度在 129 到 255 的范围内,则在解压缩时将复制以下单个字节 257 - length 次(2 到 128 次)。” 第 142 页,RunLengthEncode 过滤器。
List<byte> final = new List<byte>();
var split01 = ArraySplit(bytefile, 2);
foreach (var binPart in split01)
{
try
{
if (binPart.ElementAt(0) <= 127)
{
int currLen = binPart[0] + 1;
for (int i = 0; i <= binPart[0]; i++)
{
final.Add(binPart[1]);
//Console.WriteLine(binPart[1]);
}
}
else if (binPart[0] >= 128)
{
int currLen = 257 - binPart[0];
for (int i = 0; i < currLen; i++)
{
final.Add(binPart[1]);
// Console.WriteLine(binPart[1]);
}
}
}
catch(Exception)
{
break;
}
}
File.WriteAllBytes(@"C:\test\again.raw", final.ToArray());
private static IEnumerable<byte[]> ArraySplit(byte[] bArray, int intBufforLengt)
{
int bArrayLenght = bArray.Length;
byte[] bReturn = null;
int i = 0;
for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
{
bReturn = new byte[intBufforLengt];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
yield return bReturn;
}
int intBufforLeft = bArrayLenght - i * intBufforLengt;
if (intBufforLeft > 0)
{
bReturn = new byte[intBufforLeft];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
yield return bReturn;
}
}
private static byte[] StringToByteArray(String hex)
{
int iValue = 0;
int NumberChars = hex.Length;
if (NumberChars % 2 != 0)
{
string m = string.Empty;
}
byte[] bytes = new byte[NumberChars / 2];
try
{
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
iValue = i;
}
}
catch (Exception e)
{
var value = iValue;
Console.WriteLine(e.Message);
}
return bytes;
}
所需的输出将是 TIFF 灰度。但是,我也可以处理 PNG。 我已经设法从这种文件中提取 未压缩的 数据;使用 Emgu(OpenCV Wrapper)我能够创建一个可视图像并在其上执行我的逻辑。
我的 RLE 压缩的实际结果只是无效的 RAW 文件,即使在 photoshop 或 IrfanViewer 上也无法查看。
欢迎任何意见。谢谢。
EDIT1:停留在这部分
for(int i=0; i < bytefile.Length; i+=2)
{
try
{
var lengthByte = bytefile[i];
if (lengthByte <= 127)
{
int currLen = lengthByte + 1;
for (int j = 0; j < currLen; j++)
{
final.Add(bytefile[i]);
i++;
}
}
if (bytefile[i] >= 128)
{
int currLen = 257 - bytefile[i];
for (int k = 0; k < currLen; k++)
{
final.Add(bytefile[i + 1]);
}
}
}
catch(Exception)
{
break;
}
}
这就是我遵循的逻辑。在引发异常之前,但我想通了(这是因为我忘记添加结束字节;对最终结果没有影响)。
虽然没有明确说明,但我相信您正试图从 Postscript 文件中提取 RunLength 编码图像并将其保存为灰度 TIFF。
作为此类事情的起点,您是否尝试过简单地从 Postscript 文件中保存一个 未压缩的 图像作为灰度 TIFF,以确保您的应用程序逻辑负责构建TIFF 图像数据确实如您所愿?我要提醒的是,在继续支持解压缩 RLE 数据然后将其转换为 TIFF 之前,这将是一个很好的第一步。
我认为这很重要的原因是因为你的问题可能与如何你解压缩 RLE 数据无关,而是你如何从中创建输出 TIFF大概是正确解码的数据。
试试这个基本大纲:
int i = 0;
while (i < bytefile.length)
{
var lengthByte = bytefile[i++];
if (lengthByte <= 127)
{
int currLen = lengthByte + 1;
for (int j = 0; j < currLen; j++)
final.Add(bytefile[i++]);
}
else
{
int currLen = 257 - lengthByte;
byte byteToCopy = bytefile[i++];
for (int j = 0; j < currLen; j++)
final.Add(byteToCopy);
}
}
无论如何,这就是我对上面指定内容的理解。