@@ -15,6 +15,8 @@ package clipboard
1515import  (
1616	"bytes" 
1717	"context" 
18+ 	"encoding/binary" 
19+ 	"errors" 
1820	"fmt" 
1921	"image" 
2022	"image/color" 
@@ -25,6 +27,8 @@ import (
2527	"time" 
2628	"unicode/utf16" 
2729	"unsafe" 
30+ 
31+ 	"golang.org/x/image/bmp" 
2832)
2933
3034func  initialize () error  { return  nil  }
@@ -107,7 +111,8 @@ func writeText(buf []byte) error {
107111func  readImage () ([]byte , error ) {
108112	hMem , _ , err  :=  getClipboardData .Call (cFmtDIBV5 )
109113	if  hMem  ==  0  {
110- 		return  nil , err 
114+ 		// second chance to try FmtDIB 
115+ 		return  readImageDib ()
111116	}
112117	p , _ , err  :=  gLock .Call (hMem )
113118	if  p  ==  0  {
@@ -154,6 +159,57 @@ func readImage() ([]byte, error) {
154159	return  buf .Bytes (), nil 
155160}
156161
162+ func  readImageDib () ([]byte , error ) {
163+ 	const  (
164+ 		fileHeaderLen  =  14 
165+ 		infoHeaderLen  =  40 
166+ 		cFmtDIB        =  8 
167+ 	)
168+ 
169+ 	hClipDat , _ , err  :=  getClipboardData .Call (cFmtDIB )
170+ 	if  err  !=  nil  {
171+ 		return  nil , errors .New ("not dib format data: "  +  err .Error ())
172+ 	}
173+ 	pMemBlk , _ , err  :=  gLock .Call (hClipDat )
174+ 	if  pMemBlk  ==  0  {
175+ 		return  nil , errors .New ("failed to call global lock: "  +  err .Error ())
176+ 	}
177+ 	defer  gUnlock .Call (hClipDat )
178+ 
179+ 	bmpHeader  :=  (* bitmapHeader )(unsafe .Pointer (pMemBlk ))
180+ 	dataSize  :=  bmpHeader .SizeImage  +  fileHeaderLen  +  infoHeaderLen 
181+ 
182+ 	if  bmpHeader .SizeImage  ==  0  &&  bmpHeader .Compression  ==  0  {
183+ 		iSizeImage  :=  bmpHeader .Height  *  ((bmpHeader .Width * uint32 (bmpHeader .BitCount )/ 8  +  3 ) &^ 3 )
184+ 		dataSize  +=  iSizeImage 
185+ 	}
186+ 	buf  :=  new (bytes.Buffer )
187+ 	binary .Write (buf , binary .LittleEndian , uint16 ('B' )| (uint16 ('M' )<< 8 ))
188+ 	binary .Write (buf , binary .LittleEndian , uint32 (dataSize ))
189+ 	binary .Write (buf , binary .LittleEndian , uint32 (0 ))
190+ 	const  sizeof_colorbar  =  0 
191+ 	binary .Write (buf , binary .LittleEndian , uint32 (fileHeaderLen + infoHeaderLen + sizeof_colorbar ))
192+ 	j  :=  0 
193+ 	for  i  :=  fileHeaderLen ; i  <  int (dataSize ); i ++  {
194+ 		binary .Write (buf , binary .BigEndian , * (* byte )(unsafe .Pointer (pMemBlk  +  uintptr (j ))))
195+ 		j ++ 
196+ 	}
197+ 	return  bmpToPng (buf )
198+ }
199+ 
200+ func  bmpToPng (bmpBuf  * bytes.Buffer ) (buf  []byte , err  error ) {
201+ 	var  f  bytes.Buffer 
202+ 	original_image , err  :=  bmp .Decode (bmpBuf )
203+ 	if  err  !=  nil  {
204+ 		return  nil , err 
205+ 	}
206+ 	err  =  png .Encode (& f , original_image )
207+ 	if  err  !=  nil  {
208+ 		return  nil , err 
209+ 	}
210+ 	return  f .Bytes (), nil 
211+ }
212+ 
157213func  writeImage (buf  []byte ) error  {
158214	r , _ , err  :=  emptyClipboard .Call ()
159215	if  r  ==  0  {
@@ -386,9 +442,9 @@ func watch(ctx context.Context, t Format) <-chan []byte {
386442}
387443
388444const  (
445+ 	cFmtBitmap       =  2  // Win+PrintScreen 
389446	cFmtUnicodeText  =  13 
390447	cFmtDIBV5        =  17 
391- 	cFmtBitmap       =  2  // Win+PrintScreen 
392448	// Screenshot taken from special shortcut is in different format (why??), see: 
393449	// https://jpsoft.com/forums/threads/detecting-clipboard-format.5225/ 
394450	cFmtDataObject  =  49161  // Shift+Win+s, returned from enumClipboardFormats 
@@ -428,6 +484,20 @@ type bitmapV5Header struct {
428484	Reserved     uint32 
429485}
430486
487+ type  bitmapHeader  struct  {
488+ 	Size           uint32 
489+ 	Width          uint32 
490+ 	Height         uint32 
491+ 	PLanes         uint16 
492+ 	BitCount       uint16 
493+ 	Compression    uint32 
494+ 	SizeImage      uint32 
495+ 	XPelsPerMeter  uint32 
496+ 	YPelsPerMeter  uint32 
497+ 	ClrUsed        uint32 
498+ 	ClrImportant   uint32 
499+ }
500+ 
431501// Calling a Windows DLL, see: 
432502// https://github.com/golang/go/wiki/WindowsDLLs 
433503var  (
0 commit comments