Антон Григор'єв - про що не пишуть в книгах по delphi - стор 22

Застосування кистей, пір'я і шрифтів в GDI принципово відрізняється від того, як це робиться в VCL. Клас TCanvas має властивості Pen. Brush. і Font. зміна властивостей яких призводить до вибору того чи іншого пера, пензля, шрифту. У GDI ці об'єкти самостійні, повинні створюватися, отримувати свій дескриптор, "вибиратися" в потрібний контекст пристрою за допомогою функції SelectObject і знищуватися після використання. Причому видаляти можна тільки ті об'єкти, які не вибрані ні в одному контексті. Є також кілька стандартних об'єктів, які не потрібно ні створювати, ні видаляти. Їх дескриптори можна отримати за допомогою функції GetStockObject. Для прикладу розглянемо фрагмент програми, яка малює на контексті з дескриптором DC дві лінії: синю і червону (лістинг 1.18). У цьому фрагменті використовується те, що функція SelectObject повертає дескриптор об'єкта, родинного обирається, який був обраний раніше. Так, при виборі нового пера вона поверне дескриптор того пера, яке було вибрано до цього.

Лістинг 1.18. Малювання різними пір'ям з використанням GDI

SelectObject (DC, CreatePen (PS_SOLID, 1, RGB (255, 0, 0)));

MoveToEx (DC, 100, 100, nil);

LineTo (DC, 200, 200);

DeleteObject (SelectObject (DC, CreatePen (PS_SOLID, 1, RGB (0, 0, 255))));

MoveToEx (DC, 200, 100, nil);

LineTo (DC, 100, 200);

Дескриптори об'єктів GDI мають сенс тільки в межах того процесу, який їх створив, передавати їх між процесами не можна. Проте зрідка можна натрапити на твердження, що така передача можлива. Джерело цієї помилки в тому. що дескриптори об'єктів GDI можна було передавати між процесами в старих, 16-розрядних версіях Windows, так що всі твердження про можливість такої передачі просто грунтуються на застарілих відомостях.

Для зберігання растрових зображень в Windows існують три формату: DDB, DIB і DIB-секція. DDB - це Device Dependent Format, формат, який визначається графічним пристроєм, на яке йде висновок. DIB - це Device Independent Bitmap, формат, єдиний для всіх пристроїв. Формат DIB - це застарілий формат, який не дозволяє використовувати графічні функції GDI для модифікації картинки, модифікувати зображення можна, лише одним способом: вручну змінюючи кольору окремих пікселів. У 32-розрядних версіях з'явився ще один формат - DIB-секція. По суті справи це той же самий DIB, але доповнений можливостями малювати на ньому за допомогою GDI-функцій. Всі відмінності між цими трьома форматами можна прочитати в чудовій книзі [1]; ми ж тут обмежимося тільки коротким їх оглядом.

DIB-секція може зберігатися в будь-якій області пам'яті, її розмір обмежується тільки розміром доступної додатком пам'яті, функції GDI для малювання на такому зображенні використовують чисто програмні алгоритми, що не задіюючи апаратний прискорювач. DIB-секція підтримує різну кольорову глибину і прямий доступ до області пам'яті, в якій зберігається зображення. DIB-секція переносимо з одного пристрою на інший. BMP-файли зберігають зображення як DIB.

Клас TBitmap може зберігати зображення як у вигляді DDB, так і у вигляді DIB- секції - це визначається значенням властивості PixelFormat. Значення pfDevice означає використання DDB, інші значення - DIB-секції з різною колірною глибиною. За замовчуванням TBitmap створює зображення з форматом pfDevice. але програміст може змінити формат в будь-який момент. При цьому створюється нове зображення необхідного формату, старе копіюється в нього і знищується.

З властивістю PixelFormat тісно пов'язане властивість HandleType. яке може набувати значень bmDIB і bmDDB. Зміна властивості PixelFormat призводить до зміни якості HandleType. і навпаки.

При завантаженні зображення з файлу, ресурсу або потоку клас TBitmap зазвичай створює зображення у форматі DIB-секції, відповідне джерела за колірною глибині. Виняток становлять стислі файли (формат BMP підтримує стиснення тільки для 16- і 256-кольорових зображень) - в цьому випадку створюється DDB. У файлі Graphics визначена глобальна змінна DDBsOnly. яка за замовчуванням дорівнює False. Якщо змінити її значення на True. завантажувати зображення завжди буде мати формат DDB.

Клас TBitmap має властивість ScanLine. через яке можна отримати прямий доступ до масиву пікселів, що становлять зображення. У довідці написано, що це властивість можна використовувати тільки з DIB-зображеннями. Але насправді DDB-зображення теж дозволяють використовувати цю властивість, хоча і з суттєвими обмеженнями. Якщо зображення зберігається в DDB- форматі, при зверненні до ScanLine створиться його DIB-копія, і ScanLine повертає покажчик на масив цієї копії. Тому, по-перше, ScanLine працює з DDB-зображеннями дуже повільно, а по-друге, працює не з зображенням, а з його копією, звідки випливають такі обмеження:

1. Копія створюється на момент звернення до ScanLine. тому зміни, зроблені на зображенні за допомогою GDI-функцій після цього, будуть недоступними.

2. Кожне звернення до ScanLine створює нову копію зображення, а стара при цьому знищується. Гарантії, що нова копія буде розташовуватися в тій же області пам'яті, немає, тому покажчик, отриманий при попередньому зверненні до ScanLine. більше не можна використовувати.

3. Зміни, зроблені в масиві пікселів, зачіпають лише копію зображення, але саме зображення при цьому не змінюється. Тому в разі DDB властивість ScanLine дає можливість прочитати, але не змінити зображення.

Схожі статті