У вас вопросы?
У нас ответы:) SamZan.net

тематики Компьютерная Графика Отчёт по лабораторной работе 2 Основы создания графических прило

Работа добавлена на сайт samzan.net: 2015-07-05

Поможем написать учебную работу

Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.

Предоплата всего

от 25%

Подписываем

договор

Выберите тип работы:

Скидка 25% при заказе до 6.4.2025

Государственное образовательное учреждение

высшего  профессионального образования

Уфимский Государственный Авиационный Технический Университет

Кафедра математики

Компьютерная Графика

Отчёт по лабораторной работе №2

Основы создания графических приложений в системе Windows

GDI+

Выполнил: студент 2 курса группы ПМИ-34,

Ибрагимов Ринат Радикович

Проверил: старший преподаватель кафедры ВВТиС,

Мухтаров Айрат Радикович


г. Уфа, УГАТУ,  Апрель 25, 2012


Задание

Создать приложение для Windows, в окне которого средствами GDI, с помощью графических примитивов, рисуются разноцветные буквы (инициалы), совершающие равноускоренное движение.

Так же, приложение должно содержать визуализацию картинки на тему «Космическая ракета».

Теоретическая часть

GDI (Graphics Device Interface, Graphical Device Interface) — один из трёх основных компонентов или «подсистем», вместе с ядром и Windows API составляющих пользовательский интерфейс (оконный менеджер GDI) Microsoft Windows.

GDI — это интерфейс Windows для представления графических объектов и передачи их на устройства отображения, такие как мониторы и принтеры.

С выходом Windows XP появился потомок подсистемы, GDI+, основанный на C++.

GDI+ является улучшенной средой для 2D-графики, в которую добавлены такие возможности, как сглаживание линий (antialiasing), использование координат с плавающей точкой, градиентная заливка, внутренняя поддержка таких графических форматов, как JPEG и PNG, куда лучшая поддержка регионов отсечения с возможностью использовать в них координаты с плавающей точкой (а не 16-битные целые) и применения к ним World Transform, преобразования двумерных матриц и т. п. GDI+ использует ARGB-цвета. Эти возможности используются в пользовательском интерфейсе Windows XP, а их присутствие в базовом графическом слое облегчает использование систем векторной графики, таких как Flash или SVG.

Динамические библиотеки GDI+ могут распространяться вместе с приложениями для использования в предыдущих версиях Windows.

GDI+ схож с подсистемой Quartz 2D у Apple и библиотеками с открытым кодом libart и Cairo.

 GDI+ есть не более чем набор оберток над обычной GDI. В Windows 7 появился новый API Direct2D, который есть примерно то же, но реализован «сверху донизу» вплоть до драйвера видеокарты (точнее, использует некие возможности Direct3D в этом драйвере), и может использовать аппаратное ускорение — т. е. трехмерный видеопроцессор для рисования некоторых двухмерных объектов (antialiasing и т. д.)
Выполнение работы

Исходный код полученного приложения, компилируемый в системе windows с помощью средств Microsoft Visual Studio 2010, прилагается к отчёту (laba2cg.zip).

Здесь же приведу разбор исходного кода. Кстати, он большей частью состоит из кода первой лабораторной работы.

Подключаем заголовочные файлы

#include <windows.h>

#include <windowsx.h>

#include <stdexcept>

#include <gdiplus.h>

#include <tchar.h>

#include <memory> // нужен для подключения умного указателя std::auto_ptr

#include <locale>

#include <string>

#include<vector>

#include <algorithm>

Так же мы создадим ресурс для приложения – а именно, строку меню. Описание этих ресурсов поместим в файл, который так же подключим.

#include "resource.h"

Далее, параметры окна и переменные

HINSTANCE g_hInstance = NULL;

using namespace Gdiplus;

using namespace std;

TCHAR const CLASS_NAME[] = _T("MainWndClass");

TCHAR const WINDOW_TITLE[] = _T("Простейшая Анимация 2");

auto_ptr<Bitmap> g_pBitmap;

int winH = 500, winW = 700;// размер окна по умолчанию

enum{ ANIMATION_TIMER_ID = 1 }; //у нас всего один таймер

DWORD g_lastTick;

UINT_PTR g_timerId = 0;

int glide = 0, polos=103;

WCHAR fio[]=L"Ибрагимов\nРинат\nРадикович";

