Класс TBitmap
Класс TBitmap является основой растровой графики в Delphi. В первых версиях среды этот класс соответствовал битовой карте, зависимой от устройства (Device Dependent Bitmap, DDB). Этот формат хорош для деловой графики — отображения небольших картинок с малой глубиной цвета, например, на кнопках. Формат DDB появился во времена первых версий Windows, когда еще не было графических ускорителей и кое-где еще помнили о EGA. Поэтому и форматы хранения были привязаны к определенным видеорежимам.
Со временем аппаратура совершенствовалась, росло и количество поддерживаемых видеорежимов. Появились режимы High Color (15—16 бит на точку) и True Color (24 бита на точку). Все это привело к тому, что картинка стала храниться в аппаратно-независимом формате (Device Independent Bitmap, DIB), а проблемы ее быстрого отображения легли на аппаратуру и драйверы.
За формат битовой карты — DIB или DDB — отвечает свойство:
type TBitraapHandleType = (bmDIB, bmDDB);
property HandleType: TBitmapHandleType;
По умолчанию устанавливается режим bmDIB. Впрочем, можно заставить приложение, написанное на Delphi, вернуться к старому типу. Для этого нужно установить глобальную переменную DOBsOnly (модуль GRAPHICS.PAS) в значение True. Впрочем, необходимость этого сомнительна. Все новые видеокарты и драйверы к ним, а также графические интерфейсы (такие, как DirectX) оптимизированы для использования DIB.
Желаемую глубину цвета битовой карты можно узнать и переустановить, меняя значение свойства:
TPixelFormat = (pfDevice, pflbit, pf4bit, pfSbit, pflSbit, pf!6bit, pf24bit, pf32bit, pfCustom);
property PixelFormat: TPixelFormat;
Режим pfDevice соответствует битовой карте DDB. Глубина цвета в 1, 4 и 8 бит на пиксел — традиционная и предусматривает наличие у изображения палитры. Другие режимы заботятся о хранении непосредственных яркостей точек в каждом из трех основных цветов — красном (R), зеленом (G) и синем (В). Разрядность 15 бит соответствует распределению бит 5-5-5 (RGB555), 16 бит - RGB 565, 24 бит - RGB888. Режим 32 бит похож на 24-битный, но в нем дополнительно добавлен четвертый канат (альфа-канал), содержащий дополнительную информацию о прозрачности каждой точки. Режим pfCustom предназначен для реализации программистом собственных графических конструкций. В стандартном классе TBitmap установка свойства PixelFormat в режим pfCustom приведет к ошибке — поэтому использовать его нужно только в написанных вами потомках TBitmap.
Битовая карта является одним из видов ресурсов. Естественно, что класс TBitmap поддерживает загрузку из ресурсов приложения:
procedure LoadFromResourcelD(Instance: THandle; ResID: Integer);
procedure LoadFromResourceName(Instance: THandle; const ResName: string);
Здесь instance — это глобальная переменная модуля System, хранящая уникальный идентификатор запущенной копии приложения (или динамической библиотеки).
Канва битовой карты доступна через свойство:
property Canvas: TCanvas;
С ее помощью можно рисовать на поверхности растрового изображения. Обратите внимание, что никакие другие потомки TGraphic канвы не имеют.
Дескрипторы битовой карты и ее палитры доступны как свойства:
property Handle: HBITMAP;
property Palette: HPALETTE;
Имея дело с классом TBitmap, учитывайте, что принцип "один объект — один дескриптор" из-за наличия механизма кэширования неверен. Два метода:
function ReleaseHandle: HBITMAP;
function ReleasePalette: HPALETTE;
возвращают дескрипторы битовой карты и палитры соответственно, а после этого обнуляют дескрипторы, т. е. как бы "отдают" их пользователю.
При любом внешнем обращении к дескриптору битовой карты и любой попытке рисовать на ее канве разделение одной картинки несколькими объектами прерывается, и объект получает собственную копию содержимого дескриптора. Для этого есть методы:
- procedure Dormant — выгружает изображение в поток и уничтожает дескрипторы битовой карты и палитры;
- procedure Freeimage — "освобождающий" дескриптор битовой карты для дальнейшего использования и внесения изменений. Это означает, что если на данный дескриптор есть ссылки, то он дублируется; поток очищается.
property Monochrome: Boolean;
Значение True соответствует монохромной битовой карте. При его изменении происходит преобразование содержимого к требуемому виду.
За прозрачность битовой карты отвечают следующие свойства:
property TransparentColor: TColor;
type TTransparentMode = (tmAuto, tmFixed);
property TransparentMode: TTransparentMode;
Если свойство TransparentMode установлено в режим tmAuto, то за прозрачный (фоновый) принимается цвет верхнего левого пиксела. В противном случае этот цвет берется из свойства Transparentcolor.
Битовая карта может использоваться в качестве маски для других битовых карт. В этом случае она превращается в двухцветную, где в белый цвет окрашиваются точки фона (см. свойство Transparentcolor), а в черный — все остальные. Для поддержки этого режима служат следующие методы и свойства:
procedure Mask(Transparentcoior: TColor);
property MaskHandle: HBitmap;
function ReleaseMaskHandle: HBitmap;
Наконец, последним по счету будет рассмотрено очень важное свойство битовой карты TBitmap. Если формат ее хранения — DIB, то есть возможность получить доступ к данным самой битовой карты:
property ScanLine[Row: Integer]: Pointer;
Это свойство представляет собой массив указателей на строки с данными битовой карты. Параметр ROW содержит номер строки. Следует помнить, что в большинстве случаев строки в битовой карте упорядочены в памяти снизу вверх и фактически первой после заголовка хранится нижняя строка. Код, возвращающий значение свойства ScanLine, это учитывает; поэтому не удивляйтесь, если с ростом параметра ROW значение свойства уменьшается.
Внутри строки данные упорядочены в соответствии с форматом (pixelFormat). Для формата pfsbit все просто — каждый байт в строке соответствует одному пикселу. Для форматов pfisbit и pfiebit пикселу соответствуют два байта (в этих 16 битах упакованы данные о трех каналах), pf24bit — три байта (по байту на канал).
Примерно так может выглядеть обработчик события onMouseMove, выводящий на панель состояния информацию о яркости в данной точке (подразумевается, что формат битовой карты — 8 или 24 бита):
procedure TMainForm.ImagelMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
begin
if not Assigned(Imagel. Picture.Bitmap) then Exit;
with Imagel.Picture.Bitmap,
do case PixelFormat of
pfSbit: Statusbarl.SimpleText := Format('x: %d y: %d b: %d',[x, y, pByteArray(ScanLine[у])^[x] ]);
pf24bit: Statusbarl.SimpleText := Format('x: %d y: %d R: %d,G: %d, B: %d',
[x,y, pByteArray(ScanLine[y])л[3*х], pByteArray(ScanLine[у])^[ 3*x+l], pByteArray(ScanLine[у])^[ 3*х+2]]);
end;
Само значение свойства ScanLine изменить нельзя (оно доступно только для чтения). Но можно изменить данные, на которые оно указывает. Вот так можно получить негатив 24-битной картинки:
Var line : pByteArray;
For i:=0 to Imagel.Picture.Bitmap.Height — 1 do
Begin
Line := Imagel.Picture.Bitmap.ScanLine[i];
For j:=0 to Imagel.Picture.Bitmap.Width * 3 - 1 do
Line^[j] := 255 - Line^[j];
End;
Если вы хотите решать более серьезные задачи — на уровне профессиональных средств — на помощь может прийти библиотека обработки изображений фирмы Intel (Intel Image Processing Library). Этот набор инструментов позволяет разработчику включать в программы алгоритмы обработки изображений, написанные и оптимизированные специально для процессоров фирмы Intel. Библиотека является свободно распространяемой, и последняя ее версия располагается на Web-сайте фирмы. Интерфейсы к функциям библиотеки для Delphi разработаны авторами этой книги и вместе с примерами находятся на прилагаемой к книге дискете.
Примечание
В Delphi можно столкнуться с "тезкой" рассматриваемого объекта — структурой TBitmap, описанной в файле WINDOWS.PAS. Поскольку обе они относятся к одной и той же предметной области, часто возникают коллизии, приводящие к ошибкам. Напомним, чтобы отличить структуры-синонимы, следует использовать имя модуля, в котором они описаны. Поэтому если в вашей программе есть модули Windows и Graphics, то описывайте и употребляйте типы Windows.TBitmap И Graphics.TBitmap.
В состав Windows входят карточные игры (точнее, пасьянсы), которые черпают ресурсы из динамической библиотеки cards.dll. Если вы откроете эту библиотеку в редакторе ресурсов, то увидите там изображения всех пятидесяти двух карт и десятка вариантов их рубашек (оборотных сторон). Используем эту возможность для рисования карт. Так загружается битовая карта для рубашки:
var CardsDll : THandle;
BackBitmap : Graphics.TBitmap;
initialization
CardsDll := LoadLibraryEx('cards.dll',0, LOAD_LIBRARY__AS_DATAFILE) ;
BackBitmap := Graphics.TBitmap.Create;
BackBitmap.LoadFromResourcelD(CardsDll, 64) ;
finalization
BackBitmap.Free;
FreeLibrary(CardsDll);
end.
Примечание
В Windows 95/98 эта динамическая библиотека — 16-разрядная, и работать так, как описано, не будет. Используйте библиотеку Cards.dll из состава Windows NT, 2000.
Аналогичным образом можно загрузить битовые карты для всей колоды. При показе карты, в зависимости от того, открыта она или закрыта, отрисовывается один из объектов TBitmap:
if Known then // карта открыта
Canvas.StretchDraw(ClientRect, FaceBitmap)
else
Canvas.StretchDraw(ClientRect,BackBitmap)
end;