Титульная страница DelphiGFX Сделать закладку Написать письмо автору сервера 

  Главная - Документация - 2D Графика

Мастера Delphi | Corba  

Обзор формата DIB и компонентов для работы с ним

Copyright © 2001 Мироводин Дмитрий  

Содержание

Что такое DIB ?
TFastDIB
TBitmap
TUniDIB
TDIB ( TDXDib )
TUltraDIB
Тестирование
Выводы
Список ссылок

Что такое DIB ?

Если вы когда-либо занимались программированием для Windows, то наверняка знаете, что растры (bitmaps) встречаются повсюду. Это происходит не только из-за того, что графический формат BMP является единственным, который непосредственно поддерживается Windows ( не считая значков (icons), возможности которых крайне ограничены). Просмотрите любое руководство по программированию для Windows, и вы найдете в нем такие функции, как CreateBitmap() , LoadBitmap() , StretchDIBits() и BitBlt() для создания, загрузки и вывода растров на экран, однако вы не обнаружите аналогичных функций для других графических форматов - например PCX, TIFF или GIF. Следовательно, вы не сможем сколько-нибудь заметно продвинуться в программировании игр для Windows, если не научитесь работать с растрами.

Аппаратно-зависимые и аппаратно-независимые растры

Аппаратно-зависимыми растрами называются графические изображения, которые могут отображаться лишь на графических устройствах определенного типа. Например, при работе с такими функциями Windows, как CreateBitmap() или LoadBitmap(), вы создаете в памяти растровое изображение, совместимое с некоторым устройством - обычно экраном монитора. Растры такого типа иногда называют растрами GDI, поскольку интерфейс графических устройств (GDI - Graphics Device Interface) системы Windows способен правильно работать с ними. Аппаратно-зависимые растры не содержат цветовых таблиц, поскольку в них используются цвета того устройства, с которым они связаны. Более того, аппаратно-зависимые растры обычно существуют только в памяти, а не в виде файлов на диске.

Аппаратно-независимыми растрами называются графические изображения, которые могут отображаться на устройствах различных типов. В таких растрах хранится цветовая таблица, используемая назначенным устройством для их отображения, чтобы в разных условиях они выглядели одинаково. Например, аппаратно-независимый растр должен под Windows казаться практически таким же, как и под DOS или OS/2. Поскольку аппаратно-независимые растры обычно являются переносимыми (portable) между различными системами, они часто сохраняются в виде файлов на диске. Например, если вы заглянете в папку Windows, то найдете там много файлов с расширением .BMP. В них хранятся аппаратно-независимые растры. Вы можете создавать свои собственные аппаратно-независимые растры с помощью разнообразных графических редакторов, среди которых - Windows Paint, имеющийся в каждой стандартной поставке Windows. Аппаратно-независимые растры часто называются DIB (от Device-Independed Bitmaps) - для краткости мы будем называть их именно так.

Формат DIB

Независимо от того, хранится ли DIB в памяти или на диске, его структура практически одинакова. Фактически файл DIB состоит из последовательно расположенных структур нескольких типов. Это структуры BITMAPFILEHEADER , BITMAPINFO , BITMAPINFOHEADER и RGBQUAD. В последующих разделах рассматривается каждая из этих структур и ее использование в программах для Windows.

Структура BITMAPFILEHEADER

В начале файла DIB расположена структура BITMAPFILEHEADER. Приведу ее описание для Windows, взято из модуля windows.pas

PBitmapFileHeader = ^TBitmapFileHeader;
TBitmapFileHeader = packed record
  bfType: Word;
  bfSize: DWORD;
  bfReserved1: Word;
  bfReserved2: Word;
  bfOffBits: DWORD;
end;

Хотя данная структура располагается в начале файла на диске, она не обязана присутствовать в растрах, находящихся в памяти. Первое поле структуры, bfType, служит для идентификации файлов растровой графики и должно содержать ASCII-коды символов BM. В шестнадцатеричном виде значение bfType должно быть равно 4D42; в противном случае файл, вероятно, не содержит растрового изображения. Второе поле структуры, bfSize, должно содержать размер файла в байтах. Однако из-за ошибки в исходной документации Windows значение bfSize ненадежно и пользоваться им не следует. С другой стороны, вы вполне можете положиться на значение bfOffBits, в котором хранится смещение в байтах от начала растрового файла до массива данных. Структура BITMAPINFOHEADER кратко описана в таблице:

