Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual1.doc
Скачиваний:
8
Добавлен:
07.03.2016
Размер:
4.35 Mб
Скачать

5.13. Запис на диск та зчитування з диску графічних об'єктів

Приклад знаходиться у папці DISK\GDI\GDI11.

Для запису графічних об'єктів на диск використаємо програму розроблену у п. 5.3, де відбувалося малювання графічних об’єктів.

У пункті 5.9. було розглянуто виведення та формування бітових зображень у формі прямокутників. Метою даної програми є малювання графічних об’єктів у вікні з подальшим збереженням їх на диск у форматі *.bmp. Як зазначалося раніше, для виведення бітових зображень необхідно мати два контексти: контекст для малювання pDC та контекст пам’яті memDC. Так, зображення можна виводити з одного контексту в інший і навпаки.

Для формування та зберігання бітового зображення нам буде потрібен об'єкт m_Bit класу CBitmap. Для виведення графіки оголосимо змінну kod_graf типу int. Додамо їх у клас вікна виду:

class CGrafView : public CView

{

.............................................................

CBitmap m_Bit;

int kod_graf;

.............................................................

};

У меню даної програми «Графика» можна вибрати три опції: «Фигуры»; «Фигуры 2»; «Сохранение картинки на диск». При виборі опції меню «Фигуры» відбувається формування бітового зображення m_Bit та виведення його на екран дисплею. При виборі опції «Фигуры 2» відбувається просте виведення на екран бітового зображення m_Bit, яке було сформовано у опції меню «Фигуры». При спрацюванні першої або другої опції меню змінній kod_graf привласнюється відповідне значення – 1 або 2. При чому значення 2 може бути привласнено, коли бітове зображення вже сформоване, тобто після натиснення першої опції меню (при kod_graf дорівнює 1).

Наведемо відповідні функції відгуків.

void CGrafView::OnFigures()

{

if(kod_graf!=1)

{

kod_graf = 1;

Invalidate();

}

}

void CGrafView::OnFigures2()

{

if(kod_graf==1)

{

kod_graf = 2;

Invalidate();

}

}

Дані функції викликають функцію OnDraw() (за допомогою Invalidate()), де і відбувається формування та виведення бітового зображення.

Наведемо текст функції OnDraw().

void CGrafView::OnDraw(CDC* pDC)

{

CGrafDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

CPen pen;

CPen* pen_st;

CBrush br;

CBrush* br_st;

CBitmap* old_bit;

CRect rect,rr;

GetClientRect(&rect);

rr = rect;

CDC memDC;

//Малювання фігур

if(kod_graf==1)

{

//Організувати виведення з memDC

//Створення memDC

memDC.CreateCompatibleDC(pDC);

m_Bit.DeleteObject();

m_Bit.CreateCompatibleBitmap(pDC,rr.Width(),rr.Height());

old_bit = memDC.SelectObject(&m_Bit);

//Малювання в memDC

pen.CreatePen(PS_SOLID,1,RGB(255,0,0));

pen_st = memDC.SelectObject(&pen);

br.CreateSolidBrush(RGB(255,0,0));

br_st = memDC.SelectObject(&br);

rect.InflateRect(-rect.right/8,-rect.bottom/8);

memDC.Rectangle(&rect);

br.DeleteObject();

br.CreateSolidBrush(RGB(0,255,0));

memDC.SelectObject(&br);

rect.InflateRect(-rect.right/8,-rect.bottom/8);

memDC.Rectangle(&rect);

br.DeleteObject();

br.CreateSolidBrush(RGB(0,0,255));

memDC.SelectObject(&br);

rect.InflateRect(-rect.right/8,-rect.bottom/8);

memDC.Ellipse(&rect);

memDC.SelectObject(pen_st);

memDC.SelectObject(br_st);

//Малювання картинки з пам’яті

pDC->BitBlt(0, 0, rr.Width(), rr.Height(), &memDC, 0,

0, SRCCOPY);

memDC.SelectObject(old_bit);

}

//Виведення картинки m_Bit на екран

if(kod_graf==2)

{

memDC.CreateCompatibleDC(pDC);

old_bit = memDC.SelectObject(&m_Bit);

//Малювання картинки з пам’яті

pDC->BitBlt(0, 0, rr.Width(), rr.Height(), &memDC,

0, 0, SRCCOPY);

memDC.SelectObject(old_bit);

}

}

Розглянемо цю функцію більш детально. При спрацюванні опції меню «Фигуры» (kod_graf дорівнює 1) відбувається формування зображення у об’єкт m_Bit класу CBitmap.

На початку створюємо контекст пам’яті memDC за допомогою використання функції CreateCompatibleDC. Потім за допомогою функції CreateCompatibleBitmap відбувається створення об’єкту m_Bit з встановленими розмірами клієнтського вікна. При створенні початковий бітовий образ заповнений нулями, тобто кожний піксель зображення має чорний колір. Після цього треба зв’язати контекст пам’яті memDC з бітовим зображенням mBit, використовуючи наступний рядок коду:

