Я пытаюсь создать код для распаковки изображения RLE, ориентированного на байты, из файла PostScript. Я уже пробовал решения, найденные в Интернете, а также пытался создать свой собственный; но ни один из них не дал нужного мне результата.
После распаковки изображения rle у меня должно быть изображение RAW, которое я могу открыть в фотошопе (с указанием ширины, высоты и количества каналов). Однако, когда я пытаюсь открыть извлеченное изображение, оно не работает; отображается только черный вывод.
Мои входные данные представляют собой двоичный файл с кодировкой ASCII (закодированный как шестнадцатеричная строка) и двоичный файл; оба RLE сжаты с байтовой ориентацией (в случае шестнадцатеричного файла это просто вопрос преобразования его в байты перед попыткой декомпрессии rle).
https://drive.google.com/drive/u/0/folders/1Q476HB9SvOG_RDwK6J7PPycbw94zjPYU Я разместил образцы здесь.
Рабочий образец.raw -> Образец изображения, который я получил с помощью другого программного обеспечения, а также его размеры.
MySample.raw -> Образец изображения, который я создал, используя свой код, а также его размеры.
Исходный файл.ppf -> Файл, содержащий исходные данные изображения и все остальное.
Извлеченный двоичный файл.bin -> Только бинарная часть из OriginalFile.ppf — облегчает чтение и работу с данными.
Этот код был предоставлен пользователем нергудс, он является частью сообщества 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 раз (от 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 Compressed — это только недействительные файлы RAW, которые нельзя просмотреть даже в фотошопе или IrfanViewer.
Любой вклад приветствуется. Спасибо.
РЕДАКТИРОВАТЬ1: застрял на этой части
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;
}
}
Это логика, которой я следую. Раньше это вызывало исключение, но я понял это (это было потому, что я забыл добавить конечный байт; это не имеет значения в конечном результате).
Это было мое понимание объяснения ... может быть, я ошибся в понимании английского? Не знаю. У меня очень хороший английский, но я действительно запутался... Если длина байта >= 128, я должен реплицировать следующий байт 257 - длина раз. Эта часть у меня очень хорошо получилась. Возможно, я немного запутался в первой части (первое условие). Давай попробуем здесь.
Скопировано сверху: If the length byte is in the range 0 to 127, the FOLLOWING length + 1 BYTES (1 to 128 bytes) are to be copied literally upon decompression
- обратите внимание на мой акцент.
Учитывая, что длина байта равна 5. Я должен скопировать следующие шесть (5 + 1) байтов, а затем перейти к следующей итерации цикла?
Почти. Скопируйте следующие 5 байтов, с [1] по [6], затем установите следующий индекс чтения на 7 для следующей итерации цикла.
Извините, мой плохой, вы правы, если значение 5, то нужно скопировать 6 байт.
Если это так, прежде всего я должен изменить цикл на обычный цикл (вместо foreach). Держите вторую попытку внести изменения
Я отредактировал вопрос. Я добавил, где я застрял на данный момент .... не могу понять, как добавить следующие байты без какого-либо RangeException.
Хотя это не указано явно, я полагаю, что вы пытаетесь извлечь изображение с кодировкой RunLength из файла Postscript и сохранить его как TIFF в оттенках серого.
В качестве отправной точки для чего-то подобного вы пытались просто сохранить изображение несжатый из файла Postscript в виде TIFF в оттенках серого, чтобы убедиться, что логика вашего приложения, отвечающая за создание данных изображения TIFF, действительно работает так, как вы ожидаете? Я хотел бы предупредить, что это будет хорошим первым шагом, прежде чем переходить к поддержке распаковки данных RLE для последующего преобразования в TIFF.
Причина, по которой я считаю это важным, заключается в том, что ваша проблема может не иметь ничего общего с как, когда вы распаковываете данные RLE, а скорее с тем, как вы создаете выходной TIFF из предположительно правильно декодированных данных.
Привет. Да, я сделал. И это сработало, я смог создать TIFF с помощью Emgu (OpenCV Wrapper). Сейчас я отредактирую вопрос и добавлю текущий прогресс.
я отредактировал вопрос и добавил информацию. Как я уже сказал, логика создания изображения из несжатых данных в порядке; никаких проблем по этому поводу. Мои проблемы связаны со сжатием RLE. Мне удалось извлечь только «части» исходного изображения, но часть его имеет только черные пятна (например, отсутствие данных). Анализируя файл в шестнадцатеричном редакторе, я также вижу много нулей (где у меня должны быть данные).
Попробуйте эту базовую схему:
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);
}
}
Во всяком случае, так я понимаю то, что указано выше.
Я думаю, что ваш второй currlen неправильный. Это всего лишь 257 - lengthByte, не более того. Я изменил эту строку, и изображение заработало. Я попробую больше ампул, но эй - спасибо! Через 5 дней я добился некоторого прогресса. Кажется, я был близок к этому...
просто вопрос: я не вижу, чтобы вы где-либо обновляли значение I. Код останавливается, потому что я добавил условие исключения, которое прерывается, когда оно выходит за пределы допустимого диапазона. Я получаю его приращение внутри байтового файла?
i++
увеличивает i
(и возвращает его значение до того, как оно было увеличено).
Вы туда не несжатые байты копируете, а только
binPart[1]
- не должно бытьbinPart[i + 1]
или что-то подобное?