Среда, 08.05.2024
Королевство Delphi
Главное меню
Статьи
Наш опрос
Как часто ви на этот сайт заходите?
Всего ответов: 159
Статистика
Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Главная » Статьи » Разные » Разные

Формат файлов RES применительно к BITMAP-ресурсам

Написать данную статью автора побудило недостаточное количество информации в рунете и за его пределами для написания своего компилятора ресурсов типа BITMAP. Начнём!

RES-файл представляет собой файл, в котором записаны поверх друг друга заголовки ресурсов и соответственно сами данные ресурсов:

Header (Заголовок)
DATA (Данные)
Header (Заголовок)
DATA (Даные)

Заголовок из себя представляет некую структуру с полями:

typedef struct {
 DWORD DataSize;
 DWORD HeaderSize;
 DWORD TYPE;
 DWORD NAME;
 DWORD DataVersion;
 WORD MemoryFlags;
 WORD LanguageId;
 DWORD Version;
 DWORD Characteristics;
} RESOURCEHEADER;

Но эта структура лишь является эталонной моделью, как в сетях является эталонной моделью модель ISO/OSI. На практике же чаще используется менее ромоздкая конструкция:

typedef struct {
 DWORD DataSize;
 DWORD HeaderSize;
 DWORD TYPE;
 DWORD NAME;
} RESOURCEHEADER;

Разберемся, что значат поля в этой структуре.

DataSize — размер данных ресурса, т.е. данных, копируемых из файла bmp. Он всегда меньше реального размера файла на 14 бит ввиду того, что отбрасываются несколько полей заголовка файла bmp (да-да, у bmp файлов тоже есть заголовок, как впрочем и у всех остальных типов файлов).

HeaderSize — размер заголовка ресурса, т.е. размер, занимаемый всей структурой RESOURCEHEADER в байтах.
Эта структура разделена на две части: базу ResourceHeaderBase, значение которой всегда 32 и, по-видимому, отражает принадлежность ресурса к 32 битному приложению; вторая часть — ResourceHeaderOffset равна разнице между размером заголовка и базой.

TYPE — тип ресурса, в нашем случае это значение равно FFFF0200, где ключевым числом является 2 т.к. именно оно является числовым эквивалентом типа BITMAP.
Значения для других типов можно посмотреть здесь: http://msdn.microsoft.com/en-us/library/ms648009(VS.85).aspx
Записываем, конечно, в шестнадцатеричном виде.

NAME — официально это поле имеет тип DWORD. MS пишет, что на самом деле это поле является строкой с нулевым окончанием. На практике было выяснено, что в поле NAME записывается по одному коду символа в ASCII кодировке с отделением символов друг от друга нулевым битом, после чего по неизвестному автору алгоритму строка добивается нулевыми битами, после чего ставится ASCII код нуля.

Также стоит заметить, что в начале заголовка ставится значение типа DWORD, равное нулю, и в конце заголовка ставится два значения типа DWORD, равные нулю.

Рассмотрим, как на практике пишется файл ресурса по смещениям:

Смещение Поле
4 ResourceHeaderBase
8 FFFF
12 FFFF
32 DataSize
36 ResourceHeaderOffset
40 TYPE
44 NAME

Далее, после заголовка записываются данные из bmp-файла, начиная с 14 бита, потому что, как я уже писал, часть заголовка bmp-файла отбрасывается.

Ниже приведена программа, записывающая из-bmp файла ресурс. Однако у этой программы есть одно ограничение ввиду того, что, как я уже писал, я не знаю, каким образом высчитывается количество нулевых битов в поле NAME до ASCII значения нуля, поэтому размер имени ресурса не может превышать двух символов.

unit Unit1;
 
interface
 
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;
 
type
 TForm1 = class(TForm)
 Button1: TButton;
 OpenDialog1: TOpenDialog;
 Edit1: TEdit;
 procedure Button1Click(Sender: TObject);
 private
 { Private declarations }
 public
 { Public declarations }
 end;
 
type Header = Record
DataSize:DWORD;
HeaderSize:DWORD;
Base:DWORD;
RcType:DWORD;
NAME:String;
End;
 
const
HearedSizeBase = 4;
HeaderSizeOffset = 36;
DataSizeOffset = 32;
TypeOffset = 40;
NameOffset = 44;
 
