Skip to content

Commit

Permalink
windows: try dib format if dibv5 is not avaliable (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
pluveto committed Jan 31, 2022
1 parent 1d2e38d commit 179c35f
Show file tree
Hide file tree
Showing 6 changed files with 558 additions and 6 deletions.
74 changes: 72 additions & 2 deletions clipboard_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ package clipboard
import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"image"
"image/color"
Expand All @@ -25,6 +27,8 @@ import (
"time"
"unicode/utf16"
"unsafe"

"golang.org/x/image/bmp"
)

func initialize() error { return nil }
Expand Down Expand Up @@ -107,7 +111,8 @@ func writeText(buf []byte) error {
func readImage() ([]byte, error) {
hMem, _, err := getClipboardData.Call(cFmtDIBV5)
if hMem == 0 {
return nil, err
// second chance to try FmtDIB
return readImageDib()
}
p, _, err := gLock.Call(hMem)
if p == 0 {
Expand Down Expand Up @@ -154,6 +159,57 @@ func readImage() ([]byte, error) {
return buf.Bytes(), nil
}

func readImageDib() ([]byte, error) {
const (
fileHeaderLen = 14
infoHeaderLen = 40
cFmtDIB = 8
)

hClipDat, _, err := getClipboardData.Call(cFmtDIB)
if err != nil {
return nil, errors.New("not dib format data: " + err.Error())
}
pMemBlk, _, err := gLock.Call(hClipDat)
if pMemBlk == 0 {
return nil, errors.New("failed to call global lock: " + err.Error())
}
defer gUnlock.Call(hClipDat)

bmpHeader := (*bitmapHeader)(unsafe.Pointer(pMemBlk))
dataSize := bmpHeader.SizeImage + fileHeaderLen + infoHeaderLen

if bmpHeader.SizeImage == 0 && bmpHeader.Compression == 0 {
iSizeImage := bmpHeader.Height * ((bmpHeader.Width*uint32(bmpHeader.BitCount)/8 + 3) &^ 3)
dataSize += iSizeImage
}
buf := new(bytes.Buffer)
binary.Write(buf, binary.LittleEndian, uint16('B')|(uint16('M')<<8))
binary.Write(buf, binary.LittleEndian, uint32(dataSize))
binary.Write(buf, binary.LittleEndian, uint32(0))
const sizeof_colorbar = 0
binary.Write(buf, binary.LittleEndian, uint32(fileHeaderLen+infoHeaderLen+sizeof_colorbar))
j := 0
for i := fileHeaderLen; i < int(dataSize); i++ {
binary.Write(buf, binary.BigEndian, *(*byte)(unsafe.Pointer(pMemBlk + uintptr(j))))
j++
}
return bmpToPng(buf)
}

func bmpToPng(bmpBuf *bytes.Buffer) (buf []byte, err error) {
var f bytes.Buffer
original_image, err := bmp.Decode(bmpBuf)
if err != nil {
return nil, err
}
err = png.Encode(&f, original_image)
if err != nil {
return nil, err
}
return f.Bytes(), nil
}

func writeImage(buf []byte) error {
r, _, err := emptyClipboard.Call()
if r == 0 {
Expand Down Expand Up @@ -386,9 +442,9 @@ func watch(ctx context.Context, t Format) <-chan []byte {
}

const (
cFmtBitmap = 2 // Win+PrintScreen
cFmtUnicodeText = 13
cFmtDIBV5 = 17
cFmtBitmap = 2 // Win+PrintScreen
// Screenshot taken from special shortcut is in different format (why??), see:
// https://jpsoft.com/forums/threads/detecting-clipboard-format.5225/
cFmtDataObject = 49161 // Shift+Win+s, returned from enumClipboardFormats
Expand Down Expand Up @@ -428,6 +484,20 @@ type bitmapV5Header struct {
Reserved uint32
}

type bitmapHeader struct {
Size uint32
Width uint32
Height uint32
PLanes uint16
BitCount uint16
Compression uint32
SizeImage uint32
XPelsPerMeter uint32
YPelsPerMeter uint32
ClrUsed uint32
ClrImportant uint32
}

// Calling a Windows DLL, see:
// https://github.com/golang/go/wiki/WindowsDLLs
var (
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ module golang.design/x/clipboard
go 1.16

require (
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMD
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 h1:3In5TnfvnuXTF/uflgpYxSCEGP2NdYT37KsPh3VjZYU=
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E=
Expand Down
219 changes: 219 additions & 0 deletions vendor/golang.org/x/image/bmp/reader.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 179c35f

Please sign in to comment.