wxImage
можно использовать, когда Вам нужен платформо-независимый класс работы с изображениями, или как промежуточный класс для загрузки и сохранения изображений. Формат хранения информации об изображении для каждого пикселя использует байт для красного, байт для зеленого, и байт для синего каналов, плюс дополнительный байт для пикселя, если изображение имеет альфа канал.
Основные функции wxImage
в Таблице 10-6.
Таблица 10-6. wxImage
Функции
wxImage
– Изображение может быть создано с заданной шириной и высотой, из другого изображения, XPM данных, битовых данных (char[]) и опционально данных об альфа канале, из файла, су указанием типа файла, или из потока ввода.ConvertAlphaToMask
– Конвертирует альфа канал (если есть) в маску.ConvertToMono
– Конвертирует в новое монохромное изображение.Copy
– Возвращает идентичную копию, не используя подсчета ссылок.Create
– Создает изображение заданного размера, опционально инициализирует его из данных.Destroy
– Удаляет внутренние данные, если никакой другой объект их не использует.GetData, SetData
– Возвращают или задают указатель на внутренние данные (unsigned char*
).GetImageCount
– Возвращает количество изображений в файле или потоке.GetOption, GetOptionInt, SetOption, HasOption
– Возвращают, задают, или проверяют объект на наличие опции.GetSubImage
– Возвращает область изображения, как новое изображение.GetWidth, GetHeight
– Возвращают размеры изображения.Getred, GetGreen, GetBlue, SetRGB, GetAlpha, SetAlpha
– Возвращают, или задают значения красного, синего, зеленого, и альфа значения для пикселя.HasMask, GetMaskRed, GetMaskGreen, GetMaskBlue, SetMaskColour
– Функции для проверки наличия маски, установки и взятия цвета маски.LoadFile, SaveFile
– Загрузка из файла и сохранение изображения в файл.Mirror
– Зеркально отображает изображение в заданном направлении, возвращает новое изображение.Ok
– Возвращает true если изображение инициализировано.Paste
– Вставляет изображение в текущее изображение, в заданной точке.Rotate, Rotate90
– Вращает изображение, возвращает новое изображение.SetMaskFromImage
– Устанавливает маску, определяет изображение или цвет, который нужно использовать для прозрачности.Scale, Rescale
– Изменяют размеры изображения, возвращают новое изображение, или сохраняют изменения в текущем.wxImage
может загружать, или сохранять в нескольких форматах, используя обработчики, которые встроены в wxImage
и обеспечают такую расширяемость. Обработчики форматов wxImage
также используются для других классов растровых изображений, если те не имеют соответственной реализации операций с файлами.
В Таблице 10-7 указаны все типы обработчиков изображений, на платформах поддерживаемых wxWidgets. По-умолчанию всегда установлен wxBMPHandler
обработчик. Для того, что бы использовать другие форматы, установите нужный обработчик с помощью wxImage::AddHandler
или wxInitAllImageHandlers
.
Если Вы используете определенный формат, у Вас должен быть вот такой код в вашей wxApp::OnInit
функции:
#include "wx/image.h" wxImage::AddHandler( new wxPNGHandler ); wxImage::AddHandler( new wxJPEGHandler ); wxImage::AddHandler( new wxGIFHandler ); wxImage::AddHandler( new wxXPMHandler );
Или же можно просто вызвать:
wxInitAllImageHandlers();
Ниже приведен пример загрузки и сохранения изображений из файлов и потоков. Учтите, при загрузке фалов, правильно указывать абсолютный путь к файлу, а не относительный путь для рабочей директории.
// Загружаем изображение, используя конструктор, с указание типа файла wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG); if (image.Ok()) { ... } // Оставляем wxImage самому определить тип файла wxImage image(wxT("image.png")); // Загрузка в два шага wxImage image; if (image.LoadFile(wxT("image.png"))) { ... } // Загрузка в два шага, с использованием индекса изображения, для // форматов, с несколькими изображениями в файле: // загружаем изображение номер два, если оно есть wxImage image; int imageCount = wxImage::GetImageCount(wxT("image.tif")); if (imageCount > 2) image.LoadFile(wxT("image.tif"), wxBITMAP_TYPE_TIFF, 2); // Загрузка из потока wxFileInputStream stream(wxT("image.tif")); wxImage image; image.LoadFile(stream, wxBITMAP_TYPE_TIF); // Сохранение в файл image.SaveFile(wxT("image.png")), wxBITMAP_TYPE_PNG); // Сохранение в поток wxFileOutputStream stream(wxT("image.tif")); image.SaveFile(stream, wxBITMAP_TYPE_TIF);
Изображения сохраняются в файл в 24-битном формате, за исключением XPM и PCX форматов, чьи обработчики подсчитывают количество цветов и сохраняют с нужной глубиной. В JPEG формате есть опция качества, которую можно установить перед сохранением. Значение является целым числом между 0 и 100, где 0 это наихудшее качество с высоким уровнем сжатия, и 100 наивысшее качество с плохим сжатием.
// Сохраняем с оптимальным сжатием и компрессией image.SetOption(wxIMAGE_OPTION_QUALITY, 80); image.SaveFile(wxT("picture.jpg"), wxBITMAP_TYPE_JPEG);
Вам может понадобиться использовать wxImage::SetOption
когда Вы сохраняете XPM в поток, так как Вы не указываете при сохранении имя файла, и обработчик не будет знать какое значение присвоить переменной C, которая является частью данных XPM . Например:
// Сохраняем XPM в поток image.SetOption(wxIMAGE_OPTION_FILENAME, wxT("myimage")); image.SaveFile(stream, wxBITMAP_TYPE_XPM);
Учтите, обработчик добавит суффикс _xpm
к имени файла, которое Вы укажете.
Есть два способа использования прозрачности в wxImage
: маска и альфа канал. Один цвет изображения может быть указан как цвет маски, что приведет к автоматическому созданию объекта wxMask
при конвертировании в wxBitmap
.
wxImage
также поддерживает альфа канал. В дополнение к каждому байту в пикселе для красного, зеленого, и синего компонентов цвета, класс содержит байт, который указывает значение непрозрачности (opacity) для данного пикселя. Значение альфа 0 соответствует прозрачному пикселю (нулевая непрозрачность), и значение 255 указывает на то, что пиксель 100% непрозрачный.
Не у всех изображений есть альфа канал, и перед использованием GetAlpha
, Вы должны проверить наличие альфа канал с помощью HasAlpha
. В данный момент, альфа канал поддерживают только изображения, загруженные из PNG файлов, или изображения с назначенным альфа каналом функцией SetAlpha
. Сохранение изображений с альфа каналом пока не поддерживается. Рисовать изображения с альфа каналом можно сконвертировав изображение в wxBitmap
и вызвав wxDC::DrawBitmap
или wxDC::Blit
.
В нижеприведенном коде показывается, как создать wxImage
с маской. Изображение будет синим, и будет содержать прозрачный прямоугольник.
// Создаем изображение с маской // Сначала рисуем в wxBitmap wxBitmap bitmap(400, 400); wxMemoryDC dc; dc.SelectObject(bitmap); dc.SetBackground(*wxBLUE_BRUSH); dc.Clear(); dc.SetPen(*wxRED_PEN); dc.SetBrush(*wxRED_BRUSH); dc.DrawRectangle(50, 50, 200, 200); dc.SelectObject(wxNullBitmap); // Конвертируем растровое изображение (bitmap) в картинку (image) wxImage image = bitmap.ConvertToImage(); // Устанавливаем красный как цвет маски image.SetMaskColour(255, 0, 0);
Другой способ сделать маску – это создать ее из другого изображения. В следующем примере, image.bmp
содержит основное изображение, и mask.bmp
содержит черные пиксели, которые будут указывать на прозрачные области.
// Загрузим изображение и его маску wxImage image(wxT("image.bmp"), wxBITMAP_TYPE_BMP); wxImage maskImage(wxT("mask.bmp"), wxBITMAP_TYPE_BMP); // Укажем черный, как цвет маски image.SetMaskFromImage(maskImage, 0, 0, 0);
Если Вы загрузили изображение с диска, Вы можете проверить его на прозрачность, и получить цвет маски:
// Загружаем изображение с прозрачностью wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG); // Получаем маску if (image.HasMask()) { wxColour maskColour(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue()); }
wxImage
поддерживает масштабирование, вращение, и зеркальное отражение картинки. Вот несколько примеров:
// Масштабировать изображение как 200x200 // и назначить результат другому объекту. // image1 не модифицируется. wxImage image2 = image1.Scale(200, 200); // Изменяем размер на 200x200 image1.Rescale(200, 200); // Вращаем на указаное число радиан. // image1 не модифицируется. wxImage image2 = image1.Rotate(0.5); // Вращаем на 90 градусов по часовой стрелке. // image1 не модифицируется. wxImage image2 = image1.Rotate90(true); // Отражаем изображение по горизонтали. // image1 не модифицируется. wxImage image2 = image1.Mirror(true);
Уменьшение Цветности
Если Вам нужно уменьшить количество цветов в изображении, Вы можете использовать статические функции класса wxQuantize
. Нужная нам функция Quantize
, в качестве аргументов принимает исходное изображение, возвращаемое изображение, выборочно палитру wxPalette**
для сокращенных из изображения цветов, и желаемое количество цветов. Так же можно указать переменную типа unsigned char**
, для получения 8-битного представления возвращаемого изображения и стиль, для лучшего управления возвращаемыми данными; для более детальной информации, смотрите справочное руководство.
Данный пример показывает, как уменьшить цветность изображения до 256 цветов:
#include "wx/image.h" #include "wx/quantize.h" wxImage image(wxT("image.png")); int maxColorCount = 256; int colors = image.CountColours(); wxPalette* palette = NULL; if (colors > maxColorCount ) { wxImage reducedImage; if (wxQuantize::Quantize(image, reducedImage, & palette, maxColorCount)) { colors = reducedImage.CountColours(); image = reducedImage; } }
С изображением может идти палитра, связанная с ним wxPalette
, например когда изображение загружено из GIF файла. Тем не менее, изображение хранится в RGB формате, а палитра просто указывает значение индексов в RGB формате. Для wxImage
также можно назначить палитру wxPalette
, и в результате SaveFile может сохранить данное изображение с ограниченным количеством цветов. Например, если Windows BMP обработчик обнаруживает, что в опциях изображения указан wxBMP_8BPP_PALETTE
формат, он сохраняет изображение с палитрой изображения; если указан формат wxBMP_8BPP
, обработчик создает палитру из данных изображения. Некоторые обработчики сами производят уменьшение цветности, например PCX, пока не подберут достаточное количество уникальных цветов.
Больше информации по wxPalette, смотрите в разделе “wxPalette” в Главе 5.
Вы можете получить доступ непосредственно к данным изображения функцией GetData
, для более быстрой манипуляции данными, чем через GetRed
, GetBlue
, GetGreen
, и SetRGB
. Ниже показан пример преобразования цветного изображения в черно-белое:
void wxImage::ConvertToGrayScale(wxImage& image) { double red2Gray = 0.297; double green2Gray = 0.589; double blue2Gray = 0.114; int w = image.GetWidth(), h = image.GetHeight(); unsigned char *data = image.GetData(); int x,y; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { long pos = (y * w + x) * 3; char g = (char) (data[pos]*red2Gray + data[pos+1]*green2Gray + data[pos+2]*blue2Gray); data[pos] = data[pos+1] = data[pos+2] = g; } } [/sourcecode] <h3>Списки Изображений и Пакеты Иконок</h3> Иногда удобно объединять несколько изображений в один объект. Списки <code>wxImageList</code> можно использовать непосредственно в Вашем приложении, или для иконок элементов управления wxWidgets, которые используют списки изображений (image lists). <code>wxNotebook</code>, <code>wxTreeCtrl</code>, и <code>wxListCtrl</code> используют <code>wxImageList</code> для иконок в своих элементах. Также можно просто нарисовать отдельное изображение из списка <code>wxImageList</code> в контекст устройства. <code>wxImageList</code> создается с указанием высоты и ширины каждого изображения, булевым значением, которое указывает на то будет ли использоваться маска, и начальным размером списка (для внутренней оптимизации). Потом нужно добавить несколько <code>wxBitmap</code> или <code>wxIcon</code> изображений. Для списков нельзя использовать <code>wxImage</code> объект, но можно передать его в конструктор <code>wxBitmap</code>. <code>wxImageList::Add</code> возвращает целочисельный индекс, который потом можно использовать как идентификатор изображения; после того, как Вы добавите изображение в список, Вы можете его уничтожить, потому что <code>wxImageList</code> делает его копию. Далее несколько примеров создания <code>wxImageList</code> и добавления в него изображений. [sourcecode language="cpp"] // СозданиеImageList wxImageList *imageList = new wxImageList(16, 16, true, 1); // Добавление растрового изображения с прозрачностью из PNG wxBitmap bitmap1(wxT("image.png"), wxBITMAP_TYPE_PNG); imageList->Add(bitmap1); // Добавление изображения с прозрачностью из другого растрового изображения wxBitmap bitmap2(wxT("image.bmp"), wxBITMAP_TYPE_BMP); wxBitmap maskBitmap(wxT("mask.bmp"), wxBITMAP_TYPE_BMP); imageList->Add(bitmap2, maskBitmap); // Добавление растрового изображения с маской, указанной цветом маски wxBitmap bitmap3(wxT("image.bmp"), wxBITMAP_TYPE_BMP); imageList->Add(bitmap3, *wxRED); // Добавление иконки #include "folder.xpm" wxIcon icon(folder_xpm); imageList->Add(icon);
Можно нарисовать изображение непосредственно в контекст устройства, передав флаг, который указывает, как будет нарисовано изображение. wxIMAGELIST_DRAW_TRANSPARENT, например, указывает, что изображение рисуется с использованием прозрачности, есть еще три формата рисования: wxIMAGELIST_DRAW_NORMAL
,
wxIMAGELIST_DRAW_SELECTED
, или wxIMAGELIST_DRAW_FOCUSED
.
// Рисуем все изображения в списке wxClientDC dc(window); size_t i; for (i = 0; i < imageList->GetImageCount(); i++) { imageList->Draw(i, dc, i*16, 0, wxIMAGELIST_DRAW_NORMAL| wxIMAGELIST_DRAW_TRANSPARENT); }
Для того, что бы назначить иконки вкладкам блокнота (notebook), нужно создать список изображений с иконками 16x16 , и вызвать wxNotebook::SetImageList
или wxNotebook::AssignImageList
. Если Вы будете использовать первый вариант, блокнот не будет удалять список, когда будет уничтожатся; во втором варианте, блокнот принимает на себя управление списком и Вам не нужно волноваться из-за удаления списка изображений. Теперь, когда Вы добавляете страницы в блокнот, Вы можете указать индекс иконки, которая будет показываться возле текста на вкладке (или вместо него, если на вкладке нет надписи). Ниже показан пример кода, где добавляется две страницы с иконками на вкладках.
// Создадим wxImageList wxImageList *imageList = new wxImageList(16, 16, true, 1); // Добавим несколько иконок wxBitmap bitmap1(wxT("folder.png"), wxBITMAP_TYPE_PNG); wxBitmap bitmap2(wxT("file.png"), wxBITMAP_TYPE_PNG); int folderIndex = imageList->Add(bitmap1); int fileIndex = imageList->Add(bitmap2); // Создадим блокнот с двумя страницами wxNotebook* notebook = new wxNotebook(parent, wxID_ANY); wxPanel* page1 = new wxPanel(notebook, wxID_ANY); wxPanel* page2 = new wxPanel(notebook, wxID_ANY); // Назначим список изображений notebook->AssignImageList(imageList); // Добавим страницы с иконками notebook->AddPage(page1, wxT("Folder options"), true, folderIndex); notebook->AddPage(page2, wxT("File options"), false, fileIndex);
В wxTreeCtrl
и wxListCtrl
используется тот же принцип с указанием списка изображений, или назначением его элементу (когда элемент управления берет на себя удаление списка).
Если у Вас много иконок, и Вам трудно управлять ими с помощью индексов, можете написать собственный класс, который ассоциирует индексы с символьными именами. Ниже показан простейший пример как это можно реализовать:
#include "wx/hashmap.h" WX_DECLARE_STRING_HASH_MAP(int, IconNameToIndexHashMap); // Класс для обращения к индексам через имя class IconNameToIndex { public: IconNameToIndex() {} // Добавление изображения с именем в список изображений void Add(wxImageList* list, const wxBitmap& bitmap, const wxString& name) { m_hashMap[name] = list->Add(bitmap); } // Добавление иконки с именем в список изображений void Add(wxImageList* list, const wxIcon& icon, const wxString& name) { m_hashMap[name] = list->Add(icon); } // Поиск индекса по имени int Find(const wxString& name) { return m_hashMap[name]; } private: IconNameToIndexHashMap m_hashMap; };
wxIconBundle
это класс для набора изображений, но он предназначен для хранения разных разрешений одного изображения, а не множества картинок. Этот класс помогает подобрать системе картинку нужного размера. Например, иконка из заголовка окна может быть меньше, чем та же иконка файла, или иконка в менеджере задач. Ниже показан пример использования пакета иконок (icon bundle).
// Создаем пакет с одной иконкой #include "file16x16.xpm" wxIconBundle iconBundle(wxIcon(file16x16_xpm)); // Добавляем иконку из файла iconBundle.Add(wxIcon(wxT("file32x32.png"), wxBITMAP_TYPE_PNG)); // Создаем пакет иконок из нескольких иконок в одном фале wxIconBundle iconBundle2(wxT("multi-icons.tif"), wxBITMAP_TYPE_TIF); // Получает иконку с заданным размером, или если не найдена, берет иконку // с размерами wxSYS_ICON_X, wxSYS_ICON_Y wxIcon icon = iconBundle.GetIcon(wxSize(16,16)); // Назначает пакет иконок приложению wxFrame* frame = new wxFrame(parent, wxID_ANY); frame->SetIcons(iconBundle);
В Windows, SetIcons
извлекает иконки размером 16x16 и 32x32 из пакета.
wxArtProvider
класс – это класс, который позволяет настраивать встроенную графику ("art") в wxWidgets приложениях. Например, Вы хотите заменить стандартные иконки в wxWidgets HTML справке или иконки в общих диалогах, таких как просмотрщик логов.
В wxWidgets есть стандартный объект wxArtProvider
, и когда вашей программе нужна графическая информация, вызывается wxArtProvider::GetBitmap
и wxArtProvider::GetIcon
для получения иконок.
У графических объектов есть два идентификатора: графический идентификатор (wxArtID
) и пользовательский идентификатор (wxArtClient
). Пользовательский идентификатор применяется, если разным окнам нужно использовать разные изображения для одних графических идентификаторов. Как пример, окно справки wxHTML использует следующий код, для изображения кнопки "назад" на панели инструментов:
wxBitmap bmp = wxArtProvider::GetBitmap(wxART_GO_BACK,wxART_TOOLBAR);
Вы можете посмотреть идентификаторы и графику, встроенную в wxWidgets, скомпилировав и запустив проект samples/artprov
в wxWidgets директории. На Изображении 10-1 показано окно браузера графики.
Для того, что бы заменить графические элементы wxWidgets, создайте производный класс из wxArtProvider
, перегрузите CreateBitmap
, и вызовите wxArtProvider::PushProvider
в OnInit
функции для того, что бы wxWidgets использовала ваш класс. Ниже показан пример замени большинства графики окна справки wxHTML
.
// XPM’ы с графикой #include "bitmaps/helpbook.xpm" #include "bitmaps/helppage.xpm" #include "bitmaps/helpback.xpm" #include "bitmaps/helpdown.xpm" #include "bitmaps/helpforward.xpm" #include "bitmaps/helpoptions.xpm" #include "bitmaps/helpsidepanel.xpm" #include "bitmaps/helpup.xpm" #include "bitmaps/helpuplevel.xpm" #include "bitmaps/helpicon.xpm" #include "wx/artprov.h" // Класс графики class MyArtProvider : public wxArtProvider { protected: virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size); }; // CreateBitmap функция wxBitmap MyArtProvider::CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size) { if (id == wxART_HELP_SIDE_PANEL) return wxBitmap(helpsidepanel_xpm); if (id == wxART_HELP_SETTINGS) return wxBitmap(helpoptions_xpm); if (id == wxART_HELP_BOOK) return wxBitmap(helpbook_xpm); if (id == wxART_HELP_FOLDER) return wxBitmap(helpbook_xpm); if (id == wxART_HELP_PAGE) return wxBitmap(helppage_xpm); if (id == wxART_GO_BACK) return wxBitmap(helpback_xpm); if (id == wxART_GO_FORWARD) return wxBitmap(helpforward_xpm); if (id == wxART_GO_UP) return wxBitmap(helpup_xpm); if (id == wxART_GO_DOWN) return wxBitmap(helpdown_xpm); if (id == wxART_GO_TO_PARENT) return wxBitmap(helpuplevel_xpm); if (id == wxART_FRAME_ICON) return wxBitmap(helpicon_xpm); if (id == wxART_HELP) return wxBitmap(helpicon_xpm); // Любые иконки wxWidgets, которые здесь не реализованы, // будут поставлены «родным» классом графики. return wxNullBitmap; } // Инициализация bool MyApp::OnInit() { ... wxArtProvider::PushProvider(new MyArtProvider); ... return true; }
В этой главе мы рассмотрели использование четырех основных классов изображений wxBitmap
, wxIcon
, wxCursor
, и wxImage
и двух классов для объединения изображений wxImageList и wxIconBundle. Также мы посмотрели, как можно заменить иконки и изображения wxWidgets своими собственными. Для примеров использования классов изображений, смотрите samples/image
, samples/listctrl
, и samples/dragimag
в wxWidgets директории.
В следующей главе мы рассмотрим классы, которые позволяют реализовать перенос данных с помощью буфера обмена и drag’n’drop.
Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…
I can see that there is still a lot of topics at wxWidgets forums related…
I've just published the source code of wxToolBox component and a couple of sample apps at…
Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…
Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…
View Comments
больше всего заинтересовала wxQuantize...
Судя по всему ее можно использовать чтобы сделать темнее\ярче изображение...
Нужно проверить.
Эээ.. если не лень, про результаты проверки потом отпиши plz? :)