News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Find Average Color of a Bitmap

Started by dedndave, June 15, 2012, 04:50:44 AM

Previous topic - Next topic

dedndave

my first attempt at using CreateDIBSection   :P
it seems to work pretty well

AverageColor PROTO :HBITMAP

;***********************************************************************************************

AverageColor PROC USES EBX ESI EDI hbmpBitmap:HBITMAP

;Returns a COLORREF value that approximates the algebraic mean color of an image.
;by DednDave, 6-14-2012
;
;Call With:         hbmpBitmap = bitmap image handle
;
;  Returns: if successful, EAX = average image color
;                          EDX = contrasting color (EAX xor 808080h)
;         if unsuccessful, EAX = 0 (black)
;                          EDX = 0FFFFFFh (white)
;
;-------------------------------

AVGCLR_SIZMAX EQU 1564000
AVGCLR_DIMSML EQU 1000
AVGCLR_DIMLRG EQU 1564
AVGCLR_DIMSQR EQU 1252

;-------------------------------

        LOCAL   hdcMem1       :HDC
        LOCAL   hdcMem2       :HDC
        LOCAL   hbmpMem2      :HBITMAP
        LOCAL   hbmpPrev1     :HBITMAP
        LOCAL   hbmpPrev2     :HBITMAP
        LOCAL   pvBits        :LPVOID
        LOCAL   sizeBitmap    :_SIZE
        LOCAL   uBytesPerLine :DWORD
        LOCAL   bmis          :BITMAPINFO

;BITMAPINFO      STRUCT
;  bmiHeader       BITMAPINFOHEADER <>
;    biSize          dd ?               ;BITMAPINFOHEADER structure size
;    biWidth         dd ?               ;image width in pixels
;    biHeight        dd ?               ;signed image height in pixels
;    biPlanes        dw ?               ;= 1
;    biBitCount      dw ?               ;= 24
;    biCompression   dd ?               ;= BI_RGB
;    biSizeImage     dd ?               ;image data bytes
;    biXPelsPerMeter dd ?               ;= 0
;    biYPelsPerMeter dd ?               ;= 0
;    biClrUsed       dd ?               ;= 0
;    biClrImportant  dd ?               ;= 0
;  bmiColors       RGBQUAD <>

;-------------------------------

        INVOKE  GetBitmapSize,hbmpBitmap,addr sizeBitmap
        mov     esi,eax                          ;ESI = image height
        xor     ebx,ebx
        mul     ecx
        mov     edi,ecx                          ;EDI = image width
        or      edx,edx
        jnz     AvgCl1

        or      eax,eax
        jnz     AvgCl0

;the image has a width or height of 0, or both

        mov     edx,0FFFFFFh
        jmp     AvgCl9

AvgCl0: cmp     eax,AVGCLR_SIZMAX
        jbe     AvgCl4

;If we come here, it means we are going to reduce the image.
;We divide the larger image dimension by the smaller one.
;If that ratio is greater than or equal to 1.25:1, we use a
;rectangle of AVGCLR_DIMLRG x AVGCLR_DIMSML if the image is
;wide, or AVGCLR_DIMSML x AVGCLR_DIMLRG if the image is tall.
;Otherwise, we use a square of AVGCLR_DIMSQR x AVGCLR_DIMSQR.

AvgCl1: xor     edx,edx
        mov     eax,esi
        inc     ebx
        cmp     eax,ecx
        jae     AvgCl2

        xchg    eax,ecx

AvgCl2: div     ecx
        dec     eax
        jnz     AvgCl3

        shl     edx,2
        cmp     edx,ecx
        jae     AvgCl3

        mov     edi,AVGCLR_DIMSQR
        mov     esi,edi
        jmp short AvgCl4

AvgCl3: cmp     edi,esi
        mov     edi,AVGCLR_DIMLRG
        mov     esi,AVGCLR_DIMSML
        jae     AvgCl4

        xchg    edi,esi

AvgCl4: mov     eax,edi
        xor     edx,edx
        mov     bmis.bmiHeader.biSize,sizeof BITMAPINFOHEADER
        shl     eax,1
        mov     bmis.bmiHeader.biWidth,edi
        mov     bmis.bmiHeader.biHeight,esi
        add     eax,edi
        mov     bmis.bmiHeader.biCompression,edx ;BI_RGB = 0
        mov     bmis.bmiHeader.biXPelsPerMeter,edx
        add     eax,3
        mov     bmis.bmiHeader.biYPelsPerMeter,edx
        and     al,0FCh
        mov     bmis.bmiHeader.biClrUsed,edx
        mov     bmis.bmiHeader.biClrImportant,edx
        mov     uBytesPerLine,eax
        mov     bmis.bmiHeader.biPlanes,1
        mul     esi
        mov     bmis.bmiHeader.biBitCount,24
        mov     bmis.bmiHeader.biSizeImage,eax
        push    edi
        INVOKE  GetDC,HWND_DESKTOP
        xchg    eax,edi
        INVOKE  CreateCompatibleDC,edi
        mov     hdcMem1,eax
        INVOKE  SelectObject,eax,hbmpBitmap
        xor     edx,edx
        mov     hbmpPrev1,eax
        INVOKE  CreateDIBSection,edi,addr bmis,DIB_RGB_COLORS,addr pvBits,edx,edx
        mov     hbmpMem2,eax
        INVOKE  CreateCompatibleDC,edi
        mov     hdcMem2,eax
        INVOKE  SelectObject,eax,hbmpMem2
        mov     hbmpPrev2,eax
        INVOKE  ReleaseDC,HWND_DESKTOP,edi
        dec     ebx
        pop     edi
        jz      AvgCl5

        inc     ebx
        INVOKE  BitBlt,hdcMem2,ebx,ebx,edi,esi,hdcMem1,ebx,ebx,SRCCOPY
        jmp short AvgCl6