Функция, которая создаёт окно с меню:

HWND CreateMainWindow(HINSTANCE hInstance){

HMENU hMainMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAIN_MENU));

HWND hMainWindow = CreateWindowEx(0, CLASS_NAME, WINDOW_TITLE, WS_OVERLAPPEDWINDOW, 20, 20, winW, winH, NULL, hMainMenu, hInstance, NULL);

 return hMainWindow;

}

Для инициализации и отключения GDI+ лучше написать класс.

class CGdiplusInitializer {

 public:

CGdiplusInitializer(){

 Gdiplus::GdiplusStartupInput input;

 Gdiplus::GdiplusStartupOutput output;

if(Gdiplus::GdiplusStartup(&m_token, &input, &output) != Gdiplus::Ok){ // Не удалось        throw std::runtime_error("Failed to initialize GDI+");

 }

}

~CGdiplusInitializer(){

 Gdiplus::GdiplusShutdown(m_token);

}

 private:

ULONG_PTR m_token;

};

Класс области из предыдущей лабораторной работы

class Area { //класс, орпеделяющий эээ... место для фигур, и эээ.. жирность

 public:

 int top; //отступ сверху

 int left; //слева

 int width; //ширина фигуры

 int height; //высота

 int bold; //жирность

 Area(int l=20, int t=10, int w=50, int h=80, int b=5){ //конструктор

top = t;

left = l;

width = w;

height = h;

bold = b;

 }

 ~Area(){}

};

Функции рисования конуса и капли переписаны с использованием GDI+

void conus(Graphics *g, Pen &pen, Brush &brush, Area A, bool top = true){

Point *pntArray = new Point[3];

 if(top == false){

 pntArray[0].X = A.left+A.width/2; pntArray[0].Y = A.top+A.height;

 pntArray[1].X = A.left+A.width; pntArray[1].Y = A.top;

 pntArray[2].X = A.left; pntArray[2].Y = A.top;

} else {

 pntArray[0].X = A.left+A.width/2; pntArray[0].Y = A.top;

 pntArray[1].X = A.left+A.width; pntArray[1].Y = A.top+A.height;

 pntArray[2].X = A.left; pntArray[2].Y = A.top+A.height;

}

g->FillPolygon(&brush, pntArray, 3);

g->DrawPolygon(&pen, pntArray, 3);

}

void drop(Graphics *g, Pen &pen, Brush &brush, Area A){

g->FillPie(&brush, A.left, A.top-A.height, A.width, 2*A.height,  0, 180);

g->DrawPie(&pen, A.left, A.top-A.height,A.width, 2*A.height,  0, 180);

}

Функция, отвечающая за показ стандартного диалогового окна выбора файла. Кстати, там будет фильтр, ограничивающий выбор только изображениями, при желании.

void InitFileNameStructure(HWND hwndOwner, OPENFILENAME *pOpenFileName, TCHAR *pFileName, DWORD maxFileName){

ZeroMemory(pOpenFileName, sizeof(OPENFILENAME));

pOpenFileName->lStructSize = sizeof(OPENFILENAME);

pOpenFileName->hwndOwner = hwndOwner;

pOpenFileName->hInstance = g_hInstance;

pOpenFileName->nMaxFile = maxFileName;

pOpenFileName->lpstrFile = pFileName;

pOpenFileName->lpstrFilter =

_T("Images (BMP, PNG, JPG, TIFF)\0*.bmp;*.png;*.jpg;*.tif\0")

 _T("All files\0*.*\0")

_T("\0");

}

Обработка выбора пункта меню – «открыть файл».

void OnOpenFile(HWND hwnd, UINT codeNotify){

OPENFILENAME ofn; TCHAR fileName[MAX_PATH + 1] = _T("");

InitFileNameStructure(hwnd, &ofn, fileName, MAX_PATH);

 if (GetOpenFileName(&ofn)){

 Image img(ofn.lpstrFile);

 if (img.GetLastStatus() == Ok){

  g_pBitmap = auto_ptr<Bitmap>(new Bitmap(img.GetWidth(), img.GetHeight(), PixelFormat32bppARGB));

  Graphics g(g_pBitmap.get());

  g.DrawImage(&img, 0, 0);

  InvalidateRect(hwnd, NULL, TRUE);

 }

}

}

