Главная » 2D графика » Низкоуровневая загрузка растра

RSS

Низкоуровневая загрузка растра

Не нравитсяНравится   Рейтинг 0

Теперь рассмотрим процедуру для загрузки 8-ми битного растра. Какая проблема возникает при этом – правильно наличие палитры. В начале процедура будет выглядеть так же, как и предыдущая за исключением изменений в разделе переменных.

1
2
3
4
5
6
7
8
9
10
11
12
13
procedure LoadBitmap8bit(const hWindow: THandle);
var
// Пока без изменений
F : File;
BitmapFileHeader : TBITMAPFILEHEADER;
BitmapInfoHeader : TBITMAPINFOHEADER;
BitmapInfo : TBitMapInfo;
BitmapBits : Pointer;
ReadCount : DWORD;
DC : HDC;
// Массив под палитру
BitmapPal : array [0..255] of TRGBQUAD;
I : byte;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Пока без изменений
AssignFile(F, Bitmap8bitFileName);
Reset(F, 1);
BlockRead(F, BitmapFileHeader, SizeOf(TBitmapFileHeader), ReadCount);
if (ReadCount <> SizeOf(TBitmapFileHeader)) then
begin
  MessageBox(hWnd, 'Ошибка чтения BITMAPFILEHEADER', 'DIB From File Sample', MB_OK+MB_ICONERROR);
  CloseFile(F);
  Exit;
end;
BlockRead(F, BitmapInfoHeader, SizeOf(TBitmapInfoHeader), ReadCount);
if (ReadCount <> SizeOf(TBitmapInfoHeader)) then
begin
  MessageBox(hWnd, 'Ошибка чтения TBITMAPINFOHEADER', 'DIB From File Sample', MB_OK+MB_ICONERROR);
  CloseFile(F);
  Exit;
end;
// Чтение палитры
BlockRead(F, BitmapPal, SizeOf(TRGBQUAD)*256, ReadCount);
// Далее все повторяется, как в предыдущей процедуре
GetMem(BitmapBits, BitmapInfoHeader.biSizeImage);
 
BlockRead(F, BitmapBits^, BitmapInfoHeader.biSizeImage, ReadCount);
if (ReadCount <> BitmapInfoHeader.biSizeImage) then
begin
  MessageBox(hWnd, 'Ошибка чтения данных файла.', 'DIB From File Sample', MB_OK+MB_ICONERROR);
  CloseFile(F);
  Exit;
end;
 
BitmapInfo.bmiHeader:=BitmapInfoHeader;
// Заполнение палитры
for I:=0 to 255 do
begin
  BitmapInfo.bmiColors[I].rgbBlue:=BitmapPal[I].rgbBlue;   BitmapInfo.bmiColors[I].rgbGreen:=BitmapPal[I].rgbGreen;   BitmapInfo.bmiColors[I].rgbRed:=BitmapPal[I].rgbRed;   BitmapInfo.bmiColors[I].rgbReserved:=BitmapPal[I].rgbReserved;
end;
// Создание растра
DC:=GetDC(hWindow);
Bitmap:=CreateDIBitmap(DC, BitmapInfoHeader, CBM_INIT, BitmapBits, BitmapInfo, DIB_RGB_COLORS);
ReleaseDC(hWindow, DC);
 
if Bitmap=0 then
  MessageBox(hWnd, 'Ошибка создания растра.', 'DIB From File Sample', MB_OK+MB_ICONERROR);
 
CloseFile(F);

Вот собственно и все ! Процедура готова. Необходимо остановится на возможностях её использования. В явном виде она аналогична примеру, приведенному в начале статьи Bitmap.LoadFromFile. В чем же её преимущество ? А в том, что с ее помощью можно последовательно считывать не 1 битмап из файла и сколько угодно. Структура файла может быть примерно следующая:

FileHeader
Заголовочная информация (строка типа SuperGame Resource File). Нужна только
доля идентификации файла, а то знаете сколько различных *.dat форматов существует
:)
FileVersion
Версия файла. Необходима для поддержки совместимости. Допустим если номер версии
1.0 используем загрузочную процедуру LoadProc1, а если 1.1 то LoadProc 2. Хотя
в простом случаем и не обязательна.
ResourceCount
Количество растров в файле.
OffsetTable
Таблица смещений
DibHeader
Заголовок 1-го растра
DibBits
Данные 1-го растра
DibHeader
Заголовок N-го растра
DibBits
Заголовок N-го растра
Далее может помещаться совершенно произвольная информация. Например звуковые
ресурсы, текст, видео и т.д.

На первый взгляд громоздкая и не понятная структура. Но при детальном рассмотрении позволяет решить множество проблем. Опишу только несколько возможностей:

  1. Защищенность на достаточно высоком уровне. Во первых Вы получаете собственный формат хранения данных, т.е. простыми программами Ваш файл не просмотришь. Во вторых возможна компрессия ресурсов, т.е. каждая секция DibHeader и DibBits может быть заархивирована и/или зашифрована. Это пожалуй самая интересная часть.
  2. Практически мгновенная загрузка интересующего нас ресурса из огромного файла. Для этого нам необходимо только прочитать маленький заголовок и таблицу смещений. Из таблицы смещений по индексу (или по имени растра, если хранить и имена) получаем необходимое смещение и методом Seek мгновенно перемещаемся на начало данных необходимого растра. При желании, можно кэшировать таблицу смещений в оперативной памяти.
  3. Возможность оптимизации. При использовании одинаковых растров, их признаки я описывал выше, можно хранить только один DibHeader и множество DibBits. При большом количестве растров получается существенная экономия дискового пространства и скорости загрузки.

Вот, далеко не полный, список тех возможностей, которые позволяет реализовать рассмотренный метод. Конечно у него существуют и недостатки:

  1. Необходимо писать «компилятор» или «сшиватель» ресурсов.
  2. Подход сложно реализовать новичку, хотя я попытаюсь это исправить в последующей части статьи.

Список ссылок

Страницы : 1 2 3

Таги: , , ,