Прототип к варианту 20 - Работа с DIB-секциями
DIBSect — демонстрация работы с DIB-секциями
Простая программа DIBSect демонстрирует применение DIB-секций — объектов GDI, по своему внутреннему формату аналогичных аппаратно-независимым растрам.
На рис. 9.14 показано рабочее окно программы DIBSect (хотя черно-белый рисунок заметно снижает впечатление).
Использование DIBSect
В окне программы DIBSect находится одно графическое поле. При нажатии кнопки Randomize программа раскрашивает отдельные пикселы DIB-секции в случайные цвета, для этого она напрямую обращается к памяти DIB. Затем функция BitBIt переносит изображение в графическое поле. Кнопка DrawRect рисует прямоугольник в совместимом контексте устройства, в котором выбран растр DIB-секции; она демонстрирует возможность вызова графических функций GDI для DIB-секций. Кнопки Strip Red, Strip Green и Strip Blue выполняют простейшую обработку изображения, удаляя из него соответственно красную, зеленую и синюю цветовые составляющие. Эта задача без особых хлопот (и с лучшим быстродействием) решается применением растровых операций; тем не менее она демонстрирует тот факт, что прямой доступ к памяти растра обеспечивает чрезвычайно гибкие возможности его обработки.
Описание проекта
Программа DIBSect содержит всего одну форму, приведенную в листинге 9.8. Кроме того, в программе используется файл APIGID32.DLL — файл объявлений для библиотеки динамической компоновки, прилагаемой к книге.
Листинг 9.8. DIBSECT.FRM
На первый взгляд создание DIB-секции происходит практически так же, как создание любого аппаратно-независимого растра. Сначала вы инициализируете структуру BITMAPINFOHEADER, для этого необходимо рассчитать общий размер растра. Хотя каждый пиксел изображения (с 24-разрядным цветом) кодируется 3 байтами, недостаточно умножить ширину на высоту, а потом умножить результат на три. В этих простых вычислениях не учитывается необходимость выравнивания каждой строки развертки по 32-разрядной границе. Вместо этого необходимо подсчитать количество байт в каждой строке развертки и умножить результат на восемь (количество строк развертки). Эта операция выполняется функцией ScanAlign. Количество бит на пиксел (или пикселов на байт) зависит от формата растра. Ниже в программе приведены формулы для других форматов DIB. Количество байт в строке развертки сохраняется в переменной
BytesPerScanLine для последующего использования.
Высоте DIB присваивается отрицательное число, в результате чего начало координат DIB (точка 0,0) устанавливается в левом верхнем углу изображения.
Инициализированная структура BITMAPINFO передается в качестве параметра функции Create-DIBSection. В нашем примере инициализировать цветовую таблицу не нужно — это одно из преимуществ использования 24-разрядного цвета. Как показано ниже, функция CreateDIBSection выделяет в памяти буфер для хранения растра и сохраняет его адрес в переменной addr. Кстати говоря, перед вами хороший пример того, как важно хорошо разбираться в объявлениях функций API. В объявлении этой функции из исходного файла WIN32API .ТХТ, входящего в Visual Basic, указано, что адрес передается по значению. Функция сделает все, что положено, и вернет правильный манипулятор растра, но, поскольку параметр передавался по значению, значение переменной addr так и не будет присвоено — функция спокойно загрузит адрес во временную копию переменной addr, созданную при передаче параметра. Обнаружить подобные ошибки бывает очень сложно, поскольку функция (вполне законно) возвращает признак успешного завершения. Это одна из причин, по которой я настоятельно рекомендую использовать файл API32.TXT, прилагаемый к книге, вместо WIN32API .ТХТ; при подготовке книги в него были внесены сотни изменений и исправлений.
Ниже продемонстрирован один из простых способов выравнивания по 32-разрядной границе. Два младших бита сбрасываются операцией AND (в сущности, определение выравнивания по 32-разрядной границе эквивалентно тому, чтобы два младших бита адреса были равны нулю). Не забудьте сначала прибавить 3, чтобы округление осуществлялось вверх.
Функция cmdWhiteRect показывает, как легко выполняются стандартные графические команды в контекстах устройства с выбранными DIB-секциями.
Функция SetSectionPixel показывает, как вычислить позицию любого пиксела в области данных. Обратите внимание на тонкости использования функции agCopyData. Поскольку адрес вычисляется на месте, он передается по значению. Однако параметр color необходимо передавать по ссылке, потому что содержимое переменной должно быть скопировано по заданному адресу.
Вычисляет смещение пиксела в DIB-секции и присваивает ему заданный цвет
В функции StripColor используется тот же прием, который был продемонстрирована в функции SetSectionPixel; однако стоит обратить внимание на простейшую ручную оптимизацию, ускоряющую работу программы. Все вычисления по возможности выносятся из цикла.
На этот раз проблема относится не столько к использованию Win32 API, сколько к программированию вообще. Самое простое и очевидное решение заключается в том, чтобы воспользоваться двойным вложенным циклом и вызывать в нем функцию SetSectionPixel. Хороший оптимизирующий компилятор (такой, как Visual C++) вынесет этот код за пределы цикла и существенно повысит быстродействие программы, хотя результат может оказаться менее эффективным, чем показанный ниже алгоритм. Конечно, на С или C++ этот алгоритм будет работать быстрее, чем в Visual Basic, но именно в таких процедурах достигается наибольшее преимущество от режима компиляции в машинный (native) код Visual Basic 5.0. Важно подчеркнуть, что выигрыш от рационально построенного алгоритма, как в данном случае, превышает дополнительный выигрыш, достигнутый при переходе от Р-кода к машинному коду. Другими словами, лучшим путем к повышению быстродействия программ Visual Basic является написание хорошего кода Visual Basic — компиляция находится на BTODOM месте.
Рекомендации для самостоятельной работы
Знакомство с примерами этой главы подходит к концу. Я настоятельно рекомендую рассмотреть другие приложения на прилагаемом компакт-диске. Кроме того, попробуйте сделать следующее:
-усовершенствуйте программу DIBSection так, чтобы она также работала с 16-цветными и 256-цветными растрами;
-измените программу Shade так, чтобы она восстанавливала исходный внешний вид экрана (пока для этого приходится перетаскивать форму по экрану, «стирая» эффект затенения);
-напишите программут которая при щелчке на имени файла выводит список всех связанных с ним значков;
-напишите программу, которая выводит сведения о файле .BMP, не загружая его.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.