Daniel Berger
2009-Apr-17 15:42 UTC
[Win32utils-devel] Getting image size for win32-clipboard
Hi, I''m having some trouble getting the image size for win32-clipboard. The basic approach is this: bmi = 0.chr * 44 # BITMAPIFO handle = GetClipboardData(CF_DIB) address = GlobalLock(handle) memcpy(bmi, address, bmi.size) size_image = bmi[20,4].unpack(''L'').first # 0 ??? This generally seems to work. I copied a small 24-bit color jpg image into my clipboard and can validate that the height and width are correct. However, the size_image always ends up 0. What am I doing wrong? The docs did mention that 24-bit RGB images might return 0. If that''s the case, how do I get the size? Thanks, Dan
Heesob Park
2009-Apr-17 23:18 UTC
[Win32utils-devel] Getting image size for win32-clipboard
Hi, 2009/4/18 Daniel Berger <djberg96 at gmail.com>:> Hi, > > I''m having some trouble getting the image size for win32-clipboard. The > basic approach is this: > > ? bmi ? ? = 0.chr * 44 # BITMAPIFO > ? handle ?= GetClipboardData(CF_DIB) > ? address = GlobalLock(handle) > ? memcpy(bmi, address, bmi.size) > ? size_image = bmi[20,4].unpack(''L'').first # 0 ??? > > This generally seems to work. I copied a small 24-bit color jpg image into > my clipboard and can validate that the height and width are correct. > However, the size_image always ends up 0. > > What am I doing wrong? The docs did mention that 24-bit RGB images might > return 0. If that''s the case, how do I get the size? >In my test with mspaint.exe, it works fine. What''s your copy process? How do I reproduce the bug? Regards, Park Heesob
Daniel Berger
2009-Apr-18 01:24 UTC
[Win32utils-devel] Getting image size for win32-clipboard
On Fri, Apr 17, 2009 at 5:18 PM, Heesob Park <phasis at gmail.com> wrote:> Hi, > > 2009/4/18 Daniel Berger <djberg96 at gmail.com>: >> Hi, >> >> I''m having some trouble getting the image size for win32-clipboard. The >> basic approach is this: >> >> ? bmi ? ? = 0.chr * 44 # BITMAPIFO >> ? handle ?= GetClipboardData(CF_DIB) >> ? address = GlobalLock(handle) >> ? memcpy(bmi, address, bmi.size) >> ? size_image = bmi[20,4].unpack(''L'').first # 0 ??? >> >> This generally seems to work. I copied a small 24-bit color jpg image into >> my clipboard and can validate that the height and width are correct. >> However, the size_image always ends up 0. >> >> What am I doing wrong? The docs did mention that 24-bit RGB images might >> return 0. If that''s the case, how do I get the size? >> > In my test with mspaint.exe, it works fine. > > What''s your copy process? > How do I reproduce the bug?I opened up a small .jpg file with Photoshop Elements 5. I did a Ctrl-A + Ctrl-C. This was the result: Header Size: 40 Width: 570 Height: 570 Planes: 1 Bit Count: 24 Compression: 0 Image Size: 0 X Per Meter: 112205 Y Per Meter: 112205 Color Used: 0 Color Import: 0 Ok...this is strange. I opened up the *same* image in Paint, and did a Ctrl-A + Ctrl-C. This was the result: Header Size: 40 Width: 570 Height: 570 Planes: 1 Bit Count: 24 Compression: 0 Image Size: 975840 X Per Meter: 112200 Y Per Meter: 112200 Color Used: 0 Color Import: 0 Maybe because it was a jpg instead of a bmp? I''m not sure. In any case, I''ve got the initial implementation in CVS. I am having some trouble actually copying clipboard contents. I tried this: File.open("test.bmp", "wb"){ |fh| fh.write Clipboard.data(Clipboard::DIB) } The file size is identical, but I can''t open the resulting file - MS Paint says it doesn''t recognize the format. Please take a look at the code in CVS (and use the latest windows-pr) and see if everything looks alright. Thanks, Dan
Heesob Park
2009-Apr-18 09:19 UTC
[Win32utils-devel] Getting image size for win32-clipboard
Hi, 2009/4/18 Daniel Berger <djberg96 at gmail.com>:> > I opened up a small .jpg file with Photoshop Elements 5. I did a > Ctrl-A + Ctrl-C. This was the result: > > Header Size: 40 > Width: 570 > Height: 570 > Planes: 1 > Bit Count: 24 > Compression: 0 > Image Size: 0 > X Per Meter: 112205 > Y Per Meter: 112205 > Color Used: 0 > Color Import: 0 > > Ok...this is strange. I opened up the *same* image in Paint, and did a > Ctrl-A + Ctrl-C. This was the result: > > Header Size: 40 > Width: 570 > Height: 570 > Planes: 1 > Bit Count: 24 > Compression: 0 > Image Size: 975840 > X Per Meter: 112200 > Y Per Meter: 112200 > Color Used: 0 > Color Import: 0 > > Maybe because it was a jpg instead of a bmp? I''m not sure. > > In any case, I''ve got the initial implementation in CVS. I am having > some trouble actually copying clipboard contents. I tried this: > > File.open("test.bmp", "wb"){ |fh| fh.write Clipboard.data(Clipboard::DIB) } > > The file size is identical, but I can''t open the resulting file - MS > Paint says it doesn''t recognize the format. > > Please take a look at the code in CVS (and use the latest windows-pr) > and see if everything looks alright. >Here is a patch. --- clipboard.rb 2009-04-18 18:11:44.000000000 +0900 +++ clipboard.rb.new 2009-04-18 18:12:03.000000000 +0900 @@ -234,6 +234,7 @@ begin address = GlobalLock(handle) + buf_size = GlobalSize(handle) memcpy(bmi, address, bmi.length) size = bmi[0,4].unpack(''L'').first # biSize @@ -241,6 +242,7 @@ 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 @@ -264,9 +266,10 @@ raise Error, "invalid bit count" end # case - buf_size = size + 14 + (table_size * 4) + size_image + offset = 0x36 + (table_size*4) buf = 0.chr * buf_size memcpy(buf, address, buf.size) + buf = "\x42\x4D" + [size_image].pack(''L'') + 0.chr * 4 + [offset].pack(''L'') + buf ensure GlobalUnlock(handle) end Regards, Park Heesob
Daniel Berger
2009-Apr-18 13:03 UTC
[Win32utils-devel] Getting image size for win32-clipboard
On Sat, Apr 18, 2009 at 3:19 AM, Heesob Park <phasis at gmail.com> wrote:> Hi, > > 2009/4/18 Daniel Berger <djberg96 at gmail.com>: >> >> I opened up a small .jpg file with Photoshop Elements 5. I did a >> Ctrl-A + Ctrl-C. This was the result: >> >> Header Size: 40 >> Width: 570 >> Height: 570 >> Planes: 1 >> Bit Count: 24 >> Compression: 0 >> Image Size: 0 >> X Per Meter: 112205 >> Y Per Meter: 112205 >> Color Used: 0 >> Color Import: 0 >> >> Ok...this is strange. I opened up the *same* image in Paint, and did a >> Ctrl-A + Ctrl-C. This was the result: >> >> Header Size: 40 >> Width: 570 >> Height: 570 >> Planes: 1 >> Bit Count: 24 >> Compression: 0 >> Image Size: 975840 >> X Per Meter: 112200 >> Y Per Meter: 112200 >> Color Used: 0 >> Color Import: 0 >> >> Maybe because it was a jpg instead of a bmp? I''m not sure. >> >> In any case, I''ve got the initial implementation in CVS. I am having >> some trouble actually copying clipboard contents. I tried this: >> >> File.open("test.bmp", "wb"){ |fh| fh.write Clipboard.data(Clipboard::DIB) } >> >> The file size is identical, but I can''t open the resulting file - MS >> Paint says it doesn''t recognize the format. >> >> Please take a look at the code in CVS (and use the latest windows-pr) >> and see if everything looks alright. >> > Here is a patch. > > --- clipboard.rb ? ? ? ?2009-04-18 18:11:44.000000000 +0900 > +++ clipboard.rb.new ? ?2009-04-18 18:12:03.000000000 +0900 > @@ -234,6 +234,7 @@ > > ? ? ? ? ?begin > ? ? ? ? ? ? address = GlobalLock(handle) > + ? ? ? ? ? buf_size = GlobalSize(handle) > ? ? ? ? ? ? memcpy(bmi, address, bmi.length) > > ? ? ? ? ? ? size ? ? ? ?= bmi[0,4].unpack(''L'').first ?# biSize > @@ -241,6 +242,7 @@ > ? ? ? ? ? ? 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 > @@ -264,9 +266,10 @@ > ? ? ? ? ? ? ? ? ? raise Error, "invalid bit count" > ? ? ? ? ? ? end # case > > - ? ? ? ? ? ?buf_size = size + 14 + (table_size * 4) + size_image > + ? ? ? ? ? offset = 0x36 + (table_size*4) > ? ? ? ? ? ? buf = 0.chr * buf_size > ? ? ? ? ? ? memcpy(buf, address, buf.size) > + ? ? ? ? ? ?buf = "\x42\x4D" + [size_image].pack(''L'') + 0.chr * 4 + > [offset].pack(''L'') + buf > ? ? ? ? ?ensure > ? ? ? ? ? ? GlobalUnlock(handle) > ? ? ? ? ?endThanks Heesob, that worked. There are a couple of things I still don''t understand, though. I used the same code as before: File.open(''clippy.bmp'', ''wb''){ |fh| fh.write Clipboard.data(Clipboard::DIB) } The resulting file is larger than the original file in my experiments by a few bytes. Why? I can''t visually detect any differences in the image, but I thought it was curious. Also, it seems like we ought to be able to remove the memcpy near the end, since ''buf'' is reassigned anyway. But, if I remove it, I get an "out of memory" error if I attempt to open the file. Last, if I replace Clipboard::DIB with Clipboard::ENHMETAFILE I get a segfault. Regards, Dan
Heesob Park
2009-Apr-18 14:20 UTC
[Win32utils-devel] Getting image size for win32-clipboard
2009/4/18 Daniel Berger <djberg96 at gmail.com>:> On Sat, Apr 18, 2009 at 3:19 AM, Heesob Park <phasis at gmail.com> wrote: > > Thanks Heesob, that worked. There are a couple of things I still don''t > understand, though. I used the same code as before: > > File.open(''clippy.bmp'', ''wb''){ |fh| > ? fh.write Clipboard.data(Clipboard::DIB) > } > > The resulting file is larger than the original file in my experiments > by a few bytes. Why? I can''t visually detect any differences in the > image, but I thought it was curious. >I guess the difference is just a dummy data for the data alignment.> Also, it seems like we ought to be able to remove the memcpy near the > end, since ''buf'' is reassigned anyway. But, if I remove it, I get an > "out of memory" error if I attempt to open the file. >I''m not sure why you want to remove it. it is an essential part.> Last, if I replace Clipboard::DIB with Clipboard::ENHMETAFILE I get a segfault. >ENHMETAFILE is nothing to do with DIB or BITMAT. it must be handled differently. After insert GetEnhMetaFileBits API to window-pr/lib/windows/gdi/bitmat.rb API.new(''GetEnhMetaFileBits'', ''LLP'', ''L'', ''gdi32'') Test with File.open(''aaa.wmf'',''wb'') { |f| f.write(Clipboard.data(Clipboard::ENHMETAFILE)) } Here is a patch for ENHMETAFILE --- clipboard.rb 2009-04-18 23:11:05.000000000 +0900 +++ clipboard.rb.new 2009-04-18 23:08:38.000000000 +0900 @@ -3,6 +3,7 @@ require ''windows/error'' require ''windows/shell'' require ''windows/msvcrt/buffer'' +require ''windows/gdi/bitmap'' # The Win32 module serves as a namespace only. module Win32 @@ -18,12 +19,14 @@ include Windows::Error include Windows::Shell include Windows::MSVCRT::Buffer + include Windows::GDI::Bitmap extend Windows::Clipboard extend Windows::Memory extend Windows::Error extend Windows::Shell extend Windows::MSVCRT::Buffer + extend Windows::GDI::Bitmap # The version of this library VERSION = ''0.5.0'' @@ -93,8 +96,10 @@ clip_data.strip! when HDROP clip_data = get_file_list(handle) - when DIB, BITMAP, ENHMETAFILE + when DIB, BITMAP clip_data = get_image_data(handle) + when ENHMETAFILE + clip_data = get_meta_data(handle) else raise Error, ''format not supported'' end @@ -281,6 +286,14 @@ buf end + def self.get_meta_data(handle) + buf = nil + buf_size = GetEnhMetaFileBits(handle,0,nil) + buf = 0.chr * buf_size + GetEnhMetaFileBits(handle,buf_size,buf) + buf + end + # Get and return an array of file names that have been copied. # def self.get_file_list(handle) Regards, Park Heesob
Daniel Berger
2009-Apr-22 05:44 UTC
[Win32utils-devel] Getting image size for win32-clipboard
> -----Original Message----- > From: win32utils-devel-bounces at rubyforge.org [mailto:win32utils-devel- > bounces at rubyforge.org] On Behalf Of Heesob Park > Sent: Saturday, April 18, 2009 8:20 AM > To: Development and ideas for win32utils projects > Subject: Re: [Win32utils-devel] Getting image size for win32-clipboard > > 2009/4/18 Daniel Berger <djberg96 at gmail.com>: > > On Sat, Apr 18, 2009 at 3:19 AM, Heesob Park <phasis at gmail.com> > wrote: > > > > Thanks Heesob, that worked. There are a couple of things I still > don''t > > understand, though. I used the same code as before: > > > > File.open(''clippy.bmp'', ''wb''){ |fh| > > fh.write Clipboard.data(Clipboard::DIB) > > } > > > > The resulting file is larger than the original file in my experiments > > by a few bytes. Why? I can''t visually detect any differences in the > > image, but I thought it was curious. > > > I guess the difference is just a dummy data for the data alignment. > > > Also, it seems like we ought to be able to remove the memcpy near the > > end, since ''buf'' is reassigned anyway. But, if I remove it, I get an > > "out of memory" error if I attempt to open the file. > > > I''m not sure why you want to remove it. it is an essential part. > > > Last, if I replace Clipboard::DIB with Clipboard::ENHMETAFILE I get a > segfault. > > > ENHMETAFILE is nothing to do with DIB or BITMAT. > it must be handled differently. > > After insert GetEnhMetaFileBits API to window- > pr/lib/windows/gdi/bitmat.rb > API.new(''GetEnhMetaFileBits'', ''LLP'', ''L'', ''gdi32'') > Test with > File.open(''aaa.wmf'',''wb'') { |f| > f.write(Clipboard.data(Clipboard::ENHMETAFILE)) } > > Here is a patch for ENHMETAFILE > --- clipboard.rb 2009-04-18 23:11:05.000000000 +0900 > +++ clipboard.rb.new 2009-04-18 23:08:38.000000000 +0900 > @@ -3,6 +3,7 @@ > require ''windows/error'' > require ''windows/shell'' > require ''windows/msvcrt/buffer'' > +require ''windows/gdi/bitmap'' > > # The Win32 module serves as a namespace only. > module Win32 > @@ -18,12 +19,14 @@ > include Windows::Error > include Windows::Shell > include Windows::MSVCRT::Buffer > + include Windows::GDI::Bitmap > > extend Windows::Clipboard > extend Windows::Memory > extend Windows::Error > extend Windows::Shell > extend Windows::MSVCRT::Buffer > + extend Windows::GDI::Bitmap > > # The version of this library > VERSION = ''0.5.0'' > @@ -93,8 +96,10 @@ > clip_data.strip! > when HDROP > clip_data = get_file_list(handle) > - when DIB, BITMAP, ENHMETAFILE > + when DIB, BITMAP > clip_data = get_image_data(handle) > + when ENHMETAFILE > + clip_data = get_meta_data(handle) > else > raise Error, ''format not supported'' > end > @@ -281,6 +286,14 @@ > buf > end > > + def self.get_meta_data(handle) > + buf = nil > + buf_size = GetEnhMetaFileBits(handle,0,nil) > + buf = 0.chr * buf_size > + GetEnhMetaFileBits(handle,buf_size,buf) > + buf > + end > + > # Get and return an array of file names that have been copied. > # > def self.get_file_list(handle)Thank you for this! I''ve committed the change (with some modifications). Instead of putting those methods in the Windows::GDI::Bitmap module, I''ve created a separate module called Windows::GDI::MetaFile. It''s now in CVS. Regards, Dan