golang-design / clipboard

đź“‹ cross-platform clipboard package that supports accessing text and image in Go (macOS/Linux/Windows/Android/iOS)
https://golang.design/x/clipboard
MIT License
579 stars 64 forks source link

bug: Image Write Doesn't Seem to Work on Linux and Windows (Ubuntu 20.04) #35

Closed HuakunShen closed 1 year ago

HuakunShen commented 1 year ago

My computer:

Sample 1

If I take a screenshot, and run the following code, I can no longer access the screenshot.

The code below simply reads the image, and write it back after 10 seconds.

func main() {
    err := clipboard.Init()
    checkErr(err)

    imgBuf := clipboard.Read(clipboard.FmtImage)
    fmt.Println(len(imgBuf))
    time.Sleep(10 * time.Second)
    clipboard.Write(clipboard.FmtImage, imgBuf)
}

Sample 2

I tried to use a base64 image string for testing. The code writes the image and read it back then compare with the source.

stdout outputs "true" in the end (on ubuntu), but I can't paste the image out. It seems like the image is written to somewhere not recognized by the OS.

This sample works on MacOS and Windows (Windows outputs false in the end but image can be pasted, seems like there were some transformation applied.)

func main() {
    sampleBase64Img := "iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAADgKtSgAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAAtdEVYdENyZWF0aW9uIFRpbWUAVHVlIDEzIERlYyAyMDIyIDA0OjM5OjI1IFBNIEVTVH9UhTgAAAIhSURBVEiJrZQxaBNhFMd/d7leYprGWEMkldIONta4xFAHqWiEYMHBpRktCkWHUoJOcexsF8EO6iA4KE4O0jgIgk6iUrDadrKobW3TJhgSm6S5kPscUhQbcvkS+qbHvXe/7//e979TwuGwYE8c6Du691HDmJqI/80TicR/NVWa0kZYwAV9wW1OHqobbH/gJ6Ip7t/5xqPrWcKe1g+xXIsQgK1K4EyGu1PrXB0wUfYHrvLqQT+Tjw+yVADFXWQ8vsGoX34Ca+WGxvxbH/FpL58KoHYWuXElR4+kfCm37Kx4mE46MAQ4j+e43C+nXh2PTBILRQm4dIs2hbX3bj5XAbXCULAipUr9svULvXuI8+FLHLM3ntfM63zPAQj8vgo2GfiHpWe8XF5H6AMM+lyN3SAUSkatatcl1wIm+XyKklBw6M6WrNYUrmsOHA4nuiLYKRdp/3usD+1a5GYtEwVyRWt4q1Nps3NPd1OD3/lq407VpNNRO7psyP3vtPXsilSjerhMwA2g8HNTw0LGv3d0zzAjp8cY6fdb2EsQPJdnUAXMDj4udGDKwGOnztKr51hOpRqoEXhDaW5HDWwKbC96eLEqt31tczXJ/I9FMpX6q+zqKXDxQpaxSAmvDcx8JzNP3GxKWkp7/XWhQclkOLbBrVCNVMm4uDdzhNktec9ozRrMos67N908THaxXJLmNoMrzD3vZXTLTtpoDSoFT6/Z26Puxh8ZKK5kzvJifAAAAABJRU5ErkJggg=="
    sampleImgBuf, _ := base64.StdEncoding.DecodeString(sampleBase64Img)
    clipboard.Write(clipboard.FmtImage, sampleImgBuf)
    time.Sleep(time.Second)
    imgRead := clipboard.Read(clipboard.FmtImage)
    decodedImgRead := base64.StdEncoding.EncodeToString(imgRead)
    fmt.Println(decodedImgRead == sampleBase64Img)
}
HuakunShen commented 1 year ago

It seems like doing this makes image writing works on Linux Ubuntu, even without triggering changed. Why does this happen?

And this will block the program.

changed := clipboard.Write(clipboard.FmtImage, sampleImgBuf)
select {
case <-changed:
    println(`Image Updated`)
}
changkun commented 1 year ago

On Linux, you must keep the application running so that others can read your data. See https://github.com/golang-design/clipboard/issues/15 for another discussion. Closing because this is not a bug, and feel free to reopen the issue if this is actually a bug.

HuakunShen commented 1 year ago

@changkun Thanks, I kind of noticed that the program has to be running. I did a work-around with xclip. Is it the same on Windows? I also can't write image on Windows.

changkun commented 1 year ago

That's not a requirement on Windows. Is the problem reproducible on latest release?

HuakunShen commented 1 year ago

@changkun Yes I tried to write an image on Windows on the latest release and it doesn't work.

Here is my sample code.

package main

import (
    "encoding/base64"
    "golang.design/x/clipboard"
    "log"
)

func main() {
    if err := clipboard.Init(); err != nil {
        log.Fatal(err)
    }
    base64Str := "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDumIVSx6AZrD0LxPba9d3sFujD7K+xie5rVvpPJsJ5P7qE/pXn3woXdY6rfdWluWNcEYpxbOlvVI9JormvDPioa/eahbGHy3tJNh966WpaadmUnfYy/ESzP4fvVgUtK0TBQOpOK8s8Kaj4q8P6MbC38PPJlifMbjOa9npMD0FXGdlaxLjd3ueFeDr/AMTReJtRjsrSPzpJd1yr/wAHPavc4S5hQyDD4G761mWXh6xsNWudSgQrPcffPY1rUVJqT0CEWkf/2Q=="
    imgBuf, err := base64.StdEncoding.DecodeString(base64Str)
    if err != nil {
        log.Fatal(err)
    }
    clipboard.Write(clipboard.FmtImage, imgBuf)
}
HuakunShen commented 1 year ago

And if I use select to monitor changed, there is a deadlock.

changed := clipboard.Write(clipboard.FmtImage, imgBuf)
select {
case <-changed:
    println(`"text data" is no longer available from clipboard.`)
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive (nil chan)]:
main.main()
    C:/Users/username/Desktop/clipboard-app/main.go:20 +0xce
changkun commented 1 year ago

Is your image png encoded?

HuakunShen commented 1 year ago

@changkun Yes, if you copy the base64 string to https://onlinepngtools.com/convert-base64-to-png The image can be rendered.

HuakunShen commented 1 year ago

Wait, it seems like it's not png encoded even if it can be displayed. I tried to take a screenshot and read it to string with go clipboard, then write it back. It works!

So does this mean other type of image encoding are not supported? I will experiment a few more things, thanks!

changkun commented 1 year ago

As documented in the API, the image buffer must be png encoded: https://pkg.go.dev/golang.design/x/clipboard#Write

It is recommended that you encode it using image/png package to encode the bytes buffer

There are underlying implementation reasons, but it is not important for users who are not interested in the details.