DIB-секция может храниться в любой области памяти, ее размер ограничивается только размером доступной приложению памяти, функции GDI для рисования на таком изображении используют чисто программные алгоритмы, никак не задействуя аппаратный ускоритель. DIB-секция поддерживает различную цветовую глубину и прямой доступ к области памяти, в которой хранится изображение. DIB-секция переносима с одного устройства на другое. BMP-файлы хранят изображение как DIB.
Скорость работы с изображением в формате DIB-секции зависит только от производительности процессора, памяти и качества реализации графических алгоритмов системой (а они, надо сказать, реализованы в Windows очень неплохо). Скорость работы с изображением в формате DDB зависит еще и от драйвера и аппаратного ускорителя видеокарты. Во-первых, аппаратный ускоритель и драйвер могут поддерживать или не поддерживать рисование
графических примитивов (в последнем случае эти примитивы рисует система: то, какие операции поддерживает драйвер, можно узнать с помощью функции
GetDeviceCaps
). До недавнего времени была характерной ситуация, когда рисование картинки на DDB-растре и вывод такого растра на экран были заметно (иногда — в два-три раза) быстрее, чем аналогичные операции с DIB-секцией. Однако сейчас разница стала существенно меньше, производительность системы в целом выросла сильнее, чем производительность двумерных аппаратных ускорителей (видимо, разработчики видеокарт больше не считают двумерную графику узким местом и поэтому сосредоточили свои усилия на развитии аппаратных ускорителей 3D-графики). На некоторых мощных компьютерах можно даже столкнуться с ситуацией, когда DDB-изображение отстает по скорости от DIB.
Класс
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-изображениями.
1.1.12. ANSI и Unicode
Windows поддерживает две кодировки: ANSI и Unicode. В кодировке ANSI (American National Standard Institute) каждый символ кодируется однобайтным кодом. Коды от 0 до 127 совпадают с кодами ASCII, коды от 128 до 255 могут означать разные символы различных языков в зависимости от выбранной кодовой страницы. Кодовые страницы позволяют уместить многочисленные символы различных языков в однобайтный код, но при этом можно работать только с одной кодовой страницей, т.е. с одним языком. Неверно выбранная кодовая страница приводит к появлению непонятных символов (в Интернете их обычно называют "кракозябрами") вместо осмысленного текста.
В кодировке Unicode используется 2 байта на символ, что даёт возможность закодировать 65 536 символов. Этого хватает для символов латиницы и кириллицы, греческого алфавита, китайских иероглифов, арабских и еврейских букв, а также многочисленных дополнительных (финансовых, математических и т. п.) символов. Кодовых страниц в Unicode нет.
Примечание
Кодовая страница русского языка в ANSI имеет номер 1251. Кодировка символов в ней отличается от принятой в DOS так называемой альтернативной кодировки. В целях совместимости для DOS-программ, а также для консольных приложений Windows использует альтернативную кодировку. Именно поэтому при выводе русского текста в консольных приложениях получаются те самые "кракозябры". Чтобы избежать этого, следует перекодировать символы из кодировки ANSI в DOS при выводе, и наоборот — при вводе. Это можно сделать с помощью функций
CharToOem
и
OemToChar
.
Windows NT/2000/XP поддерживает ANSI и Unicode в полном объеме. Это значит, что любая функция, работающая со строками, представлена в двух вариантах: для ANSI и для Unicode. Windows 9x/МЕ в полном объеме поддерживает только ANSI. Unicode-варианты в этих системах есть у относительно небольшого числа функций. Каждая страница MSDN, посвященная функции, работающей со строками (или со структурами, содержащими строки), в нижней части содержит надпись, показывающую, реализован ли Unicode-вариант этой функции только для NT/2000/XP или для всех платформ.
Примечание
В качестве примера рассмотрим функции вывода текста на экран. Unicode-версию на всех платформах имеют только две из них
TextOut
и
ExtTextOut
. Функции
DrawText
и
DrawTextEx
имеют Unicode-варианты только в Windows NT/2000/XP. Если же смотреть функции для работы с окнами, то среди них нет ни одной, которая имела бы Unicode-вариант в Windows 9х/МЕ. Следует отметить, что с относительно недавнего времени Microsoft предоставляет расширение для Windows 9x/МЕ которое позволяет добавить полную поддержку Unicode в эти системы. Это расширение называется MSLU (Microsoft Layer for Unicode), его можно скачать с официального сайта Microsoft.