47952 (597372), страница 20

Файл №597372 47952 (Основы графического вывода) 20 страница47952 (597372) страница 202016-07-30СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 20)

а) драйвер не может осуществлять сжатие битмапа заново после каждой операции рисования,

б) необходимый для хранения битмапа объем памяти может увеличиваться в процессе рисования, так как он зависит от реально достигнутой степени сжатия, разной для разных изображений, а размер блока памяти, содержащего упакованный DIB, определяется вами и не может изменяться в процессе рисования на контексте.

DIBcекция (Win32 API)

Win32 API содержит специальную функцию CreateDIBSection, которая создает хендл DDB битмапа (HBITMAP), ассоциированный не с DDB, а с независимым от устройства битмапом. Таким образом существует возможность выполнения над DIB всех операций, типичных для DDB. Так, например, можно получить HBITMAP, соответствующий DIB и выбрать его в контекст устройства.

HBITMAP CreateDIBSection (hdc, lpbmi, nColorUse, ppvBits, hSection, dwOffset); 1

Параметр hdc задает хендл контекста устройства, информация о цветах и палитре которого используется когда параметр nColorUse равен DIB_PAL_COLORS.

Параметр lpbmi является указателем на структуру BITMAPINFO, содержащую заголовок битмапа и, при необходимости, палитру или маски (для HiColor режимов). BITMAPINFOHEADER, являющийся частью BITMAPINFO содержит информацию об организации битмапа и его размерах.

С помощью параметра nColorUse задается способ использования палитры. Значение DIB_RGB_COLORS указывает, что палитра битмапа содержит таблицу записей RGBQUAD (RGBTRIPLE), а значение DIB_PAL_COLORS указывает, что вместо палитры битмапа размещен массив целых чисел, являющихся индексами цветов в системной палитре.

Параметр ppvBits является указателем на переменную типа LPVOID. В эту переменную будет записан указатель на начало данных изображения.

Два последних параметра: hSection и dwOffset используются, если битмап содержится в проецируемом в память файле. В этом случае hSection является хендлом проецирования, возвращенном функцией CreateFileMapping, а dwOffset — смещение от начала файла до данных изображения. В описании указывается, что функция CreateDIBSection требует, что бы значение dwOffset было кратно 4 (длина строки растра в DIB всегда выравнивается на границу двойного слова). Если в проецируемом файле содержится так называемый «Packed DIB », то есть битмап без заголовка файла, то смещение до начала данных изображения само собой будет кратно 4 байтам12.

Однако в нормальных файлах битмапов заголовок файла присутствует. Он описывается структурой BITMAPFILEHEADER, которая имеет размер 14 байт. Очевидно, что 14 не кратно 4. И, как следствие, для большинства битмапов суммарный размер заголовка файла, заголовка битмапа и данных о цветах (палитры или масок) не может быть кратен 4 (!). Размер структуры BITMAPINFOHEADER равен 40. Суммарный размер обоих заголовков равен 54 и не кратен 4. Палитра, состоящая из записей RGBAUAD по 4 байта каждая, либо маски цветов — три двойных слова никак не могут выровнять конец заголовка по границе двойного слова. В тоже время, если при вызове функции CreateDIBSection задать величину dwOffset не кратную 4, то функция вернет NULL, хотя код ошибки (возвращаемый функцией GetLastError) не будет установлен. Как результат — обычные битмапы в виде файлов нельзя спроецировать в память и передать функции CreateDIBSection.

В итоге функция CreateDIBSection может легко применяться для создания нового DIB — в этом случае hSection и dwOffset следует задать равными 0. Тогда GDI сам создаст необходимое проецирование и вернет хендл битмапа. При необходимости сохранения DIB в виде файла можно с помощью функции GetObject прочитать информацию о DIB–секции:

DIBSECTION ds; // 1

int GetObject (hbmpDIBSection, sizeof (DIBSECTION), &ds);

Структура DIBSECTION содержит следующую информацию:

typedef struct _DIBSECTION {// 1

BITMAP dsBm;

BITMAPINFOHEADER dsBmih;

DWORD dsBitfields[ 3 ];

HANDLE dshSection;

DWORD dsOffset;

} DIBSECTION;

Поле dsBm содержит структуру BITMAP, описывающую секцию как DDB; В этой структуре можно прочитать поле bmBits (в примере выше это будет ds.dsBm.bmBits), которое является указателем на данные изображения DIB–секции. Этот указатель совпадает с тем, который возвращается в параметре ppvBits при вызове функции CreateDIBSection и может быть использован функциями работы с DIB.

Поле dsBmih описывает секцию как DIB; В основном значения полей этой структуры совпадают с теми, которые были указаны при создании секции. Однако, если вы не вычисляли сами размер данных изображения перед вызовом CreateDIBSection, то GDI сам вычислит нужное значение и возвратит его в поле biSizeImage (в примере выше это будет ds.dsBmih.biSizeImage).

Массив dsBitfields содержит маски цветов; они заполняются в зависимости от числа цветов и установленного режима сжатия. Подробнее о масках см. «Формат Win32 (Windows NT 3.x)», стр.58.

