Avif image - read/convert to dibitmap

New to FreeBASIC? Post your questions here.
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Avif image - read/convert to dibitmap

Post by srvaldez »

@UEZ
[off-topic]
MasterGy from the QB64 forum made some amazing graphic demos https://qb64forum.alephc.xyz/index.php?topic=4735.0, you might find them interesting
[/off-topic]
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

Re: Avif image - read/convert to dibitmap

Post by Iczer »

I tried to load (just load) libavif.so (x64, renamed to .dll) but get "InitOnceBeginInitialize not found in KERNEL32.dll." (I'm need it under WinXP x64) So I tried to compile library from source, but after running cmake and enabling AVIF_CODEC_AOM, I get:

Code: Select all

libavif: Enabling warnings for GCC
libavif: libyuv not found; libyuv-based fast paths disabled.
CMake Error at C:/cmake-3.23.1-windows-x86_64/share/cmake-3.23/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find aom (missing: AOM_LIBRARY AOM_LIBRARIES AOM_INCLUDE_DIR)
Call Stack (most recent call first):
  C:/cmake-3.23.1-windows-x86_64/share/cmake-3.23/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
  cmake/Modules/Findaom.cmake:32 (find_package_handle_standard_args)
  CMakeLists.txt:386 (find_package)

Configuring incomplete, errors occurred!
See also "C:/libavif-main/_build/CMakeFiles/CMakeOutput.log".
So I tried to compile AOM library separately, but get:

Code: Select all

Could NOT find Git (missing: GIT_EXECUTABLE) 
--- aom_configure: Detected CPU: x86_64
CMake Error at build/cmake/aom_configure.cmake:141 (message):
  Unable to find assembler.  Install 'yasm' or 'nasm.' To build without
  optimizations, add -DAOM_TARGET_CPU=generic to your cmake command line.
Call Stack (most recent call first):
  CMakeLists.txt:66 (include)

Configuring incomplete, errors occurred!
I downloaded yaml (yasm-1.3.0-win64.exe) placed it in mingw64 \bin folder and renamed copy of it to yasm.exe but cmake still cannot find yasm... Where I should place yasm.exe so cmake can successfully find it? Is it possible to compile avif.dll for WinXP x64?
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Avif image - read/convert to dibitmap

Post by srvaldez »

renaming libavif.so to libavif.dll won't work because then some other function may complain that libavif.so can't be found
just pretend that libavif.so is a dll which it is
I don't have a Windows XP-x64 VM to check, maybe a dll compiled on Windows 7 might work
Iczer, have you tried installing msys2 on your system? https://www.msys2.org/
if you are able to install msys2 then you should know that the installation doesn't include any development tools like gcc, you have to install them via pacman
like pacman -S gcc
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Avif image - read/convert to dibitmap

Post by srvaldez »

hello Iczer
here's the avif.dll with the dependencies
built on Windows 7 x64 https://drive.google.com/file/d/1gGd_uF ... sp=sharing
[edit]
I did a clean install of msys2 on Windows 7 x64 and when I launched the msys2 shell at some point I got the message that msys2 support for Windows 7 would discontinue this year (2022) so I went on a package-install spree, I lost count of the number of packages I installed
so finally it was time to build libavif, when I issued the command cmake .. it said something like "building for ninja" all went well except that there was no makefile, took me some minutes to figure out that now instead of issuing the command make I needed to do ninja and it built the dll not an .so as on my first experiment, the only downside are all the dependent dll's, but you can build a static lib, extract the objects and do gcc -static -shared -o libavif.dll *.obj -laom -l yuv and you have a standalone dll
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Avif image - read/convert to dibitmap

Post by UEZ »

The issue with "Always getting an error: "Error = 9 / Failed to decode image -> BMFF parsing failed"" can be fixed when setting strictFlags to AVIF_STRICT_DISABLED

Code: Select all

...
Dim As avifDecoder Ptr decoder = avifDecoderCreate()
decoder->strictFlags = AVIF_STRICT_DISABLED
...
Tested two images which didn't work now working. :)
Last edited by UEZ on May 27, 2022 22:48, edited 2 times in total.
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Avif image - read/convert to dibitmap

Post by srvaldez »

same here :(
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Avif image - read/convert to dibitmap

Post by UEZ »

srvaldez wrote: May 27, 2022 22:42same here :(
Which one is not working for you?

srvaldez wrote: May 26, 2022 12:39 @UEZ
[off-topic]
MasterGy from the QB64 forum made some amazing graphic demos https://qb64forum.alephc.xyz/index.php?topic=4735.0, you might find them interesting
[/off-topic]
Thx - will have a look to it... :)
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Avif image - read/convert to dibitmap

Post by srvaldez »

sorry I missed your post
it fail with kodim03_yuv420_8bpc.avif
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Avif image - read/convert to dibitmap

Post by UEZ »

srvaldez wrote: May 28, 2022 12:14 sorry I missed your post
it fail with kodim03_yuv420_8bpc.avif
Hmmm, that's odd. It works for me on WIn10 and Win7 (VM) properly.

You may try this: AVIF.7z
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Avif image - read/convert to dibitmap

Post by srvaldez »

Hi UEZ
works perfect :)
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Avif image - read/convert to dibitmap

Post by UEZ »

srvaldez wrote: May 28, 2022 16:24 Hi UEZ
works perfect :)
:wink:

Btw, why is the size of libavif.so so huge?

@Iczer: you have a look to WebP image compression (Autoit version) if you are interested. :)
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Avif image - read/convert to dibitmap

Post by srvaldez »

UEZ wrote: May 28, 2022 16:46 Btw, why is the size of libavif.so so huge?
because it uses libaom which is huge https://aomedia.googlesource.com/aom/
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

Re: Avif image - read/convert to dibitmap

Post by Iczer »

with disabled multi-threading in aom codec it works in XP...

I'm testing avif-preview GUI based on freeimage and avif lib's , but run into problem with wrong colors:

Code: Select all

' =============================================================================================
#Pragma Once
' .........................................................................................
#Define UNICODE

#Ifndef MB_TIMEDOUT
	Const MB_TIMEDOUT = 32000
#EndIf
' .........................................................................................
#Include Once "avif.bi"
#Include Once "FreeImage.bi"
' .........................................................................................
#LibPath "E:\Program Files\FreeBASIC\libPlusN2"
' .........................................................................................
#Inclib "avif"
' =============================================================================================
Const _WindowClassName = "AVIFPreviewGUI"
Dim Shared As WndClassEx Ptr __WindowClass