bfType WORD Содержит ASCII-коды символов «BM»
bfReserved1 WORD Всегда равен 0
bfReserved2 WORD Всегда равен 0
bfOffBits DWORD Смещение в байтах от начала файла до графических данных
Структура BITMAPINFO

За структурой BITMAPFILEHEADER следует структура BITMAPINFO. Приводится ее описание для Windows:

type PBitmapInfo = ^TBitmapInfo;

TBitmapInfo = packed record
  bmiHeader: TBitmapInfoHeader;
  bmiColors: array[0..0] of TRGBQuad;
end;

Как видите, эта структура состоит из заголовка в виде структуры BITMAPINFOHEADER и цветовой таблицы в виде массива структур RGBQUAD.

Структура BITMAPINFOHEADER

Теперь приведу описание структуры TBITMAPINFOHEADER для Windows:

PBitmapInfoHeader = ^TBitmapInfoHeader;

TBitmapInfoHeader = packed record
  biSize: DWORD;
  biWidth: Longint;
  biHeight: Longint;
  biPlanes: Word;
  biBitCount: Word;
  biCompression: DWORD;
  biSizeImage: DWORD;
  biXPelsPerMeter: Longint;
  biYPelsPerMeter: Longint;
  biClrUsed: DWORD;
  biClrImportant: DWORD;
end;

В поле biSize содержится размер структуры BITMAPINFOHEADER, который должен быть равен 40 байтам. Поля biWidth и biHeight содержат соответственно ширину и высоту растра в пикселях. biPlanes всегда присваивается значение 1. Число в поле biBitCount, обозначающее количество битов на пиксель, может быть равно 1, 4, 8 или 24, что соответствует монохромным, 16-цветным, 256-цветным и, наконец, полноцветным (16,7 миллиона цветов) изображениям. Обычно в играх используют 8 или 24-х битные растры.

Поле biCompression показывает тип сжатия (компрессии), использованного в растре; значение 0 означает отсутствие сжатия, 1 - сжатие по алгоритму RLE-8, а 2 - сжатие по алгоритму RLE-4. Если вы не знакомы с техникой сжатия данных, не стоит волноваться - в файлах DIB сжатие применяется редко. Обычно поле biCompression содержит 0.

Поле biSize содержит размер растра в байтах и, как правило, используется только для сжатых растров. При этом учитывается тот факт, что число байтов в каждой строке растра всегда кратно 4. При необходимости строки дополняются пустыми байтами. Однако, только если вы не пишете программу для создания DIB, вам не придется иметь дела с дополнением строк и трудностями, которые при этом возникают.

Поля biXPelsPerMeter и biYPelsPerMeter предназначены для указания количества пикселей на метр по горизонтали и вертикали, но обычно в них содержится 0. Поля biClrUsed и biClrImportant, задающие общее количество использованных цветов и количество значащих цветов соответственно, также обычно остаются равными 0.

Возможно, вы обратили внимание на то, что поля структуры BITMAPINFOHEADER, следующие после biBitCount, обычно равны 0, так что после чтения структуры из дискового файла на их значения полагаться не следует. В этой главе мы узнаем, как вычислить любые необходимые параметры - такие, как количество цветов, использованных в изображении, - и сохранить их в соответствующих полях структуры для будущего использования. Для удобства структура BITMAPINFOHEADER кратко описана в таблице:

biSize DWORD Размер данной структуры в байтах
biWidth DWORD Ширина растра в пикселях
biHeight DWORD Высота растра в пикселях
biPlanes WORD Всегда равен 1
biBitCount WORD Количество битов на пиксель
biCompression DWORD Тип сжатия: 0 = отсутствует, 1 = RLE-8, 2 = RLE-4
biSizeImage DWORD Размер растра в байтах
biXPelsPerMeter DWORD Количество пикселей на метр по горизонтали
biYPelsPerMeter DWORD Количество пикселей на метр по вертикали
biClrUsed DWORD Количество использованных цветов
biClrImportant DWORD Количество значащих цветов
Структура RGBQUAD

Описание последней структуры, RGBQUAD, приведено в листинге

PRGBQuad = ^TRGBQuad; TRGBQuad = packed record
  rgbBlue: Byte;
  rgbGreen: Byte;
  rgbRed: Byte;
  rgbReserved: Byte;
end;

В данной структуре всего лишь хранятся интенсивности красной, зеленой и синей составляющих цвета. Каждый цвет в DIB представлен отдельной структурой RGBQUAD. Таким образом, для 16-цветового (4-битного) растра цветовая таблица состоит из 16 структур RGBQUAD, а для 256-цветового (8-битного) цветовая таблица состоит из 256 структур RGBQUAD. Исключение составляют 24-битные изображения, в которых цветовая таблица вообще отсутствует.