AvgCl5: INVOKE  SetStretchBltMode,hdcMem2,HALFTONE
        INVOKE  SetBrushOrgEx,hdcMem2,ebx,ebx,ebx
        INVOKE  StretchBlt,hdcMem2,ebx,ebx,edi,esi,hdcMem1,
                ebx,ebx,sizeBitmap.x,sizeBitmap.y,SRCCOPY

;EDI           = DIB section width
;ESI           = DIB section height
;pvBits        = address of first image scan line
;uBytesPerLine = bytes per line

AvgCl6: push    ebp
        push    esi
        mov     edx,pvBits
        mov     eax,ebx
        push    uBytesPerLine
        mov     ecx,ebx
        mov     ebp,ebx

AvgCl7: push    edi
        push    edx

AvgCl8: mov     al,[edx]
        add     ebx,eax
        mov     al,[edx+1]
        add     ecx,eax
        mov     al,[edx+2]
        add     edx,3
        add     ebp,eax
        sub     edi,1
        jnz     AvgCl8

        pop     edx
        pop     edi
        add     edx,[esp]
        sub     esi,1
        jnz     AvgCl7

        pop     edx
        pop     eax
        mul     edi
        xchg    eax,edi

;EBX = blue total
;ECX = green total
;EBP = red total
;ESI = 0
;EDI = divisor

        mov     eax,ebx
        mov     edx,esi
        mov     ebx,esi
        div     edi
        shl     edx,1
        cmp     edx,edi
        sbb     al,-1
        adc     al,-1
        mov     bh,al
        mov     edx,esi
        mov     eax,ecx
        shl     ebx,8
        div     edi
        shl     edx,1
        cmp     edx,ecx
        sbb     al,-1
        adc     al,-1
        mov     edx,esi
        mov     bh,al
        mov     eax,ebp
        div     edi
        shl     edx,1
        cmp     edx,ecx
        sbb     al,-1
        adc     al,-1
        mov     bl,al
        pop     ebp
        INVOKE  SelectObject,hdcMem2,hbmpPrev2
        INVOKE  DeleteObject,eax
        INVOKE  DeleteDC,hdcMem2
        INVOKE  SelectObject,hdcMem1,hbmpPrev1
        INVOKE  DeleteDC,hdcMem1
        xchg    eax,ebx
        mov     edx,eax
        xor     edx,808080h

AvgCl9: ret

AverageColor ENDP

;***********************************************************************************************

dedndave

oh yah - a needed support function
GetBitmapSize PROTO :HBITMAP,:LPVOID

;***********************************************************************************************

GetBitmapSize PROC hbmpBitmap:HBITMAP,lpSize:LPVOID

;BITMAP      STRUCT
; bmType       dd ?
; bmWidth      dd ?
; bmHeight     dd ?
; bmWidthBytes dd ?
; bmPlanes     dw ?
; bmBitsPixel  dw ?
; bmBits       dd ?

        xor     eax,eax
        sub     esp,sizeof BITMAP-12
        push    eax
        push    eax
        push    eax
        INVOKE  GetObject,hbmpBitmap,sizeof BITMAP,esp
        pop     edx
        pop     ecx
        pop     eax
        mov     edx,lpSize
        add     esp,sizeof BITMAP-12
        or      edx,edx
        jz      GBSize

        mov     [edx]._SIZE.x,ecx
        mov     [edx]._SIZE.y,eax

GBSize: ret

GetBitmapSize ENDP

;***********************************************************************************************

MichaelW

Just out of curiosity, how would you use the average color?
Well Microsoft, here's another nice mess you've gotten us into.

dedndave

well - there are other uses, but i am using it as a background or "matte" to surround an image
i am almost finished with this little project
one more function to write
i want to be able to open a variety of image types from file or resource
BMP, DIB, EMF, GIF, ICO, JPG, PNG, TIFF, WMF
at the moment, i can only open BMP's - otherwise it is pretty much done
i will post it with source
it has pan/zoom - pan-grab - pretty cool   :P

maybe later, i will make it handle transparent images, as well
not needed for this program, but i want a versatile function i can use for other things

i could add some other things - like measuring calipers   :P
i implemented calipers in a 16-bit program long ago that was kinda neat

dedndave

here is the project as it is...

it will only open BMP and DIB files, at the moment
and - it needs a bit of clean-up
but, i thought it would be fun for others to play with   :P

notice that, when you open a new image, the custom colors in the color-picker are modified
the first custom color is the image average and the last one is the contrasting color


FORTRANS

Hi,

   Rather nice program Dave.  I think I will see if I can
learn something from it.

Thanks,

Steve

dedndave


Don57


dedndave

thanks Don
i have some more work to do on it
i had to set it aside to get some other things done, for now
hopefully, i will get back to it in the next few days