Declare Function _WndProc(ByVal hWnd AS HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As LRESULT
Declare Function Preview_GUI(ByVal pwsPathTo_ImageToShow As WString Ptr) As Long
Declare Function avifIOCreateImageDecoderU(Byval filename As WString Ptr) As avifDecoder Ptr
' =============================================================================================
'
' =============================================================================================
Dim As WString Ptr pwsPathTo_ImageToShow = @(WStr("kodim03_yuv420_8bpc.avif"))


Preview_GUI(pwsPathTo_ImageToShow)


' =============================================================================================
'
' =============================================================================================
Function Preview_AVIF(ByVal pwsPathTo_ImageToShow As WString Ptr, ByVal hWndMain As HWND, ByVal hPicFrame As HWND, ByRef iPic_WMax As Long, ByRef iPic_HMax As Long) As Long
	'-----------------------------------------------------------------------------------------
	
	'-----------------------------------------------------------------------------------------
	Dim As avifResult result
	Dim As avifDecoder Ptr decoder = avifIOCreateImageDecoderU(pwsPathTo_ImageToShow)
	Dim As avifRGBImage _rgb
	
	Dim As ULong iBPP, iRetVal, c = 0
	Dim As Long iPic_RatioMax, iPic_Ratio, iPic_W, iPic_H, iPic_WNew, iPic_HNew
	Dim As Double dblPic_W, dblPic_H, dblPic_WNew, dblPic_HNew, dblPic_WMax, dblPic_HMax, dblPic_Ratio, dblPic_RatioMax
	
	If decoder <> NULL Then
		result = avifDecoderParse(decoder)
		If result = AVIF_RESULT_OK Then
			'---------------------------------------------------------------------------------
			While avifDecoderNextImage(decoder) = AVIF_RESULT_OK
				avifRGBImageSetDefaults(@_rgb, decoder->image)
				avifRGBImageAllocatePixels(@_rgb)
				avifImageYUVToRGB(decoder->image, @_rgb)
				c += 1
			Wend
			'---------------------------------------------------------------------------------
			Select Case As Const _rgb.Format
				Case AVIF_RGB_FORMAT_RGB	:	iBPP = 3 * _rgb.depth
				Case AVIF_RGB_FORMAT_RGBA	:	iBPP = 4 * _rgb.depth
				Case AVIF_RGB_FORMAT_ARGB	:	iBPP = 4 * _rgb.depth
				Case AVIF_RGB_FORMAT_BGR	:	iBPP = 3 * _rgb.depth
				Case AVIF_RGB_FORMAT_BGRA	:	iBPP = 4 * _rgb.depth
				Case AVIF_RGB_FORMAT_ABGR	:	iBPP = 4 * _rgb.depth
			End Select
			'---------------------------------------------------------------------------------
			iPic_H = decoder->image->height
			iPic_W = decoder->image->Width
			
			dblPic_WNew = CDbl(iPic_W)
			dblPic_HNew = CDbl(iPic_H)
			dblPic_Ratio = dblPic_WNew/dblPic_HNew
			
			dblPic_WMax = CDbl(iPic_WMax)
			dblPic_HMax = CDbl(iPic_HMax)
			dblPic_RatioMax = dblPic_WMax/dblPic_HMax
			
			If dblPic_WNew > dblPic_WMax Then
				dblPic_WNew = dblPic_WMax
				dblPic_HNew = dblPic_WMax/dblPic_Ratio
			EndIf
			
			If dblPic_HNew > dblPic_HMax Then
				dblPic_WNew = dblPic_HMax*dblPic_Ratio
				dblPic_HNew = dblPic_HMax
			EndIf
			
			iPic_WNew =	CLng(dblPic_WNew)
			iPic_HNew = CLng(dblPic_HNew)
			'---------------------------------------------------------------------------------
			Dim As FIBITMAP Ptr hImageOriginal, hImageResized, hImageResized2
			Dim As FREE_IMAGE_FORMAT ImageFIF
			Dim As HDC hDC
			Dim As HBITMAP hDIB
			Dim As Long pitch = _rgb.rowBytes'((((iBPP * _rgb.width) + 31) / 32) * 4)
			Dim As Boolean topdown = TRUE
			Dim As ULong red_mask	= &h00FF0000, _
							 green_mask	= &h0000FF00, _
							 blue_mask	= &h000000FF
			
			hImageOriginal = FreeImage_ConvertFromRawBits(_rgb.pixels,iPic_W, _
																						 iPic_H, _
																						 pitch, _
																						 iBPP, _
																						 red_mask, green_mask, blue_mask, topdown)
			'---------------------------------------------------------------------------------
			hImageResized = FreeImage_Rescale(hImageOriginal, iPic_WNew, iPic_HNew, FILTER_CATMULLROM)' FILTER_LANCZOS3
			
			iBPP = FreeImage_GetBPP(hImageResized)
			
			If iBPP >= 32 Then
				hImageResized2 = FreeImage_ConvertTo24Bits(hImageResized)
				
				If hImageResized <> 0 Then
					FreeImage_Unload(hImageResized)
				EndIf
				
				hImageResized = hImageResized2
			EndIf
			
			If hImageOriginal <> 0 Then
				FreeImage_Unload(hImageOriginal)
			EndIf
			'---------------------------------------------------------------------------------
			hDC = GetDC(hWndMain)
			
			hDIB = CreateDIBitmap(hDC,FreeImage_GetInfoHeader(hImageResized), CBM_INIT, FreeImage_GetBits(hImageResized), FreeImage_GetInfo(hImageResized), 0)
			
			ReleaseDC(hWndMain, hDC)
			
			DeleteObject(Cast(HANDLE, SendMessage(hPicFrame, STM_SETIMAGE, Cast(WPARAM, IMAGE_BITMAP), Cast(LPARAM, hDIB))))
			
			If hImageResized <> 0 Then
				FreeImage_Unload(hImageResized)
			EndIf
			'---------------------------------------------------------------------------------
		EndIf
	EndIf
	'-----------------------------------------------------------------------------------------
	avifRGBImageFreePixels(@_rgb)
	avifDecoderDestroy(decoder)
	
	Return 0
End Function
' =============================================================================================
Function avifIOCreateImageDecoderU(Byval filename As WString Ptr) As avifDecoder Ptr
	
	Dim As FILE Ptr f = _wfopen(filename, StrPtr(WStr("rb")))
	
	If f = NULL Then
		Return NULL
	EndIf
	
	fseek(f, 0, SEEK_END)
	Dim As Long imageSize = ftell(f)
	
	If imageSize < 0 Then
		fclose(f)
		Return NULL
	EndIf
	fseek(f, 0, SEEK_SET)
	
	Dim As UByte Ptr imagedata = Allocate(imageSize)
	Dim As UInteger bytesRead = fread(imagedata, 1, imageSize, f)
	
	fclose(f)
	
	If imageSize <> bytesRead Then
		If ferror(f) <> 0 Then
			Deallocate(imagedata)
			Return NULL
		EndIf
		imageSize = bytesRead
	EndIf
	
	Dim As avifDecoder Ptr decoder = avifDecoderCreate()
	
	decoder->strictFlags = AVIF_STRICT_DISABLED
	decoder->maxThreads = 1
	
	Dim As avifResult result = avifDecoderSetIOMemory(decoder, imagedata, imageSize)
	
	If result <> AVIF_RESULT_OK Then
		Deallocate(imagedata)
		avifDecoderDestroy(decoder)
		Return NULL
	EndIf
	
	Return decoder
End Function
' =============================================================================================
'
' =============================================================================================
Sub  _InitClass()

	'-----------------------------------------------------------------------------------------
	' creating custom class
	'-----------------------------------------------------------------------------------------
	Dim As Long iIsOlreadyInit
	' ........................................................................................
	Dim As DWORD dwNum = MultiByteToWideChar(CP_UTF8, 0, StrPtr(_WindowClassName), -1, NULL, 0)
	Dim As WString Ptr _WindowClassNameW = CAllocate(dwNum + 1, 2)	:	MultiByteToWideChar(CP_UTF8, 0, StrPtr(_WindowClassName), -1, _WindowClassNameW, dwNum)
	' ........................................................................................
	Dim As WString Ptr lpMsgBuf
	Dim As ATOM MsgBoxEXWClass
	Dim As HINSTANCE hInst = GetModuleHandle(NULL)
	' ........................................................................................
	__WindowClass = New WndClassEx
	
	__WindowClass->cbSize	= SizeOf(*__WindowClass)
	
	iIsOlreadyInit = GetClassInfoExW( hInst, _WindowClassNameW, __WindowClass)
	
	If iIsOlreadyInit = 0 Then
		
		__WindowClass->STYLE         = CS_VREDRAW Or CS_HREDRAW Or CS_DBLCLKS Or CS_BYTEALIGNCLIENT Or CS_BYTEALIGNWINDOW
		__WindowClass->lpfnWndProc   = Cast(WNDPROC, @_WndProc)
		__WindowClass->cbClsExtra    = 0
		__WindowClass->cbWndExtra    = 0
		__WindowClass->hInstance     = hInst
		__WindowClass->hIcon         = LoadIcon( NULL, IDI_APPLICATION ) 
		__WindowClass->hCursor       = LoadCursor(NULL, IDC_ARROW)
		__WindowClass->lpszMenuName  = NULL
		__WindowClass->lpszClassName = _WindowClassNameW
		__WindowClass->hIconSm       = LoadIcon( NULL, IDI_APPLICATION ) 
		__WindowClass->hbrBackground = GetSysColorBrush(COLOR_3DFACE)
		
		__WindowClass->cbSize        = SizeOf(*__WindowClass)
		
		MsgBoxEXWClass = RegisterClassExW(__WindowClass)
		
		If MsgBoxEXWClass = 0 Then
			Dim As Integer iErrCurrent = GetLastError()
			
			Print !"x  InitClass :: Error : Cannot register __WindowClass :: Error = " & Str(iErrCurrent)
		EndIf
	End If
	
	Delete __WindowClass
	' ........................................................................................
	DeAllocate(_WindowClassNameW)
	' ........................................................................................
End Sub
' =============================================================================================
Function Preview_GUI(ByVal pwsPathTo_ImageToShow As WString Ptr) As Long
	
	' ........................................................................................
	_InitClass()
	' ........................................................................................
	'
	' ........................................................................................
	Dim As String  TitleName = "Avif Preview :"
	' ........................................................................................
	Dim As DWORD dwNum
	
	dwNum = MultiByteToWideChar(CP_UTF8, 0, StrPtr(_WindowClassName), -1, NULL, 0)
	Dim As WString Ptr sClassNameW = CAllocate(dwNum + 1, 2)
												MultiByteToWideChar(CP_UTF8, 0, StrPtr(_WindowClassName), -1, sClassNameW, dwNum)
	
	dwNum = MultiByteToWideChar(CP_UTF8, 0, StrPtr(TitleName), -1, NULL, 0)
	Dim As WString Ptr sTitleNameW = CAllocate(dwNum + 1, 2)
												MultiByteToWideChar(CP_UTF8, 0, StrPtr(TitleName), -1, sTitleNameW, dwNum)
	' ........................................................................................
	Dim As UShort nWidth	=  GetSystemMetrics(SM_CXSCREEN)/3
	Dim As UShort nHeight=  GetSystemMetrics(SM_CYSCREEN)/3 + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYBORDER)
	Dim As UShort nLeft	= (GetSystemMetrics(SM_CXSCREEN) - nWidth)\2
	Dim As UShort nTop	= (GetSystemMetrics(SM_CYSCREEN) - nHeight)\2
	' ----------------------------------------------------------------------------------------
	Dim As HINSTANCE hInst = GetModuleHandle(NULL)
	'-----------------------------------------------------------------------------------------
	' Create GUI Window.
	' ----------------------------------------------------------------------------------------
	Dim As HWND hWndMain = CreateWindowExW(WS_EX_WINDOWEDGE Or WS_EX_TOPMOST Or WS_EX_STATICEDGE, _'EXSTYLE 0x00000008
														sClassNameW, _
														sTitleNameW, _
														WS_CAPTION Or WS_POPUP Or WS_SYSMENU Or DS_SETFOREGROUND, _'STYLE 0x10C80800
														nLeft, nTop, nWidth, nHeight, _
														NULL, NULL, hInst, NULL)
	'------------------------------------------------------------------------------
	' Create Group Frame control.
	'------------------------------------------------------------------------------
	Dim As HWND hwndGroup = CreateWindowEx( WS_EX_TRANSPARENT Or WS_EX_LEFT Or WS_EX_LTRREADING, _
														"Button", _  
														"Avif Image wrong colors...", _ 
														WS_CHILD Or WS_VISIBLE Or BS_TEXT Or BS_LEFT Or BS_GROUPBOX, _'0x50000007
														8,2, nWidth-16,nHeight-12 - (GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYBORDER)), _ 
														hWndMain, NULL, hInst, NULL )
	'------------------------------------------------------------------------------
	' Create Image control.
	'------------------------------------------------------------------------------
	Dim As ULong imgW = nWidth-32, imgH = nHeight-48 - (GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYBORDER))
	
	Dim As HWND hwndImage = CreateWindowEx( WS_EX_LEFT Or WS_EX_LTRREADING or WS_EX_CLIENTEDGE Or WS_EX_RIGHTSCROLLBAR, _
														"Static", _  
														"", _ 
														WS_CHILD Or WS_VISIBLE Or SS_BITMAP, _
														16,22,imgW,imgH, _ 
														hWndMain, Cast(HMENU, 16011), hInst, NULL )
	' .............................................................................
	Preview_AVIF(pwsPathTo_ImageToShow, hWndMain, hwndImage, imgW, imgH)
	'------------------------------------------------------------------------------
	ShowWindow(hWndMain, SW_SHOWNOACTIVATE)
	UpdateWindow(hWndMain)
	' ----------------------------------------------------------------------------------------
	Dim As UInteger iTimeToPresent = 88888, nTimerIDEvent = SetTimer(hWndMain, -1, iTimeToPresent, NULL)
	Dim As Long iReturnValue = MB_TIMEDOUT
	Dim As MSG uMsg
	
	While (GetMessage(@uMsg, hWndMain,  0, 0) <> 0)
		
		Select Case (uMsg.message)
			
			Case WM_TIMER
				If uMsg.wParam = nTimerIDEvent Then	:	iReturnValue = MB_TIMEDOUT	:	Exit While	:	EndIf
				
		End Select
		
		TranslateMessage( @uMsg )
		DispatchMessage( @uMsg )
		
	Wend
	' ........................................................................................
	Select Case Cast(Integer, LoWord (uMsg.wParam))
		Case IDCONTINUE, IDCANCEL, IDRETRY, MB_TIMEDOUT, IDCONTINUE
			iReturnValue = Cast(Long, LoWord (uMsg.wParam))
			
		Case Else
			iReturnValue = MB_TIMEDOUT
			
	End Select
	
	Sleep(333,1)
	' ----------------------------------------------------------------------------------------
	If nTimerIDEvent <> 0 Then KillTimer(hWndMain, nTimerIDEvent)
	
	DestroyWindow(hWndMain)
	
	Deallocate(sClassNameW)
	Deallocate(sTitleNameW)
	
	Function = iReturnValue