std::wstring WStringToLower(std::wstring const& str){

std::wstring result(str);

std::transform(result.begin(), result.end(), result.begin(), ::tolower);

 return result;

}

Теперь займёмся функциями, которые отвечают за запись в файлы.

CLSID GetEncoderCLSID(std::wstring const& fileExtension){ // Приводим разрешение к виду "*.разрешение"

std::wstring extensionMask = L"*." + WStringToLower(fileExtension) + L";"; // Запрашиваем у GDI+ количество кодировщиков изображений и размер блока данных для хранения их описания

UINT numEncoders, encodersSize;

GetImageEncodersSize(&numEncoders, &encodersSize); // Выделяем буфер для хранения информации о кодировщиках

std::vector<BYTE> encodersBuffer(encodersSize); // Запрашиваем у GDI+ информацию обо всех кодировщиков

 ImageCodecInfo* pInstalledCodecs = reinterpret_cast<ImageCodecInfo *>(&encodersBuffer[0]);

GetImageEncoders(numEncoders, encodersSize, pInstalledCodecs);

ImageCodecInfo * pMatchedCodec = NULL;

 for (unsigned i = 0; i < numEncoders; ++i){ // ищем подходящий кодировщик изображений

ImageCodecInfo & codec = pInstalledCodecs[i]; // получаем расширения файлов, поддерживаемых данным кодировщиком в формате: *.jpg;*.jpe;*.jpeg;

std::wstring extensions = WStringToLower(codec.FilenameExtension) + L";";

 if(extensions.find(extensionMask) != wstring::npos){  // Если в списке расширений содержится маска расширения файла то кодек считается найденным

 return codec.Clsid;

}

}

 return CLSID_NULL; // не нашли подходящий кодировщик, возвращаем нулевой идентификатор

}

Получение типа файла.

std::wstring GetFileExtension(std::wstring const& fileName){

size_t dotPos = fileName.find_last_of(L'.');

 if(dotPos != std::wstring::npos){

 return fileName.substr(dotPos + 1);

} else {

 return std::wstring();

}

}

Ну вот и само «Сохранение картинки в файл».

void SaveBitmap(Bitmap & bitmap, std::wstring const& fileName, int quality = 0){

std::wstring fileExtension = GetFileExtension(fileName); // получаем расширение выходного файла

CLSID codecId = GetEncoderCLSID(fileExtension); // Получаем идентификатор по расширению файла

 if (IsEqualCLSID(codecId, CLSID_NULL)){ return; } // Если вернули CLSID_NULL (кодек не найден), то выходим

EncoderParameters params; // заполняем параметры кодировщика

params.Count = 1;// у нас только один параметр (степень компресии 0-100)

 EncoderParameter & param0 = params.Parameter[0]; // заполняем характеристики параметра качество сжатия

 LONG qualityParam = quality;

param0.Guid = EncoderCompression;// идентификатор параметра "компрессия"

 param0.NumberOfValues = 1; // в массиве параметров содержится одно значение

 param0.Type = EncoderParameterValueTypeLong; // тип значений LONG

param0.Value = &qualityParam; // адрес массива параметров

 bitmap.Save(fileName.c_str(), &codecId, &params); // сохраняем изображение с использованием подобранного кодировщика и параметра Quality (на практике используется только в JPEG-е)

}

Нажатие на кнопку «сохранить»:

void OnSaveFile(HWND hwnd, UINT codeNotify){

 if (!g_pBitmap.get()){ return; } // Если изображение не открыто, то его и сохранить нельзя

 Graphics g(g_pBitmap.get());

Font font(L"Segoe UI", 48);

RectF bounds(0, 0, winW, winH);

LinearGradientBrush brush4(bounds, Color(255,0,0), Color(255,255,255,255), LinearGradientModeBackwardDiagonal);

 g.DrawString(fio, -1, &font, bounds, NULL, &brush4);// Выводим текст приветствия, длина -1 означает, что строка заканчивается нулем

 OPENFILENAME ofn;

TCHAR fileName[MAX_PATH + 1] = _T("");

InitFileNameStructure(hwnd, &ofn, fileName, MAX_PATH);

 if (GetSaveFileName(&ofn)){

SaveBitmap(*g_pBitmap, fileName, 95);

 }

}

Теперь перейдём к рисованию на экране. На этот раз мы не будем анимировать буквы.