За структурой BITMAPINFO в DIB следует массив с данными изображения. Его объем, конечно, зависит от размера изображения.

На последок еще раз приведу структуру DIB файла:

Теперь можно перейти к рассмотрению компонентов работающих с DIB структурами. Напомню что можно не использовать компоненты, а использовать обычные API функций ( их и используют все описанные ниже компоненты ). Но это не всегда удобно, т.к. иногда хочется получить некоторые дополнительные возможности, вроде поворота изображения, размытия и т.д. В данном обзоре будут рассмотрены 5 компонентов для работы с DIB.

TFastDIB

Компонент состоит из следующих модулей:

fastdib.pas updated: 8/24/2000 версия v3.56 Gordon Cowie
fastfx.pas updated: 7/15/2000 Gordon Cowie
fastquant.pas updated: 7/7/99 Gordon Alex Cowie III
fastsize.pas updated: 8/19/99 Gordon Cowie

Сам класс TFastDIB находится в модуле fastdib.pas, он является наследником TObject. Я выделю наиболее интересные свойства, процедуры и функции присущие данному классу:

procedure Assign(Bmp:TFastDIB);
property Pixels[y,x:Integer]:TFColor read GetPixel write SetPixel;
property PixelsB[y,x:Integer]:Byte read GetPixelB write SetPixelB;
procedure SetSize(fWidth,fHeight:Integer;fBpp:Byte);
procedure SetSizeEx(fWidth,fHeight:Integer;fBpp,fBpr,fBpg,fBpb:Byte);
procedure SetSizeIndirect(bmInfo:TBMInfo);
procedure SetInterface(fBits:Pointer; fWidth,fHeight:Integer;fBpp,fBpr,fBpg,fBpb:Byte);
procedure SetInterfaceIndirect(fBits:Pointer;bmInfo:TBMInfo);
procedure SetSubset(fBmp:TFastDIB;x,y,w,h:Integer);
procedure MakeCopy(fBmp:TFastDIB);

procedure LoadFromHandle(hBmp:Integer);
procedure LoadFromFile(FileName:string);
procedure LoadFromStream(Stream:TStream);
procedure LoadFromRes(hInst:Integer;ResID,ResType:PChar);
procedure LoadFromClipboard;
procedure SaveToClipboard;
procedure SaveToFile(FileName:string); // Процедуры блиттинка - копирования изображения
procedure UpdateColors;
procedure Draw(fDC,x,y:Integer);
procedure Stretch(fDC,x,y,w,h:Integer);
procedure DrawRect(fDC,x,y,w,h,sx,sy:Integer);
procedure StretchRect(fDC,x,y,w,h,sx,sy,sw,sh:Integer);
procedure MaskDraw(fDC,x,y:Integer;Mono:TFastDIB);
procedure MaskRect(fDC,x,y,w,h,sx,sy,mx,my:Integer;Mono:TFastDIB);
procedure TransDraw(fDC,x,y:Integer;c:TFColor);
procedure TransStretch(fDC,x,y,w,h:Integer;c:TFColor);
procedure AlphaDraw(fDC,x,y:Integer;a:Byte;hasAlpha:Boolean);
procedure AlphaStretch(fDC,x,y,w,h:Integer;a:Byte;hasAlpha:Boolean);
procedure TileDraw(fDC,x,y,w,h:Integer);
// Функции аналогичные работе с GDI
procedure SetPen(Style,Width,Color:Integer);
procedure SetBrush(Style,Hatch,Color:Integer);
procedure SetFont(Font:string;Size:Integer);
procedure SetFontEx (Font:string;Width,Height,Weight:Integer;Italic,Underline,Strike:Boolean);
procedure SetTextColor(Color:Integer);
procedure SetTransparent(Transparent:Boolean);
procedure SetBkColor(Color:Integer);
procedure Ellipse(x1,y1,x2,y2:Integer);
procedure FillRect(Rect:TRect);
procedure LineTo(x,y:Integer);
procedure MoveTo(x,y:Integer);
procedure Polygon(Points:array of TPoint);
procedure Polyline(Points:array of TPoint);
procedure Rectangle(x1,y1,x2,y2:Integer);
procedure TextOut(x,y:Integer;Text:string);
procedure DrawText(Text:string;Rect:TRect;Flags:Integer);

