Code: Select all
'coded by UEZ build 2017-11-27
#define WIN_INCLUDEALL
#include once "windows.bi"
#Include Once "win/gdiplus.bi"
Using GDIPLUS
Declare Function FileOpenDialog (Byref sTitle As String, Byref sDir As String = CurDir, sFilter As String = !"All Files (*.*)" + Chr(0) + "*.*" + Chr(0, 0)) As String
Declare Function _GDIPlus_ImageCountColors32(himage as any Ptr) as uInteger
Declare Function _GDIPlus_ImageCountColors24(himage as any Ptr) as UInteger
Declare function _GDIPlus_ImageCountColorsAccurat(himage as any Ptr) as uInteger
Declare function _GDIPlus_ImageCountColors24ASM(himage as any Ptr) as uInteger
Declare Function _GDIPlus_ImageGetPixelFormat(hImage as any ptr) as UInteger
Declare Sub Quicksort(Array() As uinteger, iStart As uinteger, iEnd As uinteger)
Function _GDIPlus_ImageCountColors32(himage as any Ptr) as uInteger 'slower variant but full 32-bit support
Dim As Single iW, iH, iPixel, iRowOffset
GdipGetImageDimension(hImage, @iW, @iH)
Dim As BitmapData tBitmapData
Dim As Rect tRect = Type(0, 0, iW - 1, iH - 1)
Dim as uinteger aColors(0 to iW * iH), c = 0, iX, iY
? "Image dimension: " & iW & "x" & iH
? "Counting all 32-bit colors"
_GDIPlus_ImageGetPixelFormat(hImage)
GdipBitmapLockBits(hImage, Cast(Any Ptr, @tRect), ImageLockModeRead, PixelFormat32bppARGB, @tBitmapData)
For iY = 0 To iH - 1
iRowOffset = iY * iW
For iX = 0 To iW - 1
aColors(c) = Cast(uInteger Ptr, tBitmapData.Scan0)[iRowOffset + iX]
c += 1
Next
Next
GdipBitmapUnlockBits(hImage, @tBitmapData)
? "Sorting color array"
QuickSort(aColors(), 0, c - 1)
? "Counting unique colors"
c = 0
For iY = 0 to Ubound(aColors) - 2
If aColors(iY) > aColors(iY + 1) Then c += 1
Next
Return c
End Function
Function _GDIPlus_ImageCountColors24(himage as any Ptr) as uInteger
Dim As Single iW, iH, iPixel, iRowOffset
GdipGetImageDimension(hImage, @iW, @iH)
Dim As BitmapData tBitmapData
Dim As Rect tRect = Type(0, 0, iW - 1, iH - 1)
Dim as uInteger c = 0, iX, iY
Dim as UlongInt iColor
Dim as Ubyte aColors()
Redim aColors(0 to 256^3 + 1)
? "Image dimension: " & iW & "x" & iH
? "Counting all 24-bit colors"
GdipBitmapLockBits(hImage, Cast(Any Ptr, @tRect), ImageLockModeRead, PixelFormat32bppRGB, @tBitmapData)
For iY = 0 To iH - 1
iRowOffset = iY * iW
For iX = 0 To iW - 1
iColor = Cast(uInteger Ptr, tBitmapData.Scan0)[iRowOffset + iX] and &h00FFFFFF 'read and make color value 24-bit
If aColors(iColor) = 0 Then
c += 1
aColors(iColor) = 1
Endif
Next
Next
GdipBitmapUnlockBits(hImage, @tBitmapData)
Return c
End Function
function _GDIPlus_ImageCountColorsAccurat(himage as any Ptr) as uInteger 'very very slow!
Dim As Single iW, iH, iPixel, iRowOffset
GdipGetImageDimension(hImage, @iW, @iH)
Dim As BitmapData tBitmapData
Dim As Rect tRect = Type(0, 0, iW - 1, iH - 1)
Dim as uinteger aColors(0 to iW * iH), iColor, c = 0, p = 0, iX, iY, iYY
Dim as Boolean bFound
? "Image dimension: " & iW & "x" & iH
? "Counting all 32-bit colors"
_GDIPlus_ImageGetPixelFormat(hImage)
GdipBitmapLockBits(hImage, Cast(Any Ptr, @tRect), ImageLockModeRead, PixelFormat32bppARGB, @tBitmapData)
For iY = 0 To iH - 1
iRowOffset = iY * iW
For iX = 0 To iW - 1
iColor = Cast(uInteger Ptr, tBitmapData.Scan0)[iRowOffset + iX]
bFound = False
For iYY = 0 to p
If iColor = aColors(iYY) Then
bFound = true
Exit For
End If
Next
If Not bFound then
aColors(p) = iColor
p += 1
c += 1
End if
Next
Next
GdipBitmapUnlockBits(hImage, @tBitmapData)
Return c
End Function
Function _GDIPlus_ImageCountColors24ASM(himage as any Ptr) as uInteger
Dim As Single iW, iH, iPixel
GdipGetImageDimension(hImage, @iW, @iH)
Dim As BitmapData tBitmapData
Dim As Rect tRect = Type(0, 0, iW - 1, iH - 1)
Dim as uInteger c = 0, iX, iY, iPixels = iW * iH
Dim as Byte aColors()
Redim aColors(0 to 256^3 + 1)
? "Image dimension: " & iW & "x" & iH
? "Counting all 24-bit colors"
GdipBitmapLockBits(hImage, Cast(Any Ptr, @tRect), ImageLockModeRead, PixelFormat32bppARGB, @tBitmapData)
Dim As Any Ptr pBmp = Cast(Any Ptr, tBitmapData.scan0)
Dim As Byte Ptr pColors = Cast(Byte Ptr, @aColors(0))
Asm
mov esi, [pBmp]
mov ecx, [iPixels]
mov edi, [pColors]
Xor eax, eax
_Pixel_Count:
mov ebx, [esi]
and ebx, &hFFFFFF
cmp Byte Ptr [edi + ebx], 1
je _Next
inc eax
mov Byte Ptr [edi + ebx], 1
_Next:
add esi, 4
dec ecx
jnz _Pixel_Count
mov [c], eax
End Asm
GdipBitmapUnlockBits(hImage, @tBitmapData)
Return c
End Function
Function _GDIPlus_ImageGetPixelFormat(hImage as any ptr) as UInteger
Dim as UInteger iFormat
GdipGetImagePixelFormat(hImage, @iFormat)
Return iFormat
End Function
'https://en.wikibooks.org/wiki/Algorithm_Implementation/Sorting/Quicksort
Sub Quicksort(Array() As uinteger, iStart As uinteger, iEnd As uinteger)
Dim As uInteger i = iStart, j = iEnd, iPivot = Array((i + j) Shr 1)
While i <= j
While Array(i) > iPivot
i += 1
Wend
While Array(j) < iPivot
j -= 1
Wend
If i <= j Then
Swap Array(i), Array(j)
i += 1
j -= 1
End if
Wend
If j > iStart Then Quicksort(Array(), iStart, j)
If i < iEnd Then Quicksort(Array(), i, iEnd)
End Sub
'code by KristopherWindsor -> https://www.freebasic.net/forum/viewtopic.php?f=7&t=10981&hilit=FileOpenDialog
Function FileOpenDialog (Byref sTitle As String, Byref sDir As String = CurDir, sFilter As String = !"All Files (*.*)" + Chr(0) + "*.*" + Chr(0, 0)) As String
Dim oFilename As OPENFILENAME
Dim sFilename As Zstring * (MAX_PATH + 1)
Dim Title As Zstring * 32 => sTitle
Dim sInitialDir As Zstring * 256 => sDir
With oFilename
.lStructSize = SizeOf(OPENFILENAME)
.hwndOwner = NULL
.hInstance = GetModuleHandle(NULL)
'"All Files, (*.*)"
'"*.*"
'"Bas Files, (*.BAS)"
'"*.bas"
'.lpstrFilter = Strptr(!"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0\0")
.lpstrFilter = Strptr(sFilter)
.lpstrCustomFilter = NULL
.nMaxCustFilter = 0
.nFilterIndex = 1
.lpstrFile = @sFilename
.nMaxFile = SizeOf(sFilename)
.lpstrFileTitle = NULL
.nMaxFileTitle = 0
.lpstrInitialDir = @sInitialDir
.lpstrTitle = @Title
.Flags = OFN_EXPLORER Or OFN_FILEMUSTEXIST Or OFN_PATHMUSTEXIST
.nFileOffset = 0
.nFileExtension = 0
.lpstrDefExt = NULL
.lCustData = 0
.lpfnHook = NULL
.lpTemplateName = NULL
End With
If (GetOpenFileName(@oFilename) = FALSE) Then Return ""
Return sFilename
End Function
Dim GDIPlusStartupInput As GDIPLUSSTARTUPINPUT
Dim As ULONG_PTR GDIPlusToken
GDIPlusStartupInput.GdiplusVersion = 1
If (GdiplusStartup(@GDIPlusToken, @GDIPlusStartupInput, NULL) <> 0) Then
End 'FAILED TO INIT GDI+!
EndIf
Dim as String sImgFile
sImgFile = FileOpenDialog("Select an image file to load...", "", "Image Files (*.bmp;*.jpg;*.png;*.gif)" + Chr(0) + "*.bmp;*.jpg;*.png;*.gif" + Chr(0))
? "Loading image"
Dim As Integer iStatus
Dim as any Ptr hImage
iStatus = GdipLoadImageFromFile(sImgFile, @hImage)
If iStatus <> 0 Then
GdiplusShutdown(GDIPlusToken)
End
End if
Dim as Double fTimer
fTimer = Timer
If (_GDIPlus_ImageGetPixelFormat(hImage) and PixelFormatAlpha) Then 'check if image has alpha channel
? "Unique color count: " & _GDIPlus_ImageCountColors32(hImage)
Else
? "Unique color count: " & _GDIPlus_ImageCountColors24ASM(hImage)
End If
? (Timer - fTimer) * 1000 & " ms"
GdipDisposeImage(hImage)
GdiplusShutdown(GDIPlusToken)
Sleep
Might be useful...