@@ -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