В модуле fastquant находятся процедуры и функции для конвертирования изображения с одним количеством цветов в другое, так же и в градации серое.

Модуль fastfx настоящая находка для любителей спецэффектов. Набор функции примерно такой же как у PhotoShop'а. Смотрите сами:

procedure FillLut(var Lut:TLut;x1,y1,x2,y2:Byte);
function MakeWLut(Bmp:TFastDIB;RLut,GLut,BLut:TLut):TWLut;

procedure AutoContrast(Bmp:TFastDIB);
procedure RGB(Bmp:TFastDIB;r,g,b:Integer);
procedure Gamma(Bmp:TFastDIB;r,g,b:Extended);
procedure Contrast(Bmp:TFastDIB;r,g,b:Integer);
procedure Lightness(Bmp:TFastDIB;r,g,b:Integer);
function SaturationLut(Amount:Integer):TSaturationLut;
procedure Saturation(Bmp:TFastDIB;Amount:Integer);
procedure Invert(Bmp:TFastDIB);
procedure AddNoise(Bmp:TFastDIB;Amount:Byte;Mono:Boolean);
procedure SplitBlur(Bmp:TFastDIB;Split:Integer);
procedure SplitConvolve(Bmp:TFastDIB;Split,nw,ne,sw,se,m:Integer);
procedure BlurEdges(Bmp:TFastDIB;Split:Integer);
procedure SharpenMore(Bmp:TFastDIB;Split:Integer);
procedure EmbossEdges(Bmp:TFastDIB;Split:Integer);
procedure QuickSoft(Bmp:TFastDIB);
procedure QuickSharp(Bmp:TFastDIB);
procedure QuickEmboss(Bmp:TFastDIB);
procedure Lines(Bmp:TFastDIB;Lut:TLut);
procedure Mosaic(Bmp:TFastDIB;xAmount,yAmount:Integer);
procedure Shift(Bmp:TFastDIB;xAmount,yAmount:Integer);
procedure AlphaBlend(Dst,Src1,Src2:TFastDIB;Amount:Byte);

procedure MaskCopy(Back,Sprite,Mask:TFastDIB;x,y,w,h,sx,sy,mx,my:Integer);
procedure MaskCopy32(Back,Sprite:TFastDIB;x,y,w,h,sx,sy:Integer;Multiplied:Boolean);procedure Flip(Bmp:TFastDIB);
procedure Flop(Bmp:TFastDIB);
procedure Rotate90CW(Src,Dst:TFastDIB);
procedure Rotate90CCW(Src,Dst:TFastDIB);
procedure Rotate180(Src,Dst:TFastDIB);
procedure RotateSize(Src,Dst:TFastDIB;Angle:Double);
procedure Transform(Src,Dst:TFastDIB;cx,cy,isin,icos:Integer;Smooth:Boolean);
procedure Rotate(Src,Dst:TFastDIB;Angle:Double;Smooth:Boolean);
procedure Rotozoom(Src,Dst:TFastDIB;Angle:Double;Zoom:Integer;Smooth:Boolean);
procedure SquareWave(Src,Dst:TFastDIB;x,y,z:Double);
procedure RoundWave(Src,Dst:TFastDIB;x,y,z:Double);
TBitmap

С этим классом все ясно: наследник класса TGraphic, имеет следующие свойства и функции:

// Свойства
Canvas
Empty
Handle
HandleType
Height
IgnorePalette
MaskHandle
Monochrome
Palette
PixelFormat
ScanLine
TransparentColor
TransparentMode
Width
// Методы
Assign
Create
Destroy
Dormant
FreeImage
LoadFromClipboardFormat
LoadFromResourceID
LoadFromResourceName
LoadFromStream
Mask
ReleaseHandle
ReleaseMaskHandle
ReleasePalette
SaveToClipboardFormat
SaveToStream

Не стану детально описывать этот класс, так как это подробно да и лучше сделано в справке Delphi и в некоторых книжках. Какие есть плюсы: во первых это стандартный компонент, написанный Borland - нет нужды искать другие компоненты, полная совместимость, меньше ошибок в коде. Второе: присутствуют все необходимые процедуры и свойства, ничего лишнего. Это и является главным минусом - все спец эффекты приходится писать самому. При работе с TBitmap постоянно такое чувство, что чего-то не хватает :)
Для тех кто хочет спустится ниже уровня TBitmap, посоветую изучить раздел TBitmap->Bitmap Functions в справке WinAPI ( файл Win32.hlp ).