old_bit = memDC.SelectObject(&m_Bit);

Далі відбувається виведення графічних об’єктів до контексту memDC та формується бітовий образ у об’єкті m_Bit.

Після формування бітового образу, використовуючи функцію BitBlt() він виводиться на екран дисплею. При цьому, та область де не мало місце малювання буде замальована чорним кольором, так як область бітового зображення при його створенні за умовчанням заповнюється нулями.

Результат роботи програми при натисненні опції меню «Фигуры» наведено на рис. 5.29.

При спрацюванні опції меню «Фигуры 2» відбувається виведення на екран сформованого бітового зображення. Відмінністю є те, що при зміні розмірів вікна у цій опції, зображення залишиться без змін, як продемонстровано на рис.5.30.

Рис.5.29. Результат формування та виведення бітового зображення («Фигуры»)

Рис.5.30. Результат виведення бітового зображення («Фигуры 2»)

Після формування та виведення зображення його можна зберегти на диск за допомогою опції меню «Сохранение картинки на диск», якій додамо функцію відгуку OnSavebmp, у якій напишемо наступний код.

void CGrafView::OnSavebmp()

{

if(!kod_graf) return;

//Вибір файлу для зберігання

CString str;

CFileDialog SaveDialog(false, "", "1.bmp",

OFN_PATHMUSTEXIST|OFN_NOCHANGEDIR|

OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,

"Bitmap (*.bmp)|*.bmp|");

if(SaveDialog.DoModal()!=IDOK) return;

str = SaveDialog.GetPathName();

//---------Зберігання картинки на диск---------

BITMAP bm;

BITMAPINFO bb;

BITMAPFILEHEADER bm_hed0;

BITMAPINFOHEADER bm_hed1;

int sizeB;

unsigned char *data1;

memset(&bm_hed1,0,sizeof(bm_hed1));

memset(&bb,0,sizeof(bb));

m_Bit.GetBitmap(&bm);

//Заповнення структури шапки BITMAPFILEHEADER

sizeB = (bm.bmWidth+1)*(bm.bmHeight+1);

bm_hed0.bfType = 'MB';

bm_hed0.bfSize = 3*sizeB+

sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);

bm_hed0.bfReserved1 = 0;

bm_hed0.bfReserved2 = 0;

bm_hed0.bfOffBits = sizeof(BITMAPFILEHEADER)

+sizeof(BITMAPINFOHEADER);

//Заповнення структури шапки BITMAPINFOHEADER

bm_hed1.biSize = sizeof(BITMAPINFOHEADER);

bm_hed1.biBitCount = 24;

bm_hed1.biWidth = bm.bmWidth;

bm_hed1.biHeight = bm.bmHeight;

bm_hed1.biPlanes = 1;

bm_hed1.biCompression = BI_RGB;

//Рядок заповнення для структури BITMAPINFO

bb.bmiHeader = bm_hed1;

data1 = new unsigned char[3*sizeB];

GetDIBits(GetDC()->m_hDC,(HBITMAP)m_Bit.m_hObject,

0,bm.bmHeight,data1,&bb,DIB_RGB_COLORS);

//Запис на диск двох структур та масиву пікселів

fstream pp;

pp.open(str,ios::out|ios::binary);

pp.write((char*)&bm_hed0,sizeof(bm_hed0));

pp.write((char*)&bm_hed1,sizeof(bm_hed1));

pp.write((char*)data1,3*sizeB);

pp.close();

delete []data1;

}

На початку функції ми перевіряємо чи вибрав користувач який небудь із режимів малювання, якщо ні – то виходимо з функції. Далі йде виклик стандартного діалога CFileDialog для вибору файла. При створенні вікна діалогу ми використали наступні константи:

OFN_NOCHANGEDIR – встановлення флагу, який при виборі користувачем іншої папки не змінює початкову директорію у структурі діалогового вікна. При повторних запусках вікна діалогу він завжди буде відкриватись із початкової папки і не буде змінювати її на останню вибрану користувачем.

OFN_OVERWRITEPROMPT – флаг який видає попередження коли при зберіганні файлу виявиться, що файл з таким ім'ям вже існує. Користувачу буде надана можливість змінити ім'я файлу або перезаписати існуючий. Флаг працює лише на діалогах виду "Сохранить как".

Якщо користувач натисне у діалозі кнопку Отмена, тоді відбудеться вихід з функції. Шлях до введеного файлу записується у змінну str через функцію діалогу GetPathName. Далі йде підготовка інформації необхідної для збереження файлу *.bmp. Коротко розглянемо структуру цих файлів. Вони (файли *.bmp) складаються з таких частин:

  • структура BITMAPFILEHEADER

  • структура BITMAPINFOHEADER

  • палітра (у зображеннях з 24-бітними кольорами не використовується)

  • данні зображення