Функция контроля параметров анимации, на этот раз только огонь.

void Animate(HWND hwnd){

 if(glide<40) glide++; else glide = 0;

InvalidateRect(hwnd, NULL, TRUE);

UpdateWindow(hwnd);

}

События окна.

void OnDestroy(HWND){ PostQuitMessage(0); }

void OnExit(HWND hwnd, UINT codeNotify){ DestroyWindow(hwnd); }

BOOL OnCreate(HWND hwnd, LPCREATESTRUCT){

g_lastTick = GetTickCount();

g_timerId = SetTimer(hwnd, ANIMATION_TIMER_ID, 20, NULL);

 return (g_timerId != 0);

}

Событие выбора пункта меню

void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify){

 switch(id){

 case ID_FILE_OPEN_IMAGE: OnOpenFile(hwnd, codeNotify); break;

 case ID_FILE_SAVE_IMAGE_AS: OnSaveFile(hwnd, codeNotify); break;

 case ID_FILE_EXIT: OnExit(hwnd, codeNotify); break;

}

}

«Тик» таймера

void OnTimer(HWND hwnd, UINT id){

 switch (id){

 case ANIMATION_TIMER_ID:

  Animate(hwnd);

    break;

}

}

Тоже событие окна, но рисование

void OnPaint(HWND hwnd) {

Насоздаём переменных и «теневой экран»

 PAINTSTRUCT ps;

HDC dc = BeginPaint(hwnd, &ps);

HDC mdc = CreateCompatibleDC(dc);

HBITMAP bdc = CreateCompatibleBitmap(dc,winW,winH);

SelectObject(mdc,bdc);

BitBlt(mdc, 0,0, winW,winH, NULL, 0,0, WHITENESS);

Инициализируем объект Graphics из GDI+

 Graphics g(mdc);

g.SetPageUnit(UnitPixel);

Font font(L"Segoe UI", 48);

RectF bounds(0, 0, winW, winH);

Если мы не должны показать в окне никакой картинки, просто рисуем ракету с текстом

 if(g_pBitmap.get() != NULL){

 g.DrawImage(g_pBitmap.get(), 0, 0);

} else {

Graphics *G = &g;

g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);

LinearGradientBrush brush1(bounds, Color(0,0,0), Color(200,200,200),LinearGradientModeVertical), brush4(bounds, Color(0,0,0, 0), Color(255,255,255, 255), LinearGradientModeBackwardDiagonal);

SolidBrush brush(Color(25,25,112)), brush2(Color(255,0,0)), brushFlameCold(Color(255,215-2*glide,0)), brushFlameHot(Color(255-2*glide,191+glide,0)), brushIlum(Color(0,127,255));

Pen pen1(Color(255, 0, 0), 2), pen2(Color(0, 255, 0), 2), pen3(Color(0, 0, 255), 2), pen4(Color(255, 255, 255), 2);

g.FillRectangle(&brush, 0, 0, winW, winH); //фон

g.FillRectangle(&brush1,450, 100, 51, 260); //ракета, цилиндр 

conus(G, pen1, brushFlameHot, Area(449, 20, 53, 80));//ракета, нос

 for(int i=0;i<5;i++){

 polos=polos+9;

 g.FillRectangle(&brush2, 450, polos, 51, 3);//ракета, полосы верхние

 g.FillRectangle(&brush2, 450, polos+110, 51, 3);//ракета, полосы нижние

}

polos=103;

g.FillEllipse(&brushIlum,460,103, 31,31);

g.FillEllipse(&brushIlum,460,140, 31,31);

drop(G, pen4, brushFlameCold, Area(442, 170, 15, 25)); //пламя из направляющих

drop(G, pen4, brushFlameCold, Area(494, 170, 15, 25));

 drop(G, pen4, brushFlameCold, Area(426, 355, 100, 150)); //Основное пламя из ускорителей

 conus(G, pen4, brushFlameHot, Area(426, 365, 45, 100),false); //Пламя из ускорителей

conus(G, pen4, brushFlameHot, Area(478, 365, 45, 100),false);

conus(G, pen1, brush1, Area(426, 235, 47, 130)); //ракета, ускорители

conus(G, pen1, brush1, Area(478, 235, 47, 130));

 conus(G, pen1, brush1, Area(441, 135, 17, 35)); //ракета, направляющие двигатели

 conus(G, pen1, brush1, Area(493, 135, 17, 35));

   g.DrawString(fio, -1, &font, bounds, NULL, &brush4);

}