var
 Form1: TForm1;
 MyRes,SrcFile: TFileStream;
 Heder:Header;
 NULL: array [0..43] of byte;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
Buf: BYTE;
Count: LongInt;
FFFF:DWORD;
CHR:WORD;
 
begin
for i:=0 to 43 do
NULL[i]:=0;
i:=FileCreate('Resource.res');//Создаем сам файл ресурса
FileClose(i);
 
MyRes:=TFileStream.Create('Resource.res',fmOpenWrite);
If OpenDialog1.Execute=true then
SrcFile:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead);
 
 Heder.NAME:=Edit1.Text;//Имя текущего файла для записи в ресурсы
 Heder.DataSize:=SrcFile.Size-14;//Размер ресурса (-14 это отбрасываемая часть заголовка файла bmp)
 Heder.RcType:=$0002FFFF; //ffff0200 тип ресурса
 
 //Записываем описание ресурса
 MyRes.Write(NULL,SizeOf(NULL));
 MyRes.Seek(8,soFromBeginning);
 FFFF:=$0000FFFF;
 MyRes.Write(FFFF,SizeOf(FFFF));//Не знаю почему но эти биты должны иметь именно такое значение
 MyRes.Write(FFFF,SizeOf(FFFF));
 MyRes.Seek(HearedSizeBase,soFromBeginning);
 Heder.Base:=32;
 MyRes.Write(Heder.Base,SizeOf(Heder.Base));//записываем базу заголовка
 MyRes.Seek(DataSizeOffset,soFromBeginning);
 MyRes.Write(Heder.DataSize,SizeOf(Heder.DataSize));//записываем размер данных
 
 MyRes.Seek(NameOffset-2,soFromBeginning);//Записываем имя ресурса
 For i:=0 to Length(Heder.Name) do
 Begin
 CHR:=Ord(Heder.Name[i]);
 MyRes.Write(CHR,SizeOf(CHR));
 End;
 
 buf:=0; //Выравнивание
 if Length(Heder.Name)=1 Then
 For i:=1 to 6 do
 MyRes.Write(buf,SizeOf(buf))
 Else
 Begin
 FFFF:=$00000000;
 For i:=1 to 2 do//расчет
 MyRes.Write(FFFF,SizeOf(FFFF));
 End;
 FFFF:=$00001030;
 MyRes.Write(FFFF,SizeOf(FFFF));
 
 i:=MyRes.Seek(0,soFromCurrent);
 MyRes.Seek(TypeOffset,soFromBeginning);
 MyRes.Write(Heder.RcType,SizeOf(Heder.RcType));//Записываем тип ресурса
 MyRes.Seek(i,soFromBeginning);
 
 FFFF:=$00000000;
 MyRes.Write(FFFF,SizeOf(FFFF));
 MyRes.Write(FFFF,SizeOf(FFFF));
 
 i:=MyRes.Seek(0,soFromCurrent);
 Heder.HeaderSize:=i-32;//Размер описания ресурса
 MyRes.Seek(HeaderSizeOffset,soFromBeginning);
 MyRes.Write(Heder.HeaderSize,SizeOf(Heder.HeaderSize));//записываем разницу между размером и базой заголовка
 MyRes.Seek(i,soFromBeginning);
 
 //пишем сам ресурс
 Count:=14;//Отбрасываем часть заголовка bmp файла
 SrcFile.Seek(14,soFromBeginning);
 While Count<SrcFile.Size do
 Begin
 SrcFile.Read(Buf,1);
 MyRes.Write(Buf,1);
 Count:=Count+1;
 End;
 
 SrcFile.Free;
 MyRes.Free;
 ShowMessage('Готово');
end;
 
end.

Получить ссылку на материал

Категория: Разные | Добавил: Барон (15.12.2011)
Просмотров: 885 | Теги: ресур, Bitmap, RES | Рейтинг: 0.0/0
[ Пожертвования для сайта ] [ Пожаловаться на материал ]

Если вам помог материал сайта кликните по оплаченной рекламе размещенной в центре

Поиск
Категории раздела
Delphi.NET [3]
Kylix Delphi for Linux [9]
Советы Дельферу [6]
Хитрости в Delphi [2]
Обзор Delphi [45]
Инсталлятор [11]
Пользовательский интерфейс [18]
Примеры Delphi [93]
Функции и процедуры [15]
Разные [31]
Королевство Delphi © 2010-2024
Яндекс цитирования