PasteImageFromClipboard()

Blitz3D Forums/Blitz3D Programming/PasteImageFromClipboard()

I've been using a function from the code archives (http://www.blitzbasic.com/codearcs/codearcs.php?code=1767) to paste an image from the clipboard into a Blitz image. It works very nicely most of the time.

However if I do a screen grab using the Print Screen key and then use the function, it seems to just return a solid red rectangle. Can anyone suggest why this might be happening?

Thanks.

no idea. Print screening worked for me (win98se).

Bizarre, isn't it? I know the screen grab itself has worked because I can paste the image into Photoshop. I wonder if the problem is caused by some difference between Windows 98 and XP then.

In any case, thanks for the functions!

i have a xp
and print screen not work!

return a red rectangle!

mongia2

I get the same in XP. Thought I might try changing from a 32bit to 16bit desktop, but then it just MAVs. Maybe it needs options for if bpp=16 or 32? Dunno -- only gave it a quick squiz.

EDIT: I think I'm right. If you change the line "If bpp=24" to "If bpp=24 Or bpp=32" you will get a wrongly coloured approximation of the clipboard (assuming its a 32 bit grab) -- or, as in my case, the top left of it! The function 'just' needs extending to cope with 32 and 16 bit formats it seems.

EDIT: Okay, got 32bit looking okay now - gonna see if I can do 16bit and we should be sorted.

Well I'm not really sure what's going on in 16bit mode, but the altered code block for tentative 32bit support looks like this...

   If (bpp=24 Or bpp=32);get rgb offset
	If bpp=24 Then multiplier=3
	If bpp=32 Then multiplier=4
    PokeByte btmp,0,PeekByte(btmp,offset+(x*multiplier)) ;blue
    PokeByte btmp,1,PeekByte(btmp,offset+(x*multiplier)+1) ;green
    PokeByte btmp,2,PeekByte(btmp,offset+(x*multiplier)+2) ;red
   Else ;get palette index, 1/4/8-bit
    PokeByte btmp,0,PeekInt(btmp,sizeInfo+(index*4))
    PokeByte btmp,1,PeekInt(btmp,sizeInfo+(index*4)+1)
    PokeByte btmp,2,PeekInt(btmp,sizeInfo+(index*4)+2)
   EndIf


Over to some other sado-masochist!

looks like you solved it Sledge!

In win98 afair there is no 16 or 32 bit image that can go on the clipboard, high-color is always 24bit. It must be different in xp. The solution for 16 bit would be to peek a short and then convert that to 3 bytes. Looking up BITMAPINFO in the Win32 help it says 16bit is 555, saying that it could be 656. You'd just have to try it.

ok, I've figured out the 16 bit problem, hopefully! I just need someone to test it for me as I don't have xp.

;Paste Image from Clipboard function, by markcw on 29/07/06

Graphics3D 640,480,0,2
SetBuffer BackBuffer()

image=PasteImageFromClipboard() ;paste image from clipboard

width=ImageWidth(image) ;get image info
height=ImageHeight(image)

While Not KeyHit(1)

 Cls
 DrawImage image,50,50 ;draw the image

 Text 0,0,"image="+image+" width="+width+" height="+height

Flip
Wend