Поля dshSection и dsOffset повторяют значения, указанные при вызове функции CreateDIBSection. Если вы указали нулевые значения, то и эти поля также будут нулевыми, несмотря на то, что система сама создает проецирование.

При использовании структуры DIBSECTION нужно следить за тем, что бы вы не создавали DIB–секцию для битмапов в формате OS/2. Непосредственно GDI эту работу выполнит без затруднений, но при этом функция GetObject возвратит в структуре DIBSECTION не BITMAPINFOHEADER, а BITMAPCOREHEADER, другого размера и с другими полями. Если вам придется все–же работать с битмапами OS/2, то заодно придется описать и собственную структуру, аналогичную DIBSECTION; лучше всего просто превратить ее в union, содержащий вариант для Windows и для OS/2.

Если же вы собираетесь использовать CreateDIBSection для редактирования уже существующего DIB, то стоит воспользоваться одним из двух возможных способов: а) создать временное проецирование и скопировать в него битмап, пропустив заголовок файла или б) загрузить DIB обычным образом, создать пустую DIB–секцию, скопировать в нее изображение (скажем, с помощью SetDIBitsToDevice) и освободить первоначально загруженный DIB.

Внимание! Если вы вызывали CreateDIBSection с нулевыми значениями hSection и dwOffset, то при удалении созданной секции с помощью DeleteObject система сама удалит созданное проецирование (вам оно недоступно, так как GetObject возвращает также нули в полях dshSection и dsOffset). Но если вы сами создали проецирование, то вы обязаны сами его удалить.

При работе с DIB–секциями часто возникает необходимость получить палитру, используемую этой секцией. Типичный случай — сохранение DIB–секции в виде файла: если число цветов меньше или равно 256, то такая секция обязательно содержит палитру. Причем в этом случае нужна палитра не в виде структуры LOGPALETTE или массива записей PALETTENTRY, а в виде массива записей RGBQUAD. Для этого предназначена пара функций:

UINT GetDIBColorTable (hdc, uStartIndex, cEntries, lprgbColors); 1

UINT SetDIBColorTable (hdc, uStartIndex, cEntries, lprgbColors); 1

Обратите внимание — функции используют не хендл DIB–секции, а хендл совместимого контекста устройства, в который должна быть выбрана DIB–секция.

Практические примеры:

1) Создание пустой DIB–секции 1:

struct {// не ‘BITMAPINFO bmi’ - нам надо зарезервировать место под палитру

BITMAPINFOHEADER bmiHeader;

RGBQUAD bmiColors[ 256+3 ]; // в BITMAPINFO используется bmiColors[1]

} bmi;

LPVOID lpData;

HDC hdcDisplay;

HDC hdcMem;

HBITMAP hbmpDibSection;

int nFirstCol;

int nColors; // число цветов в системной палитре

PALETTEENTRY pe[ 256 ]; // системная палитра

int i;

hdcDisplay = GetWindowDC ( (HWND)0L);

// создаем DIB–секцию, для чего полностью заполняем bmi, включая маски и палитру

bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);

bmi.bmiHeader.biWidth = GetDeviceCaps (hdcDisplay, HORZRES); // пусть размер DIB

bmi.bmiHeader.biHeight = GetDeviceCaps (hdcDisplay, VERTRES); // совпадает с экраном

bmi.bmiHeader.biPlanes = 1;

bmi.bmiHeader.biBitCount =

GetDeviceCaps (hdcDisplay, BITSPIXEL) * GetDeviceCaps (hdcDisplay, PLANES);

bmi.bmiHeader.biCompression = BI_RGB;

bmi.bmiHeader.biSizeImage = 0L; // а это пусть GDI вычисляет

bmi.bmiHeader.biXPelsPerMeter =

GetDeviceCaps (hdcDisplay, HORZRES)*1000 / GetDeviceCaps (hdcDisplay, HORZSIZE);

bmi.bmiHeader.biYPelsPerMeter =

GetDeviceCaps (hdcDisplay, VERTRES)*1000 / GetDeviceCaps (hdcDisplay, VERTSIZE);

bmi.bmiHeader.biClrUsed = 0;

bmi.bmiHeader.biClrImportant = 0;

// обнулим палитру

ZeroMemory ( (LPVOID)bmi.bmiColors, sizeof (bmi.bmiColors));

// решим, будем–ли мы задавать маски цветов для режимов 16 и 32 bpp

// если задавать, то только стандартные 5–5–5, 5–6–5 или 8–8–8 и указать BI_BITFIELDS

// (даже на Windows NT 4.0 CreateDIBSection работала только со стандартными масками_

// можно и не задавать; битмапы 16 и 32 bpp можно создать и как BI_RGB

// В ДАННОМ ПРИМЕРЕ БУДЕМ ЗАДАВАТЬ РЕЖИМ BI_BITFIELDS

nFirstCol = 0;