Отже вводимо структури bm_hed0 і bm_hed1. Обнуляємо структуру bm_hed1 функцією memset. Далі відбувається заповнення цих структур. Структура bm_hed0 містить наступні параметри:

typedef struct tagBITMAPFILEHEADER

{ // bmfh

WORD bfType;

DWORD bfSize;

WORD bfReserved1;

WORD bfReserved2;

DWORD bfOffBits;

} BITMAPFILEHEADER

У параметрі bfType повинні бути символи "BM" скорочення від слів "Bit Map". Всі файли формату *.bmp повинні містити ці символи. У коді функції ми пишемо bm_hed0.bfType = 'MB'; тому, що числові дані задаються у зворотньому порядку. Тобто символ B буде першим а M другим у файлі.

У параметрі bfSize повинен міститись розмір файлу *.bmp. У змінній sizeB ми обчислили кількість пікселів у зображенні. Повний розмір файлу буде дорівнювати сумі sizeB помноженому на 3 та розміру структур BITMAPFILEHEADER і BITMAPINFOHEADER. Кількість пікселів множимо на 3 тому, що зображення будемо зберігати у 24-бітному виді по 8 біт на червоний, зелений та синій кольори.

У параметри bfReserved1 і bfReserved2 ставимо 0, вони зарезервовані для використання у системних функціях. По аналогії з класами можна сказати що вони були б захищеними членами класу. Але у структурах захищених змінних не передбачено тому при використанні структури ми не повинні змінювати їх значення.

У змінну bfOffBits повинно бути записано зміщення початку даних зображення відносно початку файла. У даному випадку це зміщення дорівнює розміру структур BITMAPFILEHEADER та BITMAPINFOHEADER. Якби ми використовували палітру то нам довелося б сюди додавати також і її розмір.

Структура bm_hed1 містить наступні параметри:

typedef struct tagBITMAPINFOHEADER

{ // bmih

DWORD biSize;

LONG biWidth;

LONG biHeight;

WORD biPlanes;

WORD biBitCount;

DWORD biCompression;

DWORD biSizeImage;

LONG biXPelsPerMeter;

LONG biYPelsPerMeter;

DWORD biClrUsed;

DWORD biClrImportant;

} BITMAPINFOHEADER;

Опис параметрів структури:

biSize містить розмір структури в байтах.

biWidth і biHeight містять ширину і висоту бітового образу.

biPlanes містить кількість зображень у пристрої. Повинно бути рівним 1.

biBitCount кількість біт у одному пікселі зображення.

biCompression визначає метод стиснення (компресії) зображення, може приймати значення наведені у табл. 5.6:

Таблиця 5.6

Види компресії зображень у файлах *.bmp

Значення

Ідентифікатор

Компресія

0

BI_RGB

не стиснуте зображення

1

BI_RLE8

стиснення RLE для 8-бітних зображень

2

BI_RLE4

стиснення RLE для 4-бітних зображень

3

BI_BITFIELDS

зображення не стиснуто, палітра містить три 4-байтних маски для червоного, зеленого і синього компонентів кольора. Використовується для 16- и 32-бітних зображень

4

BI_JPEG

Win98/Me/2000/XP: JPEG - стиснення

5

BI_PNG

Win98/Me/2000/XP: PNG - стиснення

6

BI_ALPHABITFIELDS

WinCE: зображення не стиснено, палітра містить чотири 4-байтні маски для червоного, зеленого, синього і прозорого (альфа-канал) компонентів кольора. Використовується для 16- и 32-бітних зображень

При зберіганні файлу нам потрібно буде створити масив з бітами зображення. Зображення міститься у контексті екрану. Для того щоб отримати біти зображення із контексту екрану у потрібний нам масив використаємо функцію GetDIBits:

int GetDIBits(

HDC hdc, // дескриптор DC

HBITMAP hbmp, // дескриптор рисунка

UINT uStartScan, // перший встановлюваний рядок розгортки

UINT cScanLines, // число копіюємих рядків розгортки

LPVOID lpvBits, // масив для бітів рисунка

LPBITMAPINFO lpbi, // буфер даних рисунка

UINT uUsage // індекси RGB або палітри

);

У параметрі lpvBits передаємо створений нами масив data1.

Збереження файлу робимо через об’єкт pp класу fstream. Його функціями: open, write та close ми відкриваємо файл для запису, пишемо структури та закриваємо файл. У разі використання класу CFile для збереження файлів код може мати наступний вид:

CFile pp;

pp.Open(str,CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);

pp.Write((char*)&bm_hed0,sizeof(bm_hed0));

pp.Write((char*)&bm_hed1,sizeof(bm_hed1));

pp.Write((char*)data1,3*sizeB);

pp.Close();

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]