Forum: Ruby How to create a monocrome bitmap with win32api

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
E10a4542870d329eb832b36136de4cf1?d=identicon&s=25 Dave Smith (daves931)
on 2016-11-30 09:06
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
This topic is locked and can not be replied to.