BitBlt(dc, 0,0, winW,winH, mdc, 0,0, SRCCOPY);

EndPaint(hwnd, &ps);

}

Хук обработки событий.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){

 switch (uMsg){

 HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy);

 HANDLE_MSG(hwnd, WM_TIMER, OnTimer);

 HANDLE_MSG(hwnd, WM_PAINT, OnPaint);

 HANDLE_MSG(hwnd, WM_CREATE, OnCreate);

 HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);

 case WM_ERASEBKGND: return 1;

}

 return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

Создание класса приложения

bool RegisterWndClass(HINSTANCE hInstance){

WNDCLASSEX wndClass = {

 sizeof(wndClass), //UINT cbSize;

 CS_HREDRAW | CS_VREDRAW, //UINT style;

 &WindowProc, //WNDPROC lpfnWndProc;

 0, //int cbClsExtra;

 0, //int cbWndExtra;

 hInstance, //HINSTANCE hInstance;

 NULL, //HICON hIcon;

 LoadCursor(NULL, IDC_ARROW), //HCURSOR hCursor;

 (HBRUSH)(COLOR_BTNFACE + 1), //HBRUSH hbrBackground;

 NULL, //LPCTSTR lpszMenuName;

 CLASS_NAME, //LPCTSTR lpszClassName;

 NULL, //HICON hIconSm;

};

 return RegisterClassEx(&wndClass) != FALSE;

}

Основной цикл приложения

int MainLoop(HWND hMainWindow){

HACCEL accel = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_MAIN_MENU)); MSG msg;

BOOL res;

 while((res = GetMessage(&msg, NULL, 0, 0)) != 0){

 if (res == -1){ // произошла ошибка - нужно обработать ее и, вероятно, завершить работу приложения

 } else { // Пытаемся обработать сообщение как сообщение от нажатия клавиш быстрого доступа

  if(!TranslateAccelerator(hMainWindow, accel, &msg)){ // Это не сообщение о нажатии клавиш быстрого доступа обрабатываем сообщение стандартным образом

   TranslateMessage(&msg); // Если это сообщение о нажатии виртуальной клавиши, то добавляем в очередь сообщений сообщения, несущие информацию о коде вводимого пользователем символа

   DispatchMessage(&msg); // передаем сообщение в соответствующую оконную процедуру

  }

 }

}

 // сюда мы попадем только в том случае извлечения сообщения WM_QUIT. msg.wParam содержит код возврата, помещенный при помощи функции PostQuitMessage()

 return msg.wParam;

}

И старт программы. Мы ыыполняем инициализацию GDI+.

При выходе из блока try произойдет автоматическая деинициализация GDI+

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow){

 try {

 CGdiplusInitializer initializer;

 if (!RegisterWndClass(hInstance)) { return 1; } // Регистрируем класс главного окна

 HWND hMainWindow = CreateMainWindow(hInstance); // Создаем главное окно приложения

 if (hMainWindow == NULL) { return 1; }

 ShowWindow(hMainWindow, nCmdShow); // Показываем главное окно приложения

 UpdateWindow(hMainWindow);

 int result = MainLoop(hMainWindow); // Запускаем цикл выборки сообщений, пока не получим сигнал о завершении приложения

 g_pBitmap.release(); // Удаляем растр перед выходом g_pBitmap.release();

 return result;

} catch (std::runtime_error &){ // ошибка инициализации gdi+

 return 2;

}

}


Скриншот




1. ЗВЕЗДЫ НОВОГО ВЕКА 2223 февраля 2014 г
2. Блок усиления мощности нелинейного локатора
3. ТЕМА 6 У другій половині вагітності жінка приймала транквілізатори групи бензодіазепинів
4. Дипломная работа- Уголовная ответственность за убийство при отягчающих обстоятельства
5. Виды фармакологии- Кл
6. Образ бедствий в современной русской эсхатологии
7. Тюменский государственный университет Филиал в г
8. тематичне моделювання та обчислювальні методи Автореферат дисертації на здобуття наукового ступ
9. 1997 дивиденды от иностранных организаций российским организациям и наоборот ПО СТАВКЕ 0
10. тематика генетика эволюционная теория