Skip to content

Commit 179c35f

Browse files
authored
windows: try dib format if dibv5 is not avaliable (#21)
1 parent 1d2e38d commit 179c35f

File tree

6 files changed

+558
-6
lines changed

6 files changed

+558
-6
lines changed

clipboard_windows.go

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ package clipboard
1515
import (
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

3034
func initialize() error { return nil }
@@ -107,7 +111,8 @@ func writeText(buf []byte) error {
107111
func 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+
157213
func 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

388444
const (
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
433503
var (

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ module golang.design/x/clipboard
33
go 1.16
44

55
require (
6-
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
6+
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
77
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554
88
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMD
77
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
88
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
99
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
10-
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
11-
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
10+
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
11+
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
1212
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
1313
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 h1:3In5TnfvnuXTF/uflgpYxSCEGP2NdYT37KsPh3VjZYU=
1414
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E=

vendor/golang.org/x/image/bmp/reader.go

Lines changed: 219 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)