TUniDIB

Простенький класс, с минимальным набором функций, наследник TObject.

Состоит из следующих модулей:

UniDIB.pas updated 1/4/99 version 1.21 Vit Kovalcik
DIBTools.pas updated 1/4/99 version 1.21 Vit Kovalcik

В первом модуле находится непосредственно сам класс. У данного класса доступны следующие процедуры и свойства:

constructor Create (AWidth,AHeight:LongInt;ABPP:Byte;SByteUse:Byte);
procedure DIBtoScreen(DC:hDC);
procedure SetPalette(Pal:TLogPalette256);
procedure Clear;
procedure DrawHorizLine(X1,X2,Y,Col:Integer);
procedure DrawVertLine (X,Y1,Y2,Col:Integer);
procedure DrawLine (X1,Y1,X2,Y2:integer; Col:Integer);
procedure FillPolygon (Poly:Array of TPoint; FillCol:Integer);
procedure CaptureScreen;
property ActPointer:Pointer read FActPointer write FActPointer;
property Bits:Pointer read FBits;
property DC:HDC read FDC;
property DWordWidth:Cardinal read FDWordWidth;
property Handle:HBITMAP read FHandle;

При работе с TUniDib можно заметить одно неудобство. Процедура DIBtoScreen копирует сразу все изображение, что практически ни когда не нужно. В процедуре не хватает x,y координат и исходного Rect-а для вывода. Хотя это можно обойти переписав процедуру DIBtoScreen, так как она осуществляет простой вызов BITBLT или, что более предпочтительно, использовать Handle на HBitmap. Второй способ лучше тем, что Вы не меняете оригинальный код и соответственно не теряется совместимость.

Во втором модуле DIBTools.pas содержатся всего две процедуры для загрузки из BMP и из PCX файла. Нужно отметить, что это единственный компонент поддерживающий формат PCX.

TDIB ( TDXDib )

Данный компонент входит в состав небезызвестного набора для работы с DirectX - DelphiX. Позволю себе некоторое отступление и расскажу о модулях и компонентах для работы с DirectX. Если бы Вы писали на C++ все было бы очень просто: перед выходом очередной версии DirectX, всеми любимая фирма Microsoft выпускает так называемый пакет для разработчиков, в простонародье SDK. Этот пакет содержит кучу полезных утилит, примеров, справочной информации и собственно заголовков для очередной версии библиотеки DirectX. Занимает все это несколько сотен мегабайт -да здравствует линия T1, хотя версии SDK можно найти и на пиратских дисках. Естественно компания Microsoft ни как не поддерживает пользователей Delphi, и все адаптации "сишных" модулей выпускаются исключительно энтузиастами. От сюда понятно почему существует такое малое количество информации по DirectX применительно к языку Object Pascal. Но все же, существует несколько вариантов библиотек для DirectX и в версиях для Delphi.

Непосредственно сами заголовки для DirectX выпускаются достаточно оперативно, и их всегда можно скачать по адресу: http://www.delphi-jedi.org/DelphiGraphics

Но ведь это простые заголовки, а Вам наверняка захочется воспользоваться удобством VCL. Вот здесь Вам и поможет набор компонентов DelphiX. Его можно скачать по адресу: http://www.yks.ne.jp/~hori/ В интернете Вы сможете найти множество описаний для работы с данным компонентом, большое количество игр и примеров ( некоторые из них представлены и на моем сайте в разделах game source и samples ). Данный проект получил широкое распространение в сети интернет и если Вам затруднительно писать программы, используя только заголовки DirectX, то данный набор компонентов будет оптимальным решением.

Лирическое отступление закончено, начинаем знакомство с самим компонентом.

Сам компонент находится в модуле DIB.pas и там Вы сможете найти две его версии TDXDib - VCL версия, и как обычный класс TDIB.

Компонент является наследником класса TGraphic. Приведу все public свойства и методы:

ColorTable: TRGBQuads;
PixelFormat: TDIBPixelFormat;
constructor Create; override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure Clear;
procedure Compress;
procedure Decompress;
procedure FreeHandle;
procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle; APalette: HPALETTE); override;
procedure LoadFromStream(Stream: TStream); override;
procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle; var APalette: HPALETTE); override;
procedure SaveToStream(Stream: TStream); override;
procedure SetSize(AWidth, AHeight, ABitCount: Integer);
procedure UpdatePalette;
procedure Blur(ABitCount: Integer; Radius: Integer);
procedure Greyscale(ABitCount: Integer);
procedure Mirror(MirrorX, MirrorY: Boolean);
procedure Negative;