switch (bmi.bmiHeader.biBitCount) {

case 16:

bmi.bmiColors[0].rgbGreen = 124; // red: 0x7C00

bmi.bmiColors[1].rgbGreen = 3; // green: 0x03E0

bmi.bmiColors[1].rgbBlue = 224;

bmi.bmiColors[2].rgbBlue = 31; // blue: 0x001F

bmi.bmiHeader.biCompression = BI_BITFIELDS;

nFirstCol = 3;

break;

case 32:

bmi.bmiColors[0].rgbRed = 255; // red: 0x00FF0000

bmi.bmiColors[1].rgbGreen = 255; // green: 0x0000FF00

bmi.bmiColors[2].rgbBlue = 255; // blue: 0x000000FF

bmi.bmiHeader.biCompression = BI_BITFIELDS;

nFirstCol = 3;

break;}

// проверим, нужно–ли назначать битмапу палитру?

nColors = GetDeviceCaps (hdcDisplay, SIZEPALETTE);

// для 16, 24 и 32 nColors будет равен 0

if (nColors) {

GetSystemPaletteEntries (hdcDisplay, 0, nColors, pe);

for (i =0; i < nColors; i++) {

bmi.bmiColors[ i + nFirstCol ].rgbRed = pe[i].peRed;

bmi.bmiColors[ i + nFirstCol ].rgbGreen = pe[i].peGreen;

bmi.bmiColors[ i + nFirstCol ].rgbBlue = pe[i].peBlue;}

bmi.bmiHeader.biClrUsed = nColors;}

// создаем секцию по полученному описанию

hbmpDibSection = CreateDIBSection (

hdcDisplay, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &lpData, (HANDLE)0L, 0);

// заполним секцию каким–либо изображением

if (hbmpDibSection) {

hdcMem = CreateCompatibleDC (hdcDisplay);

SelectObject (hdcMem, hbmpDibSection);

// собственно здесь и выполняется редактирование DIB–секции

BitBlt (

hdcMem, 0,0, bmi.bmiHeader.biWidth,bmi.bmiHeader.biHeight,

hdcDisplay, 0,0,

SRCCOPY);

DeleteDC (hdcMem);}

ReleaseDC ( (HWND)0L, hdcDisplay);

// hbmpDibSection оставляем для использования в дальнейшем

2) Сохранение DIB–секции в виде .bmp файла 1:

HBITMAP hbmpDibSection; // этот хендл мы получаем из предыдущего примера

BITMAPFILEHEADER bmfh; // заголовок файла битмапа

DIBSECTION ds; // информация о битмапе

HANDLE hf; // хендл файла в котором будет записан DIB

int nColors; // число цветов в палитре битмапа

RGBQUAD rgbs[ 256 ]; // палитра, заполняется если nColors != 0

HDC hdcDisplay;

HDC hdcMem;

DWORD dwWritten;

// получаем кое-какую информацию о записанном битмапе

GetObject (hbmpDibSection, sizeof (ds), &ds);

// определяем размер палитры

hdcDisplay = GetWindowDC ( (HWND)0L);

hdcMem = CreateCompatibleDC (hdcDisplay);

SelectObject (hdcMem, hbmpDibSection);

ReleaseDC ( (HWND)0L, hdcDisplay);

nColors = ds.dsBmih.biClrUsed ? ds.dsBmih.biClrUsed :

(ds.dsBmih.biBitCount <= 8 ? 1<

if (nColors) {

// палитра присутствует

nColors = GetDIBColorTable (hdcMem, 0, nColors, rgbs);

ds.dsBmih.biClrUsed = nColors;}

DeleteDC (hdcMem);

// сохраняем в файле

hf = CreateFile (

"TestDIB.bmp", GENERIC_READ, 0,0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if (hf != INVALID_HANDLE_VALUE) {

// заполняем и записываем заголовок файла

bmfh.bfType = 'MB';

bmfh.bfSize = bmfh.bfReserved1 = bmfh.bfReserved2 = 0L;

bmfh.bfOffBits =

sizeof (BITMAPFILEHEADER) +

ds.dsBmih.biSize +

(ds.dsBmih.biCompression == BI_BITFIELDS ? sizeof (ds.dsBitfields): 0) +

nColors * sizeof (RGBQUAD);

WriteFile (hf, (LPVOID)&bmfh, sizeof (bmfh), &dwWritten, (LPOVERLAPPED)0L);

// записываем полученный от GDI заголовок битмапа

WriteFile (hf, (LPVOID)&ds.dsBmih,ds.dsBmih.biSize,&dwWritten, (LPOVERLAPPED)0L);

// проверяем наличие масок цветов

if (ds.dsBmih.biCompression == BI_BITFIELDS) {

// пишем маски

WriteFile (

hf, (LPVOID) (ds.dsBitfields), sizeof (ds.dsBitfields),

&dwWritten, (LPOVERLAPPED)0L);}

Характеристики

Тип файла
Документ
Размер
4,85 Mb
Тип материала
Учебное заведение
Неизвестно

Список файлов книги

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
7027
Авторов
на СтудИзбе
260
Средний доход
с одного платного файла
Обучение Подробнее