End Function
' =============================================================================================
Function _WndProc(ByVal hWnd AS HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As LRESULT

	Select Case uMsg
		Case WM_DESTROY
			 Return 0
		
		Case WM_CLOSE
			PostMessage(hWnd,WM_QUIT,Cast(wParam, MB_TIMEDOUT),lParam)	:	Return 0
		
	End Select

	Return DefWindowProcW(hWnd, uMsg, wParam, lParam)
End Function
' =============================================================================================
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

Re: Avif image - read/convert to dibitmap

Post by Iczer »

problem was - freeimage expects raw images/byte arrays in ARGB format but image was in RGBA, color masks dont work for some reason (or maybe it i'm not doing it right...). Anyway, this works for 8bit per channel images:

Code: Select all

Function Preview_AVIF(ByVal pwsPathTo_ImageToShow As WString Ptr, ByVal hWndMain As HWND, ByVal hPicFrame As HWND, ByRef iPic_WMax As Long, ByRef iPic_HMax As Long) As Long
	'-----------------------------------------------------------------------------------------
	
	'-----------------------------------------------------------------------------------------
	Dim As avifResult result
	Dim As avifDecoder Ptr decoder = avifIOCreateImageDecoderU(pwsPathTo_ImageToShow)
	Dim As avifRGBImage _rgb
	
	Dim As ULong iBPP, iRetVal, c = 0
	Dim As Long iPic_RatioMax, iPic_Ratio, iPic_W, iPic_H, iPic_WNew, iPic_HNew
	Dim As Double dblPic_W, dblPic_H, dblPic_WNew, dblPic_HNew, dblPic_WMax, dblPic_HMax, dblPic_Ratio, dblPic_RatioMax
	
	If decoder <> NULL Then
		result = avifDecoderParse(decoder)
		If result = AVIF_RESULT_OK Then
			'-----------------------------------------------------------------------------------------
			While avifDecoderNextImage(decoder) = AVIF_RESULT_OK
				avifRGBImageSetDefaults(@_rgb, decoder->image)
				avifRGBImageAllocatePixels(@_rgb)
				avifImageYUVToRGB(decoder->image, @_rgb)
			Wend
			'-----------------------------------------------------------------------------------------
			Dim As ULong red_mask, green_mask, blue_mask
			Dim As ULongInt index = 0, length
			Dim As UByte Ptr bytes = 0
			
			red_mask = &h00FF0000 : green_mask = &h0000FF00 : blue_mask = &h000000FF
			
			Select Case As Const _rgb.Format'			FreeImage expects ARGB
				' .....................................................................................
				Case AVIF_RGB_FORMAT_RGB
					iBPP = 3 * _rgb.depth : red_mask = &hFF0000		: green_mask = &h00FF00		: blue_mask = &h0000FF
					
					length = decoder->image->Width * decoder->image->height * (iBPP/8)
					bytes = Allocate(length)
					While index < length
						bytes[index]     = _rgb.pixels[index + 2]'  //B
						bytes[index + 1] = _rgb.pixels[index + 1]'  //G
						bytes[index + 2] = _rgb.pixels[index]'      //R
						index += 3 * k
					Wend
					' .....................................................................................
				Case AVIF_RGB_FORMAT_RGBA
					iBPP = 4 * k : red_mask = &hFF000000	: green_mask = &h00FF0000	: blue_mask = &h0000FF00
					
					length = decoder->image->Width * decoder->image->height * (iBPP/8)
					bytes = Allocate(length)
					While index < length
						bytes[index]     = _rgb.pixels[index + 2]'  //B
						bytes[index + 1] = _rgb.pixels[index + 1]'  //G
						bytes[index + 2] = _rgb.pixels[index]'      //R
						bytes[index + 3] = _rgb.pixels[index + 3]'  //A
						index += 4 * k
					Wend
					' .....................................................................................
				Case AVIF_RGB_FORMAT_ARGB
					iBPP = 4 * _rgb.depth : red_mask = &h00FF0000	: green_mask = &h0000FF00	: blue_mask = &h000000FF
					' .....................................................................................
				Case AVIF_RGB_FORMAT_BGR
					iBPP = 3 * _rgb.depth : red_mask = &h0000FF		: green_mask = &h00FF00		: blue_mask = &hFF0000
					
					length = decoder->image->Width * decoder->image->height * (iBPP/8)
					bytes = Allocate(length)
					While index < length
						bytes[index]     = _rgb.pixels[index]'      //R
						bytes[index + 1] = _rgb.pixels[index + 1]'  //G
						bytes[index + 2] = _rgb.pixels[index + 2]'  //B
						index += 3 * k
					Wend
					' .....................................................................................
				Case AVIF_RGB_FORMAT_BGRA
					iBPP = 4 * _rgb.depth : red_mask = &h0000FF00	: green_mask = &h00FF0000	: blue_mask = &hFF000000
					
					length = decoder->image->Width * decoder->image->height * (iBPP/8)
					bytes = Allocate(length)
					While index < length
						bytes[index]     = _rgb.pixels[index]'      //R
						bytes[index + 1] = _rgb.pixels[index + 1]'  //G
						bytes[index + 2] = _rgb.pixels[index + 2]'  //B
						bytes[index + 3] = _rgb.pixels[index + 3]'  //A
						index += 4 * k
					Wend
					' .....................................................................................
				Case AVIF_RGB_FORMAT_ABGR
					iBPP = 4 * _rgb.depth : red_mask = &h000000FF	: green_mask = &h0000FF00	: blue_mask = &h00FF0000
					' .....................................................................................
			End Select
			'-----------------------------------------------------------------------------------------
			iPic_H = decoder->image->height
			iPic_W = decoder->image->Width
			
			dblPic_WNew = CDbl(iPic_W)
			dblPic_HNew = CDbl(iPic_H)
			dblPic_Ratio = dblPic_WNew/dblPic_HNew
			
			dblPic_WMax = CDbl(iPic_WMax)
			dblPic_HMax = CDbl(iPic_HMax)
			dblPic_RatioMax = dblPic_WMax/dblPic_HMax
			
			If dblPic_WNew > dblPic_WMax Then
				dblPic_WNew = dblPic_WMax
				dblPic_HNew = dblPic_WMax/dblPic_Ratio
			EndIf
			
			If dblPic_HNew > dblPic_HMax Then
				dblPic_WNew = dblPic_HMax*dblPic_Ratio
				dblPic_HNew = dblPic_HMax
			EndIf
			
			iPic_WNew =	CLng(dblPic_WNew)
			iPic_HNew = CLng(dblPic_HNew)
			'-----------------------------------------------------------------------------------------
			Dim As FIBITMAP Ptr hImageOriginal, hImageResized, hImageResized2
			Dim As FREE_IMAGE_FORMAT ImageFIF
			Dim As HDC hDC
			Dim As HBITMAP hDIB
			Dim As Long pitch = _rgb.rowBytes
			Dim As Boolean topdown = TRUE
			' .....................................................................................
			If bytes = 0 Then
				hImageOriginal = FreeImage_ConvertFromRawBits(_rgb.pixels,iPic_W, _
																							 iPic_H, _
																							 pitch, _
																							 iBPP, _
																							 red_mask, green_mask, blue_mask, topdown)
			Else
				hImageOriginal = FreeImage_ConvertFromRawBits(bytes,iPic_W, _
																					 iPic_H, _
																					 pitch, _
																					 iBPP, _
																					 red_mask, green_mask, blue_mask, topdown)
			EndIf
			'-----------------------------------------------------------------------------------------
			hImageResized = FreeImage_Rescale(hImageOriginal, iPic_WNew, iPic_HNew, FILTER_CATMULLROM)' FILTER_LANCZOS3
			
			iBPP = FreeImage_GetBPP(hImageResized)
			
			If iBPP >= 32 Then
				hImageResized2 = FreeImage_ConvertTo24Bits(hImageResized)
				
				If hImageResized <> 0 Then
					FreeImage_Unload(hImageResized)
				EndIf
				
				hImageResized = hImageResized2
			EndIf
			
			If hImageOriginal <> 0 Then
				FreeImage_Unload(hImageOriginal)
			EndIf
			
			If bytes <> 0 Then
				DeAllocate(bytes)
			EndIf
			'-----------------------------------------------------------------------------------------
			hDC = GetDC(hWndMain)
			
			hDIB = CreateDIBitmap(hDC,FreeImage_GetInfoHeader(hImageResized), CBM_INIT, FreeImage_GetBits(hImageResized), FreeImage_GetInfo(hImageResized), 0)
			
			ReleaseDC(hWndMain, hDC)
			
			DeleteObject(Cast(HANDLE, SendMessage(hPicFrame, STM_SETIMAGE, Cast(WPARAM, IMAGE_BITMAP), Cast(LPARAM, hDIB))))
			
			If hImageResized <> 0 Then
				FreeImage_Unload(hImageResized)
			EndIf
			'-----------------------------------------------------------------------------------------
		EndIf
	EndIf
	'-----------------------------------------------------------------------------------------
	avifRGBImageFreePixels(@_rgb)
	avifDecoderDestroy(decoder)
	'-----------------------------------------------------------------------------------------
	Return 0
	'-----------------------------------------------------------------------------------------
End Function
But what to do with 10 or more bits per channel images? I need to downscale them to 8 bit before feeding them to freeimage, but this not work:

Code: Select all

					If _rgb.depth > 8 Then
						
						length = decoder->image->Width * decoder->image->height * (iBPP/8)
						bytes = Allocate(length)
						
						For i As UInteger = 0 To decoder->image->Width * decoder->image->height
							bytes[index]     = Cast(UByte, CPtr(Short Ptr,_rgb.pixels)[index + 2]/256)'  //B
							bytes[index + 1] = Cast(UByte, CPtr(Short Ptr,_rgb.pixels)[index + 1]/256)'  //G
							bytes[index + 2] = Cast(UByte, CPtr(Short Ptr,_rgb.pixels)[index]/256)'      //R
							bytes[index + 3] = Cast(UByte, CPtr(Short Ptr,_rgb.pixels)[index + 3]/256)'  //A
						Next
					EndIf
@UEZ can you see into problem?
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Avif image - read/convert to dibitmap

Post by UEZ »

I cannot run your code but this is what I did so far.

avif.bi

Code: Select all

'Coded by UEZ build 2022-05-27
#Ifdef __Fb_64bit__
	#Inclib "gdiplus"
    #Include Once "win/gdiplus-c.bi"
#Else
    #Include Once "win/gdiplus.bi"
    Using gdiplus
#Endif
#Include "fbgfx.bi"
Using FB

#Define AVIF_API
Const AVIF_VERSION_MAJOR = 0
Const AVIF_VERSION_MINOR = 10
Const AVIF_VERSION_PATCH = 1
Const AVIF_VERSION_DEVEL = 1
Const AVIF_VERSION = (((AVIF_VERSION_MAJOR * 1000000) + (AVIF_VERSION_MINOR * 10000)) + (AVIF_VERSION_PATCH * 100)) + AVIF_VERSION_DEVEL
Type avifBool As Long
Const AVIF_TRUE = 1
Const AVIF_FALSE = 0
Const AVIF_DIAGNOSTICS_ERROR_BUFFER_SIZE = 256
Const AVIF_DEFAULT_IMAGE_SIZE_LIMIT = 16384 * 16384
Const AVIF_DEFAULT_IMAGE_COUNT_LIMIT = (12 * 3600) * 60
Const AVIF_QUANTIZER_LOSSLESS = 0
Const AVIF_QUANTIZER_BEST_QUALITY = 0
Const AVIF_QUANTIZER_WORST_QUALITY = 63
Const AVIF_PLANE_COUNT_YUV = 3
Const AVIF_SPEED_DEFAULT = -1
Const AVIF_SPEED_SLOWEST = 0
Const AVIF_SPEED_FASTEST = 10

Type avifPlanesFlag As Long
Enum
	AVIF_PLANES_YUV = 1 Shl 0
	AVIF_PLANES_A = 1 Shl 1
	AVIF_PLANES_ALL = &hff
End Enum

Type avifPlanesFlags As Ulong

Type avifChannelIndex As Long
Enum
	AVIF_CHAN_R = 0
	AVIF_CHAN_G = 1
	AVIF_CHAN_B = 2
	AVIF_CHAN_Y = 0
	AVIF_CHAN_U = 1
	AVIF_CHAN_V = 2
End Enum

Type avifResult As Long
Enum
	AVIF_RESULT_OK = 0
	AVIF_RESULT_UNKNOWN_ERROR
	AVIF_RESULT_INVALID_FTYP
	AVIF_RESULT_NO_CONTENT
	AVIF_RESULT_NO_YUV_FORMAT_SELECTED
	AVIF_RESULT_REFORMAT_FAILED
	AVIF_RESULT_UNSUPPORTED_DEPTH
	AVIF_RESULT_ENCODE_COLOR_FAILED
	AVIF_RESULT_ENCODE_ALPHA_FAILED
	AVIF_RESULT_BMFF_PARSE_FAILED
	AVIF_RESULT_NO_AV1_ITEMS_FOUND
	AVIF_RESULT_DECODE_COLOR_FAILED
	AVIF_RESULT_DECODE_ALPHA_FAILED
	AVIF_RESULT_COLOR_ALPHA_SIZE_MISMATCH
	AVIF_RESULT_ISPE_SIZE_MISMATCH
	AVIF_RESULT_NO_CODEC_AVAILABLE
	AVIF_RESULT_NO_IMAGES_REMAINING
	AVIF_RESULT_INVALID_EXIF_PAYLOAD
	AVIF_RESULT_INVALID_IMAGE_GRID
	AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION
	AVIF_RESULT_TRUNCATED_DATA
	AVIF_RESULT_IO_NOT_SET
	AVIF_RESULT_IO_ERROR
	AVIF_RESULT_WAITING_ON_IO
	AVIF_RESULT_INVALID_ARGUMENT
	AVIF_RESULT_NOT_IMPLEMENTED
	AVIF_RESULT_OUT_OF_MEMORY
End Enum

Type avifROData
	Data As Const Ubyte Ptr
	size As Uinteger
End Type

Type avifRWData
	Data As Ubyte Ptr
	size As Uinteger
End Type

#Define AVIF_DATA_EMPTY (NULL, 0)

Type avifPixelFormat As Long
Enum
	AVIF_PIXEL_FORMAT_NONE = 0
	AVIF_PIXEL_FORMAT_YUV444
	AVIF_PIXEL_FORMAT_YUV422
	AVIF_PIXEL_FORMAT_YUV420
	AVIF_PIXEL_FORMAT_YUV400
End Enum

Type avifPixelFormatInfo
	monochrome As avifBool
	chromaShiftX As Long
	chromaShiftY As Long
End Type

Type avifChromaSamplePosition As Long
Enum
	AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN = 0
	AVIF_CHROMA_SAMPLE_POSITION_VERTICAL = 1
	AVIF_CHROMA_SAMPLE_POSITION_COLOCATED = 2
End Enum

Type avifRange As Long
Enum
	AVIF_RANGE_LIMITED = 0
	AVIF_RANGE_FULL = 1
End Enum

Enum
	AVIF_COLOR_PRIMARIES_UNKNOWN = 0
	AVIF_COLOR_PRIMARIES_BT709 = 1
	AVIF_COLOR_PRIMARIES_IEC61966_2_4 = 1
	AVIF_COLOR_PRIMARIES_UNSPECIFIED = 2
	AVIF_COLOR_PRIMARIES_BT470M = 4
	AVIF_COLOR_PRIMARIES_BT470BG = 5
	AVIF_COLOR_PRIMARIES_BT601 = 6
	AVIF_COLOR_PRIMARIES_SMPTE240 = 7
	AVIF_COLOR_PRIMARIES_GENERIC_FILM = 8
	AVIF_COLOR_PRIMARIES_BT2020 = 9
	AVIF_COLOR_PRIMARIES_XYZ = 10
	AVIF_COLOR_PRIMARIES_SMPTE431 = 11
	AVIF_COLOR_PRIMARIES_SMPTE432 = 12
	AVIF_COLOR_PRIMARIES_EBU3213 = 22
End Enum

Type avifColorPrimaries As Ushort
	
Enum
	AVIF_TRANSFER_CHARACTERISTICS_UNKNOWN = 0
	AVIF_TRANSFER_CHARACTERISTICS_BT709 = 1
	AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED = 2
	AVIF_TRANSFER_CHARACTERISTICS_BT470M = 4
	AVIF_TRANSFER_CHARACTERISTICS_BT470BG = 5
	AVIF_TRANSFER_CHARACTERISTICS_BT601 = 6
	AVIF_TRANSFER_CHARACTERISTICS_SMPTE240 = 7
	AVIF_TRANSFER_CHARACTERISTICS_LINEAR = 8
	AVIF_TRANSFER_CHARACTERISTICS_LOG100 = 9
	AVIF_TRANSFER_CHARACTERISTICS_LOG100_SQRT10 = 10
	AVIF_TRANSFER_CHARACTERISTICS_IEC61966 = 11
	AVIF_TRANSFER_CHARACTERISTICS_BT1361 = 12
	AVIF_TRANSFER_CHARACTERISTICS_SRGB = 13
	AVIF_TRANSFER_CHARACTERISTICS_BT2020_10BIT = 14
	AVIF_TRANSFER_CHARACTERISTICS_BT2020_12BIT = 15
	AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084 = 16
	AVIF_TRANSFER_CHARACTERISTICS_SMPTE428 = 17
	AVIF_TRANSFER_CHARACTERISTICS_HLG = 18
End Enum

Type avifTransferCharacteristics As Ushort

Enum
	AVIF_MATRIX_COEFFICIENTS_IDENTITY = 0
	AVIF_MATRIX_COEFFICIENTS_BT709 = 1
	AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED = 2
	AVIF_MATRIX_COEFFICIENTS_FCC = 4
	AVIF_MATRIX_COEFFICIENTS_BT470BG = 5
	AVIF_MATRIX_COEFFICIENTS_BT601 = 6
	AVIF_MATRIX_COEFFICIENTS_SMPTE240 = 7
	AVIF_MATRIX_COEFFICIENTS_YCGCO = 8
	AVIF_MATRIX_COEFFICIENTS_BT2020_NCL = 9
	AVIF_MATRIX_COEFFICIENTS_BT2020_CL = 10
	AVIF_MATRIX_COEFFICIENTS_SMPTE2085 = 11
	AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL = 12
	AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_CL = 13
	AVIF_MATRIX_COEFFICIENTS_ICTCP = 14
End Enum

Type avifMatrixCoefficients As Ushort

Type avifDiagnostics
	error As Zstring * 256
End Type

Type avifTransformFlag As Long
Enum
	AVIF_TRANSFORM_NONE = 0
	AVIF_TRANSFORM_PASP = 1 Shl 0
	AVIF_TRANSFORM_CLAP = 1 Shl 1
	AVIF_TRANSFORM_IROT = 1 Shl 2
	AVIF_TRANSFORM_IMIR = 1 Shl 3
End Enum

Type avifTransformFlags As Ulong

Type avifPixelAspectRatioBox
	hSpacing As Ulong
	vSpacing As Ulong
End Type

Type avifCleanApertureBox
	widthN As Ulong
	widthD As Ulong
	heightN As Ulong
	heightD As Ulong
	horizOffN As Ulong
	horizOffD As Ulong
	vertOffN As Ulong
	vertOffD As Ulong
End Type

Type avifImageRotation
	angle As Ubyte
End Type

Type avifImageMirror
	/''imir' from ISO/IEC 23008-12:2017 6.5.12 (Draft Amendment 2):	

     'mode' specifies how the mirroring is performed:

     0 indicates that the top and bottom parts of the image are exchanged;
     1 specifies that the left and right parts are exchanged.

     NOTE In Exif, orientation tag can be used to signal mirroring operations. Exif
     orientation tag 4 corresponds to mode = 0 of ImageMirror, and Exif orientation tag 2
     corresponds to mode = 1 accordingly.

	Legal values: [0, 1]

 NOTE: As of HEIF Draft Amendment 2, the name of this variable has changed from 'axis' to 'mode' as
       the logic behind it has been *inverted*. Please use the wording above describing the legal
       values for 'mode' and update any code that previously may have used `axis` to use
       the *opposite* value (0 now means top-to-bottom, where it used to mean left-to-right). '/
	mode As Ubyte
End Type

Type avifCropRect
	x As Ulong
	y As Ulong
	Width As Ulong
	height As Ulong
End Type

Type avifImage
	Width As Ulong
	height As Ulong
	depth As Ulong 'all planes must share this depth; if depth>8, all planes are uint16_t internall
	yuvFormat As avifPixelFormat
	yuvRange As avifRange
	yuvChromaSamplePosition As avifChromaSamplePosition
	yuvPlanes(0 To 2) As Ubyte Ptr
	yuvRowBytes(0 To 2) As Ulong
	imageOwnsYUVPlanes As avifBool
	alphaPlane As Ubyte Ptr
	alphaRowBytes As Ulong
	imageOwnsAlphaPlane As avifBool
	alphaPremultiplied As avifBool
	icc As avifRWData 'ICC Profile
	
	/'CICP information:	
	These are stored in the AV1 payload and used to signal YUV conversion. Additionally, if an	
	ICC profile is not specified, these will be stored in the AVIF container's `colr` box with	
	a type of `nclx`. If your system supports ICC profiles, be sure to check for the existence	
	of one (avifImage.icc) before relying on the values listed here! '/	
	colorPrimaries As avifColorPrimaries
	transferCharacteristics As avifTransferCharacteristics
	matrixCoefficients As avifMatrixCoefficients

	/'Transformations - These metadata values are encoded/decoded when transformFlags are set
	appropriately, but do not impact/adjust the actual pixel buffers used (images won't be
	pre-cropped or mirrored upon decode). Basic explanations from the standards are offered in
	comments above, but for detailed explanations, please refer to the HEIF standard (ISO/IEC
	23008-12:2017) and the BMFF standard (ISO/IEC 14496-12:2015).

	To encode any of these boxes, set the values in the associated box, then enable the flag in
	transformFlags. On decode, only honor the values in boxes with the associated transform flag set. '/
	transformFlags As avifTransformFlags
	pasp As avifPixelAspectRatioBox
	clap As avifCleanApertureBox
	irot As avifImageRotation
	imir As avifImageMirror
	exif As avifRWData 'Metadata - set with avifImageSetMetadata*() before write, check .size>0 for existence after read
	xmp As avifRWData
End Type

Type avifRGBFormat As Long
Enum
	AVIF_RGB_FORMAT_RGB = 0
	AVIF_RGB_FORMAT_RGBA
	AVIF_RGB_FORMAT_ARGB
	AVIF_RGB_FORMAT_BGR
	AVIF_RGB_FORMAT_BGRA
	AVIF_RGB_FORMAT_ABGR
End Enum

Type avifChromaUpsampling As Long
Enum
	AVIF_CHROMA_UPSAMPLING_AUTOMATIC = 0 'Chooses best trade off of speed/quality (prefers libyuv, else uses BEST_QUALITY)
	AVIF_CHROMA_UPSAMPLING_FASTEST = 1 'Chooses speed over quality (prefers libyuv, else uses NEAREST)
	AVIF_CHROMA_UPSAMPLING_BEST_QUALITY = 2 'hooses the best quality upsampling, given settings (avoids libyuv)
	AVIF_CHROMA_UPSAMPLING_NEAREST = 3 'Uses nearest-neighbor filter (built-in)
	AVIF_CHROMA_UPSAMPLING_BILINEAR = 4 'Uses bilinear filter (built-in)
End Enum

Type avifRGBImage
	Width As Ulong
	height As Ulong
	depth As Ulong
	format As avifRGBFormat 'all channels are always full range
	chromaUpsampling As avifChromaUpsampling 'Defaults to AVIF_CHROMA_UPSAMPLING_AUTOMATIC: How to upsample non-4:4:4 UV (ignored for 444) when converting to RGB. Unused when converting to YUV. avifRGBImageSetDefaults() prefers quality over speed.
	ignoreAlpha As avifBool 'Used for XRGB formats, treats formats containing alpha (such as ARGB) as if they were RGB, treating the alpha bits as if they were all 1.
	alphaPremultiplied As avifBool 'indicates if RGB value is pre-multiplied by alpha. Default: false
	isFloat As avifBool 'indicates if RGBA values are in half float (f16) format. Valid only when depth == 16. Default: false
	pixels As Ubyte Ptr
	rowBytes As Ulong
End Type

Type avifCodecChoice As Long
Enum
	AVIF_CODEC_CHOICE_AUTO = 0
	AVIF_CODEC_CHOICE_AOM
	AVIF_CODEC_CHOICE_DAV1D 'Decode only
	AVIF_CODEC_CHOICE_LIBGAV1 'Decode only
	AVIF_CODEC_CHOICE_RAV1E 'Encode only
	AVIF_CODEC_CHOICE_SVT 'Encode only
End Enum

Type avifCodecFlag As Long
Enum
	AVIF_CODEC_FLAG_CAN_DECODE = 1 Shl 0
	AVIF_CODEC_FLAG_CAN_ENCODE = 1 Shl 1
End Enum

Type avifCodecFlags As Ulong

Type avifCodecConfigurationBox
	seqProfile As Ubyte
	seqLevelIdx0 As Ubyte
	seqTier0 As Ubyte
	highBitdepth As Ubyte
	twelveBit As Ubyte
	monochrome As Ubyte
	chromaSubsamplingX As Ubyte
	chromaSubsamplingY As Ubyte
	chromaSamplePosition As Ubyte
End Type

Type avifIO As avifIO_
Type avifIODestroyFunc As Sub(Byval io As avifIO Ptr)
Type avifIOReadFunc As Function(Byval io As avifIO Ptr, Byval readFlags As Ulong, Byval offset As Ulongint, Byval size As Uinteger, Byval Out As avifROData Ptr) As avifResult
Type avifIOWriteFunc As Function(Byval io As avifIO Ptr, Byval writeFlags As Ulong, Byval offset As Ulongint, Byval Data As Const Ubyte Ptr, Byval size As Uinteger) As avifResult

Type avifIO_
	destroy As avifIODestroyFunc
	read As avifIOReadFunc
	write As avifIOWriteFunc 'This is reserved for future use - but currently ignored. Set it to a null pointer.

	/'If non-zero, this is a hint to internal structures of the max size offered by the content
	this avifIO structure is reading. If it is a static memory source, it should be the size of
	the memory buffer; if it is a file, it should be the file's size. If this information cannot
	be known (as it is streamed-in), set a reasonable upper boundary here (larger than the file
	can possibly be for your environment, but within your environment's memory constraints). This
	is used for sanity checks when allocating internal buffers to protect against
	malformed/malicious files.'/
	sizeHint As Ulongint
	
	/'If true, *all* memory regions returned from *all* calls to read are guaranteed to be	
	persistent and exist for the lifetime of the avifIO object. If false, libavif will make	
	in-memory copies of samples and metadata content, and a memory region returned from read must	
	only persist until the next call to read.'/
	persistent As avifBool
	
	/'The contents of this are defined by the avifIO implementation, and should be fully destroyed	
	by the implementation of the associated destroy function, unless it isn't owned by the avifIO	
	struct. It is not necessary to use this pointer in your implementation.'/
	data As Any Ptr
End Type

Type avifStrictFlag As Long
Enum
	AVIF_STRICT_DISABLED = 0
	AVIF_STRICT_PIXI_REQUIRED = 1 Shl 0
	AVIF_STRICT_CLAP_VALID = 1 Shl 1
	AVIF_STRICT_ALPHA_ISPE_REQUIRED = 1 Shl 2
	AVIF_STRICT_ENABLED = (AVIF_STRICT_PIXI_REQUIRED Or AVIF_STRICT_CLAP_VALID) Or AVIF_STRICT_ALPHA_ISPE_REQUIRED
End Enum

Type avifStrictFlags As Ulong
Type avifEncoderData As Ulong
Type avifDecoderData As Ulong
Type avifCodecSpecificOptions As Ulong

Type avifIOStats
	colorOBUSize As Uinteger
	alphaOBUSize As Uinteger
End Type

Type avifDecoderSource As Long
Enum
	AVIF_DECODER_SOURCE_AUTO = 0
	AVIF_DECODER_SOURCE_PRIMARY_ITEM
	AVIF_DECODER_SOURCE_TRACKS
End Enum

Type avifImageTiming
	timescale As Ulongint 'timescale of the media (Hz)
	pts As Double 'presentation timestamp in seconds (ptsInTimescales / timescale)
	ptsInTimescales As Ulongint	'presentation timestamp in "timescales"
	duration As Double 'in seconds (durationInTimescales / timescale)
	durationInTimescales As Ulongint 'duration in "timescales"
End Type

Type avifProgressiveState As Long
Enum
	AVIF_PROGRESSIVE_STATE_UNAVAILABLE = 0
	AVIF_PROGRESSIVE_STATE_AVAILABLE
	AVIF_PROGRESSIVE_STATE_ACTIVE
End Enum

Type avifDecoder
	codecChoice As avifCodecChoice
	maxThreads As Long
	requestedSource As avifDecoderSource
	allowProgressive As avifBool
	allowIncremental As avifBool
	ignoreExif As avifBool
	ignoreXMP As avifBool
	imageSizeLimit As Ulong
	imageCountLimit As Ulong
	strictFlags As avifStrictFlags
	image As avifImage Ptr
	imageIndex As Long
	imageCount As Long
	progressiveState As avifProgressiveState
	imageTiming As avifImageTiming
	timescale As Ulongint
	duration As Double
	durationInTimescales As Ulongint
	alphaPresent As avifBool
	ioStats As avifIOStats
	diag As avifDiagnostics
	io As avifIO Ptr
	data As avifDecoderData Ptr
End Type

Type avifExtent
	offset As Ulongint
	size As Uinteger
End Type

Type avifEncoder
	codecChoice As avifCodecChoice
	maxThreads As Long
	minQuantizer As Long
	maxQuantizer As Long
	minQuantizerAlpha As Long
	maxQuantizerAlpha As Long
	tileRowsLog2 As Long
	tileColsLog2 As Long
	speed As Long
	keyframeInterval As Long
	timescale As Ulongint
	ioStats As avifIOStats
	diag As avifDiagnostics
	data As avifEncoderData Ptr
	csOptions As avifCodecSpecificOptions Ptr
End Type

Type avifAddImageFlag As Long
Enum
	AVIF_ADD_IMAGE_FLAG_NONE = 0
	AVIF_ADD_IMAGE_FLAG_FORCE_KEYFRAME = 1 Shl 0
	AVIF_ADD_IMAGE_FLAG_SINGLE = 1 Shl 1
End Enum

Type avifAddImageFlags As Ulong	
	
Extern "c"
Declare Function avifResultToString Alias "avifResultToString" (Byval result As avifResult) As Const Zstring Ptr
Declare Function avifDecoderCreate Alias "avifDecoderCreate" () As avifDecoder Ptr
Declare Function avifDecoderSetIOFile Alias "avifDecoderSetIOFile" (Byval decoder As avifDecoder Ptr, Byval filename As Const Zstring Ptr) As avifResult
Declare Function avifDecoderSetIOMemory Alias "avifDecoderSetIOMemory" (Byval decoder As avifDecoder Ptr, Byval Data As Const Ubyte Ptr, Byval size As Uinteger) As avifResult
Declare Function avifDecoderParse Alias "avifDecoderParse" (Byval decoder As avifDecoder Ptr) As avifResult
Declare Function avifDecoderNextImage Alias "avifDecoderNextImage" (byval decoder as avifDecoder Ptr) As avifResult
Declare Sub avifDecoderDestroy Alias "avifDecoderDestroy" (Byval decoder As avifDecoder Ptr)

Declare Sub avifRGBImageSetDefaults Alias "avifRGBImageSetDefaults" (Byval Rgb As avifRGBImage Ptr, Byval image As Const avifImage Ptr)
Declare Sub avifRGBImageAllocatePixels Alias "avifRGBImageAllocatePixels" (Byval Rgb As avifRGBImage Ptr)
Declare Function avifImageYUVToRGB Alias "avifImageYUVToRGB" (Byval image As Const avifImage Ptr, Byval Rgb As avifRGBImage Ptr) As avifResult
Declare Sub avifRGBImageFreePixels Alias "avifRGBImageFreePixels" (Byval Rgb As avifRGBImage Ptr)
Declare Function avifImageCreate Alias "avifImageCreate" (Byval Width As Long, Byval height As Long, Byval depth As Long, Byval yuvFormat As avifPixelFormat) As avifImage Ptr
Declare Sub avifImageAllocatePlanes Alias "avifImageCreate" (Byval image As avifImage Ptr, Byval planes As avifPlanesFlags)
Declare Function avifImageRGBToYUV Alias "avifImageRGBToYUV" (Byval image As avifImage Ptr, Byval Rgb As Const avifRGBImage Ptr) As avifResult
Declare Sub avifImageDestroy Alias "avifImageDestroy" (Byval image As avifImage Ptr)
Declare Sub avifRWDataFree Alias "avifRWDataFree" (Byval raw As avifRWData Ptr)

Declare Function avifEncoderAddImage Alias "avifEncoderAddImage" (Byval encoder As avifEncoder Ptr, Byval image As Const avifImage Ptr, Byval durationInTimescales As Ulongint, Byval addImageFlags As avifAddImageFlags) As avifResult
Declare Function avifEncoderFinish Alias "avifEncoderFinish" (Byval encoder As avifEncoder Ptr, Byval Output As avifRWData Ptr) As avifResult
Declare Sub avifEncoderDestroy Alias "avifEncoderDestroy" (Byval encoder As avifEncoder Ptr)
Declare Function avifEncoderCreate Alias "avifEncoderCreate" () As avifEncoder Ptr
End Extern

Dim Shared gdipToken As ULONG_PTR
Dim Shared GDIp As GdiplusStartupInput 

Private Function _GDIPlus_Startup() As Bool
	GDIp.GdiplusVersion = 1
	If GdiplusStartup(@gdipToken, @GDIp, NULL) <> 0 Then
		Error 1
		Return False
	Endif
	Return True
End Function

Private Sub _GDIPlus_Shutdown()
	GdiplusShutdown(gdipToken)
End Sub

Private Function AVIF_BitmapCreateGDIp_internal(pRgba As Ubyte Ptr, w As Long, h As Long, bGDI As Bool = False) As Any Ptr
	Dim hBitmap As Any Ptr
	Dim As Rect tRect = Type(0, 0, w - 1, h - 1)
	Dim As BitmapData tBitmapData
	Dim As Integer i = 0, ub = (w * h)
	GdipCreateBitmapFromScan0(w, h, 0, PixelFormat32bppARGB, 0, @hBitmap)
	GdipBitmapLockBits(hBitmap, Cast(Any Ptr, @tRect), ImageLockModeWrite, PixelFormat32bppARGB, @tBitmapData)
	Dim As Ulong c
	While i < ub
		c = Cast(ULong Ptr, pRgba)[i]
		Cast(ULong Ptr, tBitmapData.Scan0)[i] = c And &hFF000000 Or ((c And &h000000FF) Shl 16) Or c And &h00FF00 Or ((c And &h00FF0000) Shr 16) 'ABGR
		i += 1
	Wend
	GdipBitmapUnlockBits(hBitmap, @tBitmapData)
	If bGDI Then
		Dim As HBITMAP hGDIBitmap
		GdipCreateHBITMAPFromBitmap(hBitmap, @hGDIBitmap, &hFF000000)
		GdipDisposeImage(hBitmap)
		Return hGDIBitmap
	Endif
	Return hBitmap
End Function

Private Sub Display_GDIpImage(hImage As Any Ptr, w As long, h As Long)
	ScreenControl SET_DRIVER_NAME, "GDI"
	ScreenRes w, h, 32, 1, GFX_HIGH_PRIORITY Or GFX_NO_SWITCH
	Dim as HWND hHWND
	ScreenControl(GET_WINDOW_HANDLE, Cast(Integer, hHWND))
	Dim As Any Ptr hCanvas, hDC = GetDC(hHWND), hDC_backbuffer = CreateCompatibleDC(hDC), hHBitmap = CreateCompatibleBitmap(hDC, w, h)
	Var hObjOld = SelectObject(hDC_backbuffer, hHBitmap)
	GdipCreateFromHDC(hDC_backbuffer, @hCanvas)
	GdipDrawImageRect(hCanvas, hImage, 0, 0, w, h)
	Do
		BitBlt(hDC, 0, 0, w, h, hDC_backbuffer, 0, 0, SRCCOPY)
		Sleep(10)
	Loop Until Len(Inkey())
	GdipDeleteGraphics(hCanvas)
	SelectObject(hDC_backbuffer, hObjOld)
	DeleteDC(hDC_backbuffer)
	ReleaseDC(hHWND, hDC)
	DeleteObject(hHBitmap)
End Sub

Example.bas

Code: Select all

'Coded by UEZ build 2022-05-26 beta
'must be compiled as x86

#include "file.bi"
#Inclib "avif"
#Include "../avif.bi"

Dim As String inputFilename = "..\kodim23_yuv420_8bpc.avif"
Dim As avifRGBImage _rgb
Dim As avifDecoder Ptr decoder = avifDecoderCreate()
decoder->strictFlags = AVIF_STRICT_DISABLED
decoder->maxThreads = 2

Dim As avifResult result = avifDecoderSetIOFile(decoder, inputFilename)

'Dim As Integer hFile, iFileSize = Filelen(inputFilename)
'Dim pMem As Ubyte Ptr
'pMem = Allocate(iFileSize)
'hFile = Freefile()
'Open inputFilename For Binary Access Read As #hFile
'Get #hFile, 0, pMem[0], iFileSize
'Close #hFile
'Dim As avifResult result = avifDecoderSetIOMemory(decoder, pMem, iFileSize)

_GDIPlus_Startup()

If result = AVIF_RESULT_OK Then
	result = avifDecoderParse(decoder)
	If result = AVIF_RESULT_OK Then
		? "width: " & decoder->image->width, "height: " & decoder->image->height, "bits per channel = " & decoder->image->depth
		Dim As Ulong c = 0
		While avifDecoderNextImage(decoder) = AVIF_RESULT_OK
			avifRGBImageSetDefaults(@_rgb, decoder->image)
			avifRGBImageAllocatePixels(@_rgb)
			avifImageYUVToRGB(decoder->image, @_rgb)
			c += 1
		Wend
		Dim As Any Ptr hBitmap = AVIF_BitmapCreateGDIp_internal(_rgb.pixels, decoder->image->width, decoder->image->height)
		Display_GDIpImage(hBitmap, decoder->image->width, decoder->image->height)
	Else
		? "Error = " & result & " / Failed to decode image -> " & *avifResultToString(result)
	Endif
Else
	? "Error = " & result & " / Cannot open file for read -> " & *avifResultToString(result)
End If

avifRGBImageFreePixels(@_rgb)
avifDecoderDestroy(decoder)
'Deallocate(pMem)
_GDIPlus_Shutdown()
Sleep
Post Reply