Выбрать главу

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

Со свойством PixelFormat тесно связано свойство HandleType, которое может принимать значения bmDIB и bmDDB. Изменение свойства PixelFormat приводит к изменению свойства HandleType, и наоборот.

Примечание

Если вы собираетесь распечатывать изображение, содержащееся в TBitmap, то вы должны установкой свойств PixelFormat или HandleType обеспечить, чтобы изображение хранилось в формате DIB. Попытка вывести DDB-изображение на принтер приводит к непредсказуемым результатам (чаще всего просто ничего не выводится) из-за того, что драйвер принтера не понимает формат, совместимый с видеокартой.

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

Примечание

В справке сказано, что когда DDBsOnly = False, вновь создаваемые изображения по умолчанию хранятся в виде DIB-секций. На самом деле из-за ошибки в модуле Graphics (как минимум до 2007-й версии Delphi включительно) вновь созданное изображение всегда хранится как DDB независимо от значения DDBsOnly.

Класс TBitmap имеет свойство ScanLine, через которое можно получить прямой доступ к массиву пикселов, составляющих изображение. В справке написано, что это свойство можно использовать только с DIB-изображениями. Но на самом деле DDB-изображения тоже позволяют использовать это свойство, хотя и с существенными ограничениями. Если изображение хранится в DDB- формате, при обращении к ScanLine создастся его DIB-копия, и ScanLine возвращает указатель на массив этой копии. Поэтому, во-первых, ScanLine работает с DDB-изображениями очень медленно, а во-вторых, работает не с изображением, а с его копией, откуда вытекают следующие ограничения:

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

2. Каждое обращение к ScanLine создает новую копию изображения, а старая при этом уничтожается. Гарантии, что новая копия будет располагаться в той же области памяти, нет, поэтому указатель, полученный при предыдущем обращении к ScanLine, больше нельзя использовать.

3. Изменения, сделанные в массиве пикселов, затрагивают только копию изображения, но само изображение при этом не меняется. Поэтому в случае DDB свойство ScanLine дает возможность прочитать, но не изменить изображение.

Следует отметить, что TBitmap иногда создает DIB-секции, даже если свойства HandleType и PixelFormat явно указывают на использование DDB. Особенно часто это наблюдается для изображений большого размера. По всей видимости, это происходит, когда в системном пуле нет места для хранения DDB-изображения такого размера, и разработчики TBitmap решили, что в таком случае лучше создать DIB-изображение, чем не создавать никакого. Пример BitmapSpeed на прилагаемом компакт-диске позволяет сравнить скорость выполнения различных операций с DDB- и DIB-изображениями.