Если вам приходится работать с графическими файлами, то, возможно, у вас появится задача получить дополнительную информацию - узнать размеры файла, глубину цвета и т.п. Безусловно, вы можете загрузить картинку из файла на форму или подходящий элемент управления (PictureBox) и получить требуемую информацию. Но, предположим, ваш проект предназначен только для сбора информации о файлах. В этом случае загружать 10-мегапиксельный рисунок в форму неоправданно - получается слишком большой расход памяти. Есть другой способ получения нужной информации. О нем и пойдет речь сегодня.
Графические файлы являются бинарными файлами с определенной структурой. Так вот, в файле уже содержатся необходимые нам данные. Наша задача - уметь извлечь данную информацию. Не будем углубляться в технические детали форматов графических файлов. Достаточно знать, что, например, ширина картинки записана всегда в строго определенном месте от начала файла. Поэтому, нам нужно только открыть файл для считывания байтов, отсчитать нужное количество байт и получить необходимое число. Кстати, по такому принципу устроены не только графические файлы, но и многие другие файлы, например, музыкальные.
Но, вернемся к файлам BMP. В начале каждого файла в формате BMP идет так называемый заголовок файла. В документации он описывается структурой BITMAPFILEHEADER, которая имеет общую длину 14 байтов: три UInt16 и два UInt32. Нас не интересует данный заголовок, поэтому вы его должны просто проигнорировать. Таким образом в коде нам нужно открыть файл и пропустить 14 байт:
reader.ReadBytes(14);
Обратите внимание, что функцию sizeof в данном случае использовать нельзя. Функция sizeof работает только с неуправляемыми ресурсами. После структуры BITMAPFILEHEADER идет структура BITMAPINFOHEADER. Именно, в этой структуре хранится необходимая информация, которую необходимо извлечь (кстати, описание структуры можно найти в справочнике по функциям Windows API для Visual Basic). Вот как будет выглядеть код извлечения информации из файла:
private void ShowBMPInfo(String file)
{
FileStream fs = new FileStream(file, FileMode.Open);
BinaryReader reader = new BinaryReader(fs);
// Пропускаем заголовок файла (14 байтов)
reader.ReadBytes(14);
// Пропускаем размер структуры BITMAPINFOHEADER
reader.ReadUInt32();
// Получаем ширину и высоту
int width = reader.ReadInt32();
int height = reader.ReadInt32();
// опять пропускаем часть байтов
reader.ReadInt16();
// Получаем глубину цвета (битов на пиксел)
Int16 bitsPerPixel = reader.ReadInt16();
// Освобождаем ресурсы
reader.Close();
fs.Close();
// Выводим информацию
MessageBox.Show(width + " x " + height + " x " + bitsPerPixel);
}
private void button1_Click(object sender, EventArgs e)
{
ShowBMPInfo(textBox1.Text); // подставляем путь к файлу
}
Тут есть одна тонкость. Пропускаемые в коде байты на самом деле все равно считываются. Чтобы действительно перепрыгнуть через заданное число байтов, вы должны использовать методы и свойства объекта потока (stream object). Например, получить текущий поток через свойство BaseStream и пропустить первые 14 байтов можно так:
reader.BaseStream.Seek(14, SeekOrigin.Begin);
Кроме того, можно передвинуть внутренний указатель на заданное смещение от конца потока или от текущей позиции. Вот как пропустить короткое целое (2 байта):
reader.BaseStream.Seek(2, SeekOrigin.Current);
С учетом этих особенностей я написал второй вариант извлечения данных из файла.
private void ShowBMPInfo2(String file)
{
FileStream fs = new FileStream(file, FileMode.Open);
BinaryReader reader = new BinaryReader(fs);
// Пропускаем заголовок файла (14 байтов) без считывания
reader.BaseStream.Seek(14, SeekOrigin.Begin);
// Пропускаем размер структуры без считывания
reader.BaseStream.Seek(4, SeekOrigin.Current);
// Получаем ширину и высоту
int width = reader.ReadInt32();
int height = reader.ReadInt32();
// Пропускаем
reader.ReadInt16();
// Получаем глубину цвета (битов на пиксел)
Int16 bitsPerPixel = reader.ReadInt16();
reader.Close();
fs.Close();
// Выводим информацию
MessageBox.Show(width + " x " + height + " x " + bitsPerPixel * planes);
}
private void button2_Click(object sender, EventArgs e)
{
ShowBMPInfo2(textBox1.Text);
}
Толчком к написаню данного топика послужила статья из журнала MSDN за август 2002 года. Там же вы можете найти код для Visual Basic.NET.
Данный совет также будет помещен в раздел Графика на моем сайте.
Удачного вам программирования!
Комментариев нет:
Отправить комментарий