Я пишу библиотеку C# для интерпретации и отображения изображений из файлов TIF, где полосы данных изображения сжимаются с использованием сжатия LZW. Я тестирую его с набором из 21 файла TIF, созданных другим приложением, которое я не могу контролировать.
Я где-то читал, что данные изображения должны начинаться с чистого кода, но его нет в Adobe TIFF6 spe c, и я не могу сейчас найти его источник.
В 14 тестовых файлах данные изображения начинаются со значения кода LZW Clear 256 ( первые байты в данных изображения - 0x8000, поэтому первые 9 битов 1000 0000 0000 0000 равны 1 0000 0000 = 256 десятичных). Я могу распаковать и отобразить их без проблем.
Однако в 7 файлах первые два байта сжатых данных LZW имеют значение 0x06FA, 0x0712 или 0x097A. Очевидно, это не простой код, который заставил бы меня инициализировать мою таблицу строк LZW. Даже когда таблица строк LZW инициализируется с начальными 256 значениями, я очень быстро сталкиваюсь с кодами в сжатых данных LZW, которые не имеют соответствующей записи в таблице строк, вызывая ошибку.
0x06FA = 0000 0110 1111 1010 first 9 bits = 0 0000 1101 = 0x0D = 13 decimal
0x0712 = 0000 0111 0001 0010 first 9 bits = 0 0000 1110 = 0x0E = 14 decimal
0x097A = 0000 1001 0111 1010 first 9 bits = 0 0001 0010 = 0x12 = 18 decimal
Имеют ли эти значения какое-то особое значение, которое я еще не обнаружил? Должны ли они рассматриваться как обычные коды в таблице строк? Если так, почему я впоследствии сталкиваюсь с кодами, которые еще не получили запись в таблице строк? Или 7 файлов, с которыми у меня проблемы, не соответствуют спецификации c? Они хорошо отображаются в IrfanView, поэтому я предполагаю, что они соответствуют.
Вот мой код распаковки, который я сохранил как можно ближе к алгоритму в TIFF6 spe c.
public byte[] DecompressToBytes()
{
List<byte> decompressed = new List<byte>();
int oldCode = 0;
int code = 0;
string entry;
// Just in case the first code we encounter isn't the clearcode.
initializeDictionary();
// getNextCode decides whether to read a 9, 10, 11 or 12 bit value
// based on size of string table Dictionary.
while(((code = getNextCode()) != EndOfInformation)) // EndOfInformation = 257
{
if(code == ClearCode) // ClearCode = 256
{
initializeDictionary();
code = getNextCode();
if(code == EndOfInformation)
break;
entry = Dictionary[code];
// convert string (eg "0A0B0C") to bytes and add to output.
addBytes(decompressed, entry);
oldCode = code;
}
else
{
if(Dictionary.ContainsKey(code))
{
entry = Dictionary[code];
addBytes(decompressed, entry);
Dictionary.Add(Dictionary.Count, stringFromCode(oldCode) + stringFromCode(code).Substring(0, 2));
oldCode = code;
}
else
{
entry = stringFromCode(oldCode) + stringFromCode(oldCode).Substring(0, 2);
addBytes(decompressed, entry);
Dictionary.Add(Dictionary.Count, entry);
oldCode = code;
}
}
}
return decompressed.ToArray();
}