Загружаем изображения разных форматов для GfxLib
Далеко не всегда нам хочется использовать такие продвинутые библиотеки вроде FreeImage. Иногда нам нужно просто загрузить изображение в формате PNG или JPEG , но для стандартной графической библиотеки сделали поддержку только формата BMP. Не знаю есть для Linux такие же простые средства, но в Windows можно легко загружать с помощью GDI+. И хоть в этой статье речь идет только про загрузку, так же не сложно и сохранять нарисованное в GfxLib в популярных форматах при помощи GDI+. Нам не нужно думать о лицензии, багах сторонних либ и пр. , GDI+ отлаживалась годами и хоть она тоже не без своих изъянов, но для загрузки и сохранения можно использовать без опаски. Главное при таком способе нам можно загружать форматы: Jpeg, Png, Gif, Bmp, Ico, Tiff. Естественно данный способ рассчитан на 32х битные изображения. То есть экран FbGfx должен создаваться с битностью 32 (пример: ScreenRes 200,200,32).
Формат пикселя (ARGB) у GFXLIB и GDI+ совпадает, но как в любом деле, всегда есть свои нюансы (так уж устроены все человеческий поделки). Дело в том, что если брать буфер с пикселями GDI+ , то у него все пиксели лежат друг за другом. То есть, если есть изображение размером 10х10 , то в буфере GDI+ и будет 100 пикселей по 4 байта на каждый. Такая же история и с OpenGl буфером. Но у FbGfx буфер устроен немного по другому. У него буфер всегда выравнивается прозрачными пикселями и кратность выравнивания равна четырем. То есть , если взять изображение 7х7 , то каждая строка буфера будет равна 8 пикселям (по одному пикселю на каждую строчку будет добавлено). В итоге буфер будет содержать не 49 пикселей как у GDI+ , а 56. Но не все так сложно, как кажется. Получить размер строки буфера можно стандартной функцией ImageInfo. Cоздавая изображение с помощью ImageCreate, буфер инициализируется прозрачными пикселями, то есть дописывать их не придется. Нам просто надо котролировать каждую строчку буфера FbGfx по длине изображения , и как только заполняемая пикселями длина строки будет равна ширине изображения, просто получать указатель на новую строку и продолжать копирование из буфера GDI+. В итоге для того чтобы загрузить изображение в буфер GFXLIB нам нужно (пошагово):
- Инициализировать GDI+
- Загрузить фото в битмап GDI+
- Получить размеры загружаемого фото
- Создать экран GFXLIB
- Создать изображение GFXLIB
- Получить доступ к указателю на буфер к пикселям GFXLIB
- Получить доступ к указателю на буфер к пикселям GDI+
- Скопировать пиксели из одного буфера (GDI+) в другой (GFXLIB)
- Изображение загружено, осталось только для наглядности его вывести на экран. И конечно не забыть освободить ненужные буферы GDI+ и деинициализировать GDI+
А теперь все описанное в пунках закрепим в нашем исходнике:
#INCLUDE "windows.bi" #INCLUDE Once "win/gdiplus.bi" ' открываем пространство имен GDI+ Using GDIPLUS Dim Shared ULONG_PTR_01 As ULONG_PTR ' указатель на маркер (token) , необходимый для функции GdiplusShutdown при завершении работы с GDI+ Dim GDIPLUSSTARTUPINPUT_01 As GDIPLUSSTARTUPINPUT 'вспомогательная структура для инициализации GDI+ ' ставим версию GDI+ GDIPLUSSTARTUPINPUT_01.GdiplusVersion = 1 ' Инициализация GDI+ If (GdiplusStartup(@ULONG_PTR_01, @GDIPLUSSTARTUPINPUT_01, NULL) <> 0) Then Print "FAIL" Endif ' функция загрузки изображения, взята из библиотеки window9 Function Load_imageA(Byval ImagePath As String) As Any Ptr ' указатель на битмап GDI+ Dim GPIMAGE_01 As GPBITMAP Ptr ' считаем длину строки в байтах для представления Unicode Var blen = (Len(ImagePath)*2)+2 ' Буфер для получения unicode строки Dim As Wstring Ptr wbuf ' выделяем память для буфера wbuf = Allocate( blen ) ' конвертируем строку в Unicode MultiByteToWideChar(CP_ACP, 0, ImagePath, -1, wbuf, blen) ' Загружаем изображение If (GdipLoadImageFromFile( *wbuf, @GPIMAGE_01) <> 0) Then Print "FAIL" End If ' освобождаем память буфера Deallocate(wbuf) ' возвращаем указатель на битмап GDI+ Return GPIMAGE_01 End Function Dim As Any Ptr hbmpSource ' хендл битмапа GDI+ Dim As BitmapData bitmapData ' вспомогательная структура для извлечения пикселей Dim image As Any Ptr ' хендл изображения GFX Dim pixels As Any Ptr ' адрес массива пикселей GFX Dim As Rect rect ' структура для выделения области считывания пикселей GDI+ Dim As Integer w,h ' ширина и высота изображения Dim As Integer pitch ' размер строки FbGfx ' Загружаем изображение hbmpSource=Load_imageA("1.png") ' Если изображение не удалось загрузить, выходим из программы If hbmpSource = 0 Then End ' Получаем размеры изображения GdipGetImageWidth(hbmpSource,@w) GdipGetImageHeight(hbmpSource,@h) ' Выделяем весь прямоугольник для считывания пикселей из GDI+ rect = Type(0, 0, w-1, h-1) ' Создаем 32-bit графический экран. Screenres 320, 200, 32 ' Создаем изображение GFX image = Imagecreate( w, h ) '' Получаем доступ к пикселям gfx изображения и заодно размер каждой строки ImageInfo( image,,,,pitch,pixels ) ' Блокируем область для получения доступа к пикселям GDI+ GdipBitmapLockBits(hbmpSource,Cast(Any Ptr,@rect),ImageLockModeRead,PixelFormat32bppARGB,@bitmapData) ' Копируем пиксели в из GDI в GFX For y As Integer = 0 To h-1 Dim row As Uinteger Ptr = pixels + y * pitch ' Получаем указатель на начало каждой строки For x As Integer = 0 To w-1 row[x] = Cast(Integer Ptr,bitmapData.Scan0)[x+y*w] 'Копируем пиксели Next Next ' Разблокировка области GdipBitmapUnlockBits(hbmpSource,@bitmapData) ' Закрашиваем фон экрана зеленым цветом Paint (10,10),&hff00ff55 ' Рисуем изображение в двух различных координатах с прозрачностью Put (10, 10), image,Alpha Put (79, 69), image,Alpha ' удаляем изображение GFX Imagedestroy( image ) ' удаляем изображение GDI+ GdipDisposeImage(hbmpSource) ' высвобождаем GDI+ GdiplusShutdown (ULONG_PTR_01) Sleep
Вот что у нас в итоге получилось:
Я думаю вам не составит труда переписать данный исходник так, чтобы было еще удобнее (то есть завернуть все что связано с загрузкой в одну функцию) .
Здесь я прикладываю архив с исходником и маленькое изображение в формате PNG :