Function PasteImageFromClipboard()
 ;Paste the clipboard to a new Blitz3D image
 ;From "Copying a DIB to the clipboard", by John Simmons
 ;(http://www.codeproject.com)

 Local hDIB,himage,pbmi,btmp,sizeInfo,sizePal,width,height,bpp
 Local sizeBits,sizeDIB,x,y,offset,index,bytespp

 ;receive the bitmap from the clipboard as a DIB
 If Api_OpenClipboard(0) ;hwnd
  hDIB=Api_GetClipboardData(8) ;CF_DIB=8
  Api_CloseClipboard()
 EndIf

 If Not hDIB ;if we didn't get a DIB, return a dummy image
  himage=CreateImage(1,1)
  Return himage
 EndIf

 pbmi=Api_GlobalLock(hDIB) ;lock memory and get pointer to it

 btmp=CreateBank(40) ;initialize bank, we will resize it later

 Api_RtlMoveMemory(btmp,pbmi,40) ;move info header to bank
 sizeInfo=PeekInt(btmp,0) ;biSize

 ;calculate palette, Clipboard DIBs use the BITMAPINFO struct
 sizePal=PeekInt(btmp,32) ;biClrUsed
 If Not sizePal
  If PeekShort(btmp,14)<16 ;no color table for 16/24/32
   sizePal=1 Shl PeekShort(btmp,14) ;biBitCount, colors=2/16/256
  Else
   sizePal=PeekInt(btmp,16) ;biCompression, 16/32 use BI_BITFIELDS=3
  EndIf
 EndIf
 sizePal=sizePal*4 ;sizeof(RGBQUAD)

 width=PeekInt(btmp,4) ;biWidth
 height=PeekInt(btmp,8) ;biHeight
 bpp=PeekShort(btmp,14) ;biBitCount
 bytespp=bpp/8 ;bytes per pixel

 ;calculate bits, DWORD-aligned scanline (Width * BitCount) * Height
 sizeBits=((width*bpp+31)/32*4)*height
 sizeDIB=sizeInfo+sizePal+sizeBits ;total size

 ResizeBank btmp,sizeDIB ;resize bank to store DIB
 Api_RtlMoveMemory(btmp,pbmi,sizeDIB) ;move DIB to bank

 Api_GlobalUnlock(hDIB) ;unlock the DIB

 himage=CreateImage(width,height) ;new image to write

 ;calculate DWORD-aligned offset of bits for proper alignment
 ;we'll use biSize to store each pixel, we don't need it any more
 LockBuffer(ImageBuffer(himage))
 For y=0 To height-1
  offset=((width*bpp+31)/32*4)*y+sizeInfo+sizePal ;start of next scanline
  For x=0 To width-1
   If bpp=1
    index=PeekByte(btmp,offset+(x/8)) ;1-bit, looks nasty but it works
    ;work out the bit, invert it, bitmask the byte and convert to 0/1
    index=(index And (1 Shl (7-(x Mod 8)))) Shr (7-(x Mod 8))
   EndIf
   If bpp=4
    index=PeekByte(btmp,offset+(x/2)) ;4-bit, work out the nibble
    If x Mod 2 Then index=index And 15 ;get bits 0-3
    If Not x Mod 2 Then index=index Shr 4 ;get bits 4-7
   EndIf
   If bpp=8
    index=PeekByte(btmp,offset+x) ;8-bit, we have our index
   EndIf
   If bpp=24 Or bpp=32 ;get rgb offset
    PokeByte btmp,0,PeekByte(btmp,offset+(x*bytespp)) ;blue
    PokeByte btmp,1,PeekByte(btmp,offset+(x*bytespp)+1) ;green
    PokeByte btmp,2,PeekByte(btmp,offset+(x*bytespp)+2) ;red
   ElseIf bpp=16 ;rgb=565
    PokeByte btmp,0,(PeekShort(btmp,offset+(x*bytespp)) And 31) Shl 3 ;blue
    PokeByte btmp,1,((PeekShort(btmp,offset+(x*bytespp)) And 2016) Shr 5) Shl 2 ;green
    PokeByte btmp,2,((PeekShort(btmp,offset+(x*bytespp)) And 63488) Shr 11) Shl 3 ;red
   Else ;get palette index, 1/4/8-bit
    PokeByte btmp,0,PeekInt(btmp,sizeInfo+(index*4))
    PokeByte btmp,1,PeekInt(btmp,sizeInfo+(index*4)+1)
    PokeByte btmp,2,PeekInt(btmp,sizeInfo+(index*4)+2)
   EndIf
   WritePixelFast x,height-1-y,PeekInt(btmp,0),ImageBuffer(himage) ;biSize
  Next
 Next
 UnlockBuffer(ImageBuffer(himage))

 FreeBank btmp
 Return himage ;image handle

End Function


Thanks for your efforts with this Sledge and Mark.

Mark, in 16 bit mode the above code does return an image but the colours are all screwed up. I know that's not a very helpful description so I'm e-mailing you an image which shows exactly what happens.

that's pretty cool actually! Thanks for the image Joe. I suspect the problem is the bit shifting I used, as it's almost right. In the code first it gets the short/word and masks the correct bits, then if its green Shr 5, red Shr 10 so all the values are 0 to 31, 5 bits. Now to get 0 to 255 I did Shl 3 which must be the problem. Instead I think you need to multiply by 8.2 to get a constant range (31*8.2=254). I have updated the above code for this, so see if that works better now.

Edit: you could also try just multiply by 8 which would give values 0 to 248. Shouldn't make much difference.

I don't think that was the problem. The updated code produces essentially the same result. :(

in xp it work a 32 bit!

mongia

i test a 16 bit!

a 16 bit dont work perfecty!

the color is a strange!

mongia2

ok, please try the code above again.

The problem was that in 16bit the rgb bit order is 565 not 555.

Also, for 16/32bit images they use the BI_BITFIELDS in the biCompression field. Which stands for 3 rgb color masks in the palette, 12 bytes. So it should now work fine.

it work!

thanks!

mongia2

Yep, works perfectly now. Thanks!