How to create a monocrome bitmap with win32api

Hello all,

I’m trying to convert a visual basic algorithm that copy a bitmap into
another performing a transparency effect. The transparence is the fined
by a chosen color. In orther to do that, it’s necessary to create a mask
to be used during some win32api bitblt operatios. That mask is a
mocromatic bitmap which has just 1 bit per pixel. Now comes, the
problem, how to create in ruby this kind of bitmap with the win32api
function CreateBitmap? That function prototype is:

Public Declare Function CreateBitmap Lib “gdi32” Alias “CreateBitmap”
(ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long,
ByVal nBitCount As Long, lpBits As Any) As Long

And when it’s used in visual basic to generate the monocromatic bitmap,
it is called like that:

hMaskBmp = CreateBitmap(Width, Height, 1, 1, ByVal 0&)

The problem is the last value: Byval 0&. This is a “special” convention
by vb for DLL function calls to pass an empty value for “pointer”
values. The & in the end indicates that the data type of the 0 should be
“long” and not integer or byte.

How to do the same thing in ruby? I tried several things but none
worked. Could someone help me with that? The code that I last tried is
at follow.

class Bitmap

RtlMoveMemory_pi = Win32API.new(‘kernel32’, ‘RtlMoveMemory’, ‘pii’, ‘i’)
FindWindow = Win32API.new(‘user32’, ‘FindWindow’, ‘pp’, ‘i’)
GetDC = Win32API.new(‘user32’, ‘GetDC’, ‘i’, ‘i’)
ReleaseDC = Win32API.new(‘user32’, ‘ReleaseDC’, ‘ii’, ‘i’)
BitBlt = Win32API.new(‘gdi32’, ‘BitBlt’, ‘iiiiiiiii’, ‘i’)
CreateCompatibleBitmap = Win32API.new(‘gdi32’,
‘CreateCompatibleBitmap’, ‘iii’, ‘i’)
CreateCompatibleDC = Win32API.new(‘gdi32’, ‘CreateCompatibleDC’, ‘i’,
‘i’)
DeleteObject = Win32API.new(‘gdi32’, ‘DeleteObject’, ‘i’, ‘i’)
GetDIBits = Win32API.new(‘gdi32’, ‘GetDIBits’, ‘iiiiipi’, ‘i’)
SelectObject = Win32API.new(‘gdi32’, ‘SelectObject’, ‘ii’, ‘i’)
SetDIBits = Win32API.new(‘gdi32’, ‘SetDIBits’, ‘iiiiipi’, ‘i’)
TransparentBlt = Win32API.new(‘msimg32’, ‘TransparentBlt’,
‘iiiiiiiiiii’,‘i’)
SetBkColor = Win32API.new(‘gdi32’, ‘SetBkColor’, ‘ii’, ‘i’)
CreateBitmap = Win32API.new(‘gdi32’, ‘CreateBitmap’, ‘iiiip’, ‘i’)
DeleteDC = Win32API.new(‘gdi32’, ‘DeleteDC’, ‘i’, ‘i’)

def address
unless @address
RtlMoveMemory_pi.call(a="\0"*4, id*2+16, 4)
RtlMoveMemory_pi.call(a, a.unpack(‘L’)[0]+8, 4)
RtlMoveMemory_pi.call(a, a.unpack(‘L’)[0]+16, 4)
@address = a.unpack(‘L’)[0]
end
return @address
end

def transpblt2(x, y, src_bmp, src_rect, color_obj)
hDC1, hBM1, info = *self.BltApiInit
hDC2, hBM2 = *src_bmp.BltApiInit
#---------------------------------------------------------------------------
dsthDC = hDC1
srchDC = hDC2

crTransparent = color_obj.red + color_obj.green*256 +

color_obj.blue*65536

#First create some DC's. These are our gateways to assosiated

bitmaps in RAM
maskDC = CreateCompatibleDC.call(dsthDC) #DC for the mask
tempDC = CreateCompatibleDC.call(dsthDC) #DC for temproary data

#Then we need the bitmaps. Note that we create a monochrome bitmap

here!
#this is a trick we use for creating a mask fast enough:

#Bitmap for mask
info2 = [40,width,height,1,1,0,0,0,0,0,0].pack('LllSSLLllLL')
hMaskBmp = CreateBitmap.call(src_rect.width, src_rect.height, 1, 1,

info2)
# Bitmap for temporary data
hTempBmp = CreateCompatibleBitmap.call(dsthDC, src_rect.width,
src_rect.height)

#..then we can assign the bitmaps to the DCs
hMaskBmp = SelectObject.call(maskDC, hMaskBmp)
hTempBmp = SelectObject.call(tempDC, hTempBmp)


#Now we can create a mask..First we set the background color to the
#transparent color then we copy the image into the monochrome

bitmap.
#When we are done, we reset the background color of the original
source.
crTransparent = SetBkColor.call(srchDC, crTransparent)
BitBlt.call( maskDC, 0, 0, src_rect.width, src_rect.height, srchDC,
src_rect.x, src_rect.y, 0xCC0020)
crTransparent = SetBkColor.call(srchDC, crTransparent)

#'The first we do with the mask is to MergePaint it into the

destination.
#this will punch a WHITE hole in the background exactly were we want
the
#graphics to be painted in.
BitBlt.call( tempDC, 0, 0, src_rect.width, src_rect.height, maskDC,
0, 0, 0xCC0020)
BitBlt.call( dsthDC, x, y, src_rect.width, src_rect.height, tempDC,
0, 0, 0xBB0226) #merpaint

#Now we delete the transparent part of our source image. To do this
#we must invert the mask and MergePaint it into the source image.

the
#transparent area will now appear as WHITE.
BitBlt.call( maskDC, 0, 0, src_rect.width, src_rect.height, maskDC,
0, 0, 0x330008) #vbNotSrcCopy
BitBlt.call( tempDC, 0, 0, src_rect.width, src_rect.height, srchDC,
0, 0, 0xCC0020)#vbSrcCopy
BitBlt.call( tempDC, 0, 0, src_rect.width, src_rect.height, maskDC,
0, 0, 0xBB0226)#vbMergePaint

#Both target and source are clean, all we have to do is to AND them

together!
BitBlt.call(dsthDC, x, y, src_rect.width, src_rect.height, tempDC,
0, 0, 0x8800C6)#vbSrcAnd

#Now all we have to do is to clean up after us and free system

resources…
DeleteObject.call(hMaskBmp)
DeleteObject.call(hTempBmp)
DeleteDC.call(maskDC)
DeleteDC.call(tempDC)
#-------------------------------------------------------------------------------
GetDIBits.call(hDC1, hBM1, 0, height, address, info, 0)
DeleteObject.call(hBM1); DeleteObject.call(hDC1)
DeleteObject.call(hBM2); DeleteObject.call(hDC2)
end

def BltApiInit
info = [40,width,height,1,32,0,0,0,0,0,0].pack(‘LllSSLLllLL’)
hWndDC = GetDC.call(hWnd=FindWindow.call(‘RGSS Player’, 0))
hMemDC = CreateCompatibleDC.call(hWndDC)
hMemBM = CreateCompatibleBitmap.call(hWndDC, width, height)
ReleaseDC.call(hWnd, hWndDC)
SelectObject.call(hMemDC, hMemBM)
SetDIBits.call(hMemDC, hMemBM, 0, height, address, info, 0)
return hMemDC, hMemBM, info
end
#------------------------------------------------------------------------------
end