As part of a puzzle/effect within a RPGMAce project, I am attempting to use Windows API to grab a bitmap from the Windows clipboard which will then be used to create a Sprite which is displayed in-game. However, I am having issues with the process of converting the clipboard resource into a Ruby-usable resource.
I can grab text without an issue, which is great, but I really would like to snag the bitmap data, as well. I am probably missing something simple or making everything more complex than it needs to be.
Sloppy, swiped and twisted code below :
I can grab text without an issue, which is great, but I really would like to snag the bitmap data, as well. I am probably missing something simple or making everything more complex than it needs to be.
Sloppy, swiped and twisted code below :
Code:
# The following script can be called from a 'Script Command' as follows :clp = Win32::Clipboard# Check For/Print Textif clp.format_available?(1)p clp.data(1)endclp = Win32::Clipboard# Check For/Use Bitmapif clp.format_available?(2)$tmpport=Viewport.new$tmpspr=Sprite.new($tmpport)$tmpspr.bitmap=clp.data(2)end
Code:
# Original Code : [URL="https://github.com/djberg96/win32-clipboard/blob/master/lib/win32/clipboard.rb#"]https://github.com/djberg96/win32-clipboard/blob/master/lib/win32/clipboard.rb#[/URL] Lock-Up Occurs At :# // get_image_data(handle)## address = @@globalLock.call(handle)# buf_size = @@globalSize.call(handle)# I believe this occurs because GlobalLock is looking for a Pointer, but receives an Integer instead.# I am not sure how to solve this, as when I change 'I' to 'P' in the Win32API function, everything# explodes sooner.# The Win32 module serves as a namespace only.module Win32 # The Clipboard class encapsulates functions that relate to the MS Windows # clipboard. class Clipboard @@closeClipboard = Win32API.new('user32' , 'CloseClipboard' , ['V'] , 'V') # The returned value of GetClipboardData probably needs to be a Pointer, but the # function dies if I switch 'I' with 'P'. @@getClipboardData = Win32API.new('user32' , 'GetClipboardData' , ['I'] , 'I') @@isClipboardFormatAvailable = Win32API.new('user32' , 'IsClipboardFormatAvailable' , ['I'] , 'I') @@openClipboard = Win32API.new('user32' , 'OpenClipboard' , ['L'] , 'L') @@globalAlloc = Win32API.new('kernel32' , 'GlobalAlloc' , ['L', 'L'] , 'L') @@globalLock = Win32API.new('kernel32' , 'GlobalLock' , ['L'] , 'L') @@globalSize = Win32API.new('kernel32' , 'GlobalSize' , ['L'] , 'L') @@globalUnlock = Win32API.new('kernel32' , 'GlobalUnlock' , ['L'] , '' ) @@memcpy = Win32API.new('ntdll' , 'memcpy' , ['P', 'P', 'L'] , 'L') # Clipboard formats # Text TEXT = 1 # Images DIB = 2 BITMAP = 8 # Returns the data currently in the clipboard. If +format+ is # specified, it will attempt to retrieve the data in that format. The # default is Clipboard::TEXT. # # If there is no data in the clipboard, or data is available but the # format doesn't match the data, then an empty string is returned. # # Examples: # # # Get some plain text # Win32::Clipboard.data # => e.g. 'hello' # # # Get a bitmap and write it to another file # File.open('bitmap_copy', 'wb'){ |fh| # fh.write Win32::Clipboard.data(Clipboard::DIB) # } # def self.data(format = TEXT) begin self.open if @@isClipboardFormatAvailable.call(format) handle = @@getClipboardData.call(format) case format when TEXT clip_data = 0.chr * @@globalSize.call(handle) @@memcpy.call(clip_data, handle, clip_data.size) clip_data = clip_data[ /^[^\0]*/ ] when DIB, BITMAP clip_data = get_image_data(handle) else raise Error, 'format not supported' end else clip_data = '' end ensure self.close end clip_data end # Singleton aliases # class << self alias :get_data :data end # Returns whether or not +format+ (an int) is currently available. # def self.format_available?(format) @@isClipboardFormatAvailable.call(format) == 1 ? true : false end private # Opens the clipboard and prevents other applications from modifying # the clipboard content until it is closed. # def self.open @@openClipboard.call(0) end # Close the clipboard # def self.close @@closeClipboard.call end # Get data for bitmap files # def self.get_image_data(handle) buf = nil bmi = 0.chr * 44 # BITMAPINFO begin address = @@globalLock.call(handle) buf_size = @@globalSize.call(handle) @@memcpy.call(bmi, address, bmi.length) bit_count = bmi[14,2].unpack('S').first # biBitCount compression = bmi[16,4].unpack('L').first # biCompression size_image = bmi[20,4].unpack('L').first # biSizeImage clr_used = bmi[32,4].unpack('L').first # biClrUsed size_image = buf_size + 16 if size_image == 0 # Calculate the header size case bit_count when 1 table_size = 2 when 4 table_size = 16 when 8 table_size = 256 when 16, 32 if compression == 0 table_size = clr_used elsif compression == 3 table_size = 3 else p "ERROR: invalid bit/compression combination" end when 24 table_size = clr_used else p "ERROR: invalid bit count" end # case offset = 0x36 + (table_size * 4) buf = 0.chr * buf_size @@memcpy.call(buf, address, buf.size) buf = "\x42\x4D" + [size_image].pack('L') + 0.chr * 4 + [offset].pack('L') + buf ensure @@globalUnlock.call(handle) end buf end endend
Last edited by a moderator:
