mushanshitiancai / vscode-paste-image

paste image from clipboard to markdown/asciidoc directly!
MIT License
423 stars 128 forks source link

Windows / Linux support #1

Closed danshryock closed 7 years ago

danshryock commented 8 years ago

I saw that you have Windows and Linux support on your TODO list, so I took a look at what APIs would be most helpful to support those platforms.

Because VSCode uses Electron, I think this would be the easiest to hit all supported platforms at once:

var electron = require("electron")
var clipboardContents = electron.clipboard.availableFormats() // probably ["image/png"] for a screenshot on the clipboard
var clipboardImage = electron.clipboard.readImage();
var uriImage = clipboardImage.toDataURL(); //if you wanted to embed the entire image in the markdown
var pngBuffer = clipboardImage.toPng() //returns a node Buffer that contains a png that you
                                       //could write to disk: https://nodejs.org/api/buffer.html#buffer_class_buffer

var fs = require("fs")
fs.writeFile("/path/to/file.png",pngBuffer, (err) => {
  if(err) {
    console.error("Error",err);
  } else {
    console.log("done")
  }
});
mushanshitiancai commented 7 years ago

Yes,you are right.There are some convenient API of Electron to handle clipboard,but vscode only provide the node environment to plugin.A plugin can't access Electron API throught vscode for now.

You can browse:

danshryock commented 7 years ago

Ah! That makes sense!

What about creating a small electron app, and then invoking it from your extension?

For a proof of concept I did this:

Add Electron dependency to the extension (sadly a big download, but it works!) npm install --save electron

in your extension you launch a custom standalone Electron app to save the png:

var child_process = require('child_process')   
var pathToElectron = require('electron'); //when run from node this returns the path to the executable
var output = [];
function collect(data) { output.push(""+data); }
var proc = child_process.spawn(
  pathToElectron,
  [
    "/path/to/extension/custom-electron-app",
    "/path/to/destination.png"
  ]
)    
proc.stdout.on('data',collect);
proc.stderr.on('data',collect);
proc.on( 'close', function(){ console.log(output.join("")) } )

and then in /path/to/extension/custom-electron-app/index.js

const {app, clipboard, BrowserWindow} = require('electron')
const fs = require("fs")

app.on('ready', captureClipboard)

function captureClipboard(){
    var destination = process.argv[2];
    console.log(destination)
    var clipboardContents = clipboard.availableFormats() // probably ["image/png"] for a screenshot on the clipboard
    var clipboardImage = clipboard.readImage();
    var uriImage = clipboardImage.toDataURL(); //if you wanted to embed the entire image in the markdown
    var pngBuffer = clipboardImage.toPng() //returns a node Buffer that contains a png that you
                                        //could write to disk: https://nodejs.org/api/buffer.html#buffer_class_buffer

    fs.writeFile(destination,pngBuffer, function(err){
        if(err) {
            console.error("Error",err);
        } else {
            console.log("done")
        }
    });

    app.quit()
}

You'd obviously need to add in proper error handling and communication from the sub process to the extension, but it should all work in theory.

Thanks!

viniarck commented 7 years ago

+1 for Linux support! Cheers!

mushanshitiancai commented 7 years ago

@danshryock very very thank you for your research!

Issue #3011 had mentioned the method that use child process to start up a electron and call electron api from this child process. It sounds feasible,but I feel it is not a good or a elegance way.Because a electron environment is very big to a plugin and start a electron cost a lot of time.

As vscode is build on electron, so the best way is that vscode expose the lower api to plugin environment. We have to wait.

But I really holp every can use this plugin, so I plan use this method when user is using win/linux.But When I finish code,I found a new problem....

If not use electron, the size of packaged plugin is 1.6M, after add electron, it become 64MB....

image

And it cause I can't publish plugin to vscode marketplace....(marketplace only accept plugin that limit to 20MB,see cannot publish no request found. · Issue #92 · Microsoft/vscode-vsce)

So....

danshryock commented 7 years ago

Ah, I suppose that makes sense. Thank you for trying! I really appreciate it!

Hopefully examples like this will help the VSCode team to realize that they need to provide some sort of support to the extension community for things like this.

Maybe via enhanced APIs provided by them, or maybe even a simple way to run a sandboxed electron instance for extensions. It could be a shell exec of the electron provided with VSCode, or maybe a custom background electron that they provide for extension authors to use.

https://github.com/Microsoft/vscode/issues/3011 https://github.com/Microsoft/vscode/issues/4972

mushanshitiancai commented 7 years ago

@danshryock @viniciusarcanjo plugin support windows now! @kivle add the support of window by powershell.

danshryock commented 7 years ago

Great news! Thanks!

mushanshitiancai commented 7 years ago

@danshryock @viniciusarcanjo support Linux now! I use xclip to implement this feature. And I add featrue that use selected text as the image file name.

paste-image