Загружаем изображения разных форматов для 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


Вот что у нас в итоге получилось:

gdiplusgfx.png

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

Здесь я прикладываю архив с исходником и маленькое изображение в формате PNG :

Скачать