property BitCount: Integer read FBitCount write SetBitCount;
property BitmapInfo: PBitmapInfo read GetBitmapInfo;
property BitmapInfoSize: Integer read GetBitmapInfoSize;
property Canvas: TCanvas read GetCanvas;
property Handle: THandle read GetHandle;
property Height: Integer read FHeight write SetHeight;
property NextLine: Integer read FNextLine;
property NowPixelFormat: TDIBPixelFormat read FNowPixelFormat write SetNowPixelFormat;
property PaletteCount: Integer read GetPaletteCount;
property PBits: Pointer read GetPBits;
property PBitsReadOnly: Pointer read GetPBitsReadOnly;
property Pixels[X, Y: Integer]: DWORD read GetPixel write SetPixel;
property ScanLine[Y: Integer]: Pointer read GetScanLine;
property ScanLineReadOnly[Y: Integer]: Pointer read GetScanLineReadOnly;
property Size: Integer read FSize;
property TopPBits: Pointer read GetTopPBits;
property TopPBitsReadOnly: Pointer read GetTopPBitsReadOnly;
property Width: Integer read FWidth write SetWidth;
property WidthBytes: Integer read FWidthBytes;

Рассмотрим, какие есть плюсы у этого класса. Первое - присутствие процедуры Assign.
Если Вы вдруг захотите загрузить JPEG файл это можно будет с легкостью осуществить. Второе - поддержка всех форматов TGraphic - TBitmap, TIcon, TMetafile. Специально для разработчиков игр предоставлена процедура UpdatePalette. Её можно использовать для вывода различных расс юнитов в играх-стратегиях. Т.е. Вы храните один ресурсовый файл и множество палитр для разных расс, при выводе спрайта на экран меняется только палитра, это позволяет сохранить огромный объем памяти. Так же эта процедура понадобится для таких эффектов как пламя и дым. Но всегда помните операции с палитрой имеют смысл при изображении с количеством цветов менее 256. Если Вы считаете что 256 цветов не достаточно, то это глубокое заблуждение - такие игры как Diablo, StarCraft и т.д. содержат по 20-40 цветов на набор спрайтов ! Обратите внимание на процедуры Blur и Mirror, их так же можно использовать для спецэффектов.

TUltraDIB

Компонент состоит из следующих модулей:

DIBultra.pas Version 1.3 1999 LEON Sebastien
DIBFX.pas Version 1.3 1999 LEON Sebastien
DIBType.pas Version 1.3 1999 LEON Sebastien
DIBCodec.pas Version 1.3 1999 LEON Sebastien

Класс TDIBUltra является наследником TObject и располагается в модуле DIBultra.pas.

constructor CreateFromStream (AStream : TStream);
constructor CreateFromResourceName(Instance : THandle ; const ResName: string);
constructor CreateFromResourceID (Instance : THandle ; ResID: Integer);
constructor CreateFromFile (const Filename: string);
constructor Create (Width, Height : Word ; PF : TDUPixelFormat ; pLogPalette : Pointer );

procedure BufferToUpdate;
procedure BufferDim (Width, Height : Word);
function BufferOf (AOwner : TObject) : Boolean;
procedure AlphaChanelBlit (Dest : TDIBUltra; x, y, Num : integer);
procedure AlphaBlit (Dest : TDIBUltra; x, y, Dens : integer);
procedure SetAlphaFile( Const MaskFile : String ; Num , Delay : Integer);
procedure SetAlphaMask( Mask : TDIBUltra ; Num , Delay : Integer);
procedure NoAlpha;
procedure MakeTransparent(ColorIndex : Byte);
procedure MakeOpaque;
procedure DrawOn (Dest : TRect ; Canevas : TCanvas ; Xsrc, Ysrc : Integer );
procedure TiledOn (Dest : TRect ; Canevas : TCanvas);
procedure StretchOn (Dest : TRect ; Canevas : TCanvas);
procedure ClearAll;
procedure ClearClipRect;
procedure PrepareStyle;
procedure RotateStyle (n : Byte);
procedure FillRect (R : TRect);
procedure MoveTo (x1,y1 : Integer);
procedure LineTo (x2,y2 : Integer);
procedure StepTo (dx,dy : Integer);
procedure Plot (Nx,Ny : Integer);
procedure SetPalette (pLogPalette : Pointer);
function StdIndex (Cl : TDUColor) : TColorIndex;
procedure SaveToFile (const Filename: string ; SavingMode : TSaveMode ; FinalBpp : TDUPixelFormat);
procedure SaveToStream(AStream : TStream ; SavingMode : TSaveMode ; FinalBpp : TDUPixelFormat);

procedure DirectPlot (Nx, Ny : Integer; ColIdx : TColor );
procedure DirectLineTo(Sg : TLine);
property Pixels [X,Y: Integer]: TColor read GetPixel write SetPixel;
property PixelsIndex[X,Y: Integer]: TColorIndex read GetPixelIndex write SetPixelIndex;
property BrushColor : TColor read ColorBrh Write SetBrhColor default ClBlack;
property PenColor : TColor read ColorPen Write SetPenColor default ClWhite;
property BrushColorIndex : TColorIndex read GetBrushColorIndex Write SetBrushColorIndex default 0;
property PenColorIndex : TColorIndex read GetPenColorIndex Write SetPenColorIndex;
property PenWidth : LongInt read WidthPen Write SetWidthPen default 1;
property PenStyle : LongInt read Mask Write SetMask default DUpsSolid;
property ClipRect : TRect read ClpRect Write SetClipRect;
property GDIStyle : Boolean read NotLast Write NotLast default False;
property LZHFormat : Boolean read RLZH Write WLZH;
property ScanLine[R:Integer]:Pointer read GetScanLine;
property Bits : Pointer read DIBBits; property PixelFormat: TDUPF read DIBResol;
property Canvas : TCanvas read Cnv;
property Width : Integer read DIBWidth;
property Height : Integer read DIBHeight;
property Size : Integer read DIBSize;
property Status : TDIBType read DIBStatus;
property Header : Pointer read PDIBheader;
property Handle : THandle read DIBHandle;
property Hpalette : hPalette read DIBHPalette;
property Bpp : Integer read DIBBpp;
property ByteWidth : Integer read DIBWidth_b;
Тестирование

Расскажу как проводилось тестирование. Тестирование таких программных продуктов, как компоненты, проводилось мною в первые. Методик тестирование так же не было ( а у Вас они есть ? ). Все приходилось придумывать на ходу. По этой простой причине нельзя со 100% уверенностью верить результатам этих тестов, но сравнительную оценку провести можно.

Итак, тесты проводились на одном и том же компьютере :) следующей конфигурации : Celeron 366, 96 Мб, Intel 740 8Мб, Винчестер 2 Мб 7200 оборотов.

Первый тест, который был мной разработан - скорость загрузки BMP файла в память. У всех рассматриваемых компонентов был метод LoadFormFile, по этому осуществить это не составляло особого труда. После загрузки файла, таймер останавливался и проверялось наличие загруженного изображения в компоненте. Как это проверить проще всего - вывести его на экран.

Для теста я подготовил четыре изображения:

1000 x 1000 x 24 bit
3000 x 3000 x 24 bit
4000 x 4000 x 8 bit
4000 x 4000 x 24 bit

Размер самого большого файла составлял 48 мегабайт, в тестируемой системе оставалось свободным ~60-70 Мб, что отменяло проблему свопинга. После каждого измерения проводилась дефрагментация памяти для удаления изображения из памяти и своп файла.

Программно тест выглядит совсем просто:

procedure TForm1.LoadTest(Sender: TObject);
var
  Bitmap:TBitmap;
  X:integer;
  S:String;
begin
  Bitmap:=TBitmap.Create;
  Case RadioGroup.ItemIndex of // в зависимости от выбранного индекса
    0: S:='..\1000.bmp';       // загружаем нужный файл
    1: S:='..\3000.bmp';
    2: S:='..\4000.bmp';
    3: S:='..\4000hi.bmp';
  end;
  X:=GetTickCount;            // включаем таймер
  Bitmap.LoadFromFile(S);
  X:=GetTickCount-X;
  MessageDlg('Time : '+IntToStr(X)+' ms',mtInformation,[mbOK],0);
  Image1.Picture.Assign(Bitmap); // проверяем есть ли изображение
  Bitmap.Free;
end;

Что нам может показать этот тест?

Во первых возможность компонента обрабатывать большие изображения. Компонент TDibUltra несколько раз вылетал с ошибкой, при попытке загрузки файла 4000 x 4000 x 24 bit. Все остальные компоненты справились с тестом без ошибок.

Второе. Некоторые компоненты применяют собственные методы загрузки. Но в принципе, использование стандартных API функции для загрузки BMP файлов более выгодно, нежели огород из собственного кода. Вот как выглядят результаты теста:

Следующий тест касался быстродействия обращения к отдельным элементам изображения - метод Pixels. Тест проводился следующим образом - создавалось изображение 1000 x 1000 x 24 bit и последовательно закрашивалось пикселями определенного цвета. Сначала я хотел заполнять каждый пиксель случайным цветом, но полученный разлет результатов просто ошеломлял 10-20 ms. Это связано со спецификой получения "случайного" числа. Дело в том, что случайное число получается не просто опросом процессора, этой операции предшествует некоторые специфические циклы ( на уровне железа ), повторяются они не всегда одинаковое число раз.

Программно тест реализуется примерно следующим образом:

var
Bitmap:TDibUltra;
I,J,X:integer;

... X:=GetTickCount;
for I:=0 to 1000 do
  for J:=0 to 1000 do
    Bitmap.Pixels[i,j]:=clRed;
X:=GetTickCount-X;
MessageDlg ('Time : '+IntToStr(X)+' ms',mtInformation,[mbOK],0);
Bitmap.DrawOn(Rect(0,0,300,300),Canvas,0,0); // проверка заполнения

Теперь по поводу результатов. Лидеры тестов TFastDIB и TUniDib. Данный тест не прошел только TBitmap, об этом более подробно.

Все дело в том, что у TBitmap нет свойства Pixels. В тесте я сделал обращение через TBitmap.Canvas.Pixels[x,y]. Вы должны понимать, что так поступать нельзя ( смотрите полученные результаты ) - это то же самое, что забивать скрипкой Страдивари гвозди в стену. Напомню, что для быстрой работы с TBitmap, существует свойство ScanLine. Если использовать его, то получатся результаты близкие к показателям других тестированных компонентов.

Следующий тест касается быстроты вывода изображения, точнее его участка. Для проведения этого теста я загружал в тестируемый компонент BMP файл размером 1000 x 1000 x 24 bit и на Canvas формы выводил изображение размером 400 x 400 пикселей. Не все компоненты имеют свойство Draw или что то подобное, по этому в некоторых случаях приходилось использовать стандартную API функцию BITBLT. В таблице такие результаты помечены звездочкой *.

Результаты тестов. Два безусловных лидера TFastDIB и TUniDib.

Вот все результаты тестов в табличном виде:

Выводы

Хорошо знакомый TBitmap, показал очень хорошие результаты - и скорость загрузки и скорость вывода. Единственный его минус - обращение к отдельным пикселам. Но написав некоторое количество кода можно обойти это затруднение использовав свойство - ScanLine.

Теперь перейдем к TDIB. Этот компонент входит в комплект DelphiX и его основное предназначение хранение графики для последующего копирования на поверхности DirectX. Как показывают результаты, он с этим успешно справляется,да и для больших изображений скорость загрузки выше чем у других компонентов.

TUniDib находится где то по серединке. Его единственное преимущество высокая скорость отрисовки и поддержка формата PCX.

Безусловный фаворит - TFastDIB. Практически во всех тестах он опережал своих "собратьев". К тому же, если учитывать, что в комплект с самим компонентом добавлен модуль со всевозможными эффектами TFastDIB безусловный лидер.

По результатам тестов Вы можете подумать "Все стираю все другие компоненты и перехожу на использование TFastDIB". Это будет не правильно.

Всегда будет чего то не хватать в уже существующем классе или компоненте, и выход один - дописывать компонент под свои нужды. У всех рассмотренных мной компонентов, код открыт, так что Вы можете с легкостью взять что то у одного, что то у другого. Переписывая код, всегда придерживайтесь следующих правил. Если Ваш компонент будет очень сильно изменен - создавайте свой. Если необходимо добавить, или изменить всего пару свойств ( процедур, функций ) используйте наследование ( к примеру TMyClass = class (TFastDIB) ); Так же можно дописать код уже существующего компонента, добавив свои процедуры или свойства. Нельзя менять код самого компонетна, тогда будет нарушена совместимость.

Список ссылок
Адрес автора
Официальный сайт распространитель TFastDIB
Скачать TFastDIB
Официальный сайт распространитель DelphiX ( DXDIB )
Скачать DelphiX
Скачать TUniDIB
Официальный сайт распространитель TDIBUltra
Скачать TDIBUltra
Титульная страница DelphiGFX Сделать закладку Написать письмо автору сервера
Hosted by uCoz