diff --git a/app.js b/app.js index 2bde6c8..a6254b7 100644 --- a/app.js +++ b/app.js @@ -7,22 +7,42 @@ import 'es.shim' import { $, bind } from 'wkit' -function test1() { - try { - window.webkit.messageHandlers.app.postMessage({ - data: { foo: 'Test 1' } - }) - $('#output').innerHTML = '这是没有回调的 ' - } catch (err) { - alert(err) - } +async function test1() { + let txt = await native.clipboard.readText() + $('input').value = txt } -function test2() { - native.handler('blabla', { foo: 'bar' }).then(r => { - $('#output').innerHTML = JSON.stringify(r) - }) +async function test2() { + native.clipboard.writeText('这是一段写进剪切板的文本') + // native.handler('blabla', { foo: 'bar' }).then(r => { + // $('#output').innerHTML = JSON.stringify(r) + // }) } bind($('.btn1'), 'click', test1) bind($('.btn2'), 'click', test2) +bind($('.btn3'), 'click', async function () { + // window.open('about:blank') + // let img = await native.clipboard.writeImage('/code/gtk/webkit/debian.png') + let img = await native.image('/code/gtk/webkit/debian.png') + native.clipboard.writeImage(img) + // native.clipboard.writeImage('/code/gtk/webkit/debian.png') + try { + $('img').src = URL.createObjectURL(await img.export()) + } catch (err) { + alert(err) + } +}) +bind($('.btn4'), 'click', async function () { + native.quit() + // native.clipboard.clear() +}) + +bind($('textarea'), 'paste', async function (ev) { + let items = ev.clipboardData.items + for (let it of items) { + let file = it.getAsFile() + $('img').src = URL.createObjectURL(file) + break + } +}) diff --git a/debian.png b/debian.png new file mode 100644 index 0000000..249de87 Binary files /dev/null and b/debian.png differ diff --git a/demo.js b/demo.js new file mode 100644 index 0000000..3b501dd --- /dev/null +++ b/demo.js @@ -0,0 +1,5 @@ +import fs from 'iofs' + +let buf = fs.cat('./debian.png') +console.log(buf) +console.log([...buf], buf.byteLength) diff --git a/index.html b/index.html index 5312038..7b4e8b5 100644 --- a/index.html +++ b/index.html @@ -16,6 +16,9 @@ } } + @@ -25,6 +28,14 @@ 打开控制台
loading...
+ + + +
+ + + + diff --git a/inject.js b/inject.js index 0840957..a3e7149 100644 --- a/inject.js +++ b/inject.js @@ -3,6 +3,40 @@ * @author yutent * @date 2023/07/21 17:38:11 */ +const MIME_TYPES = { + html: 'text/html', + json: 'application/json', + js: 'application/javascript', + htm: 'text/html', + txt: 'text/plain', + css: 'text/css', + webp: 'image/webp', + jpg: 'image/jpg', + jpeg: 'image/jpeg', + png: 'image/png', + gif: 'image/gif', + svg: 'image/svg+xml', + ico: 'image/ico', + mp3: 'audio/mpeg', + ogg: 'audio/ogg', + m4a: 'audio/m4a', + amr: 'audio/amr', + mp4: 'video/mp4', + webm: 'video/webm', + wasm: 'application/wasm', + asm: 'application/asm', + zip: 'application/zip', + '7z': 'application/x-7z-compressed', + eot: 'application/vnd.ms-fontobject', + ttf: 'font/ttf', + otf: 'font/otf', + woff: 'font/woff', + woff2: 'font/woff2', + xls: 'application/vnd.ms-excel', + doc: 'application/msword', + xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' +} function defer() { let obj = {} @@ -19,8 +53,14 @@ function rand(prefix = 'cb_') { function handler(event, data = {}, once = true) { let _ = defer() - let callback = rand() - native[once ? '$once' : '$on'](callback, _.resolve) + let callback + + if (typeof once === 'boolean') { + callback = rand() + native[once ? '$once' : '$on'](callback, _.resolve) + } else { + _.resolve(true) + } window.webkit.messageHandlers.app.postMessage({ event, data, @@ -29,6 +69,43 @@ function handler(event, data = {}, once = true) { return _.promise } +class NativeImage { + #origin + + constructor(obj) { + this.#origin = obj + this.width = obj.width + this.height = obj.height + this.type = MIME_TYPES[obj.filepath.split('.').pop()] + } + + toPixbuf() { + return this.#origin + } + + export(type) { + let _ = defer() + let canvas = document.createElement('canvas') + canvas.width = this.width + canvas.height = this.height + let ctx = canvas.getContext('2d') + let imgData = ctx.getImageData(0, 0, this.width, this.height) + let data = imgData.data + + for (let i = 0; i < this.#origin.bytes.length; i += 4) { + imgData.data[i] = this.#origin.bytes[i] + imgData.data[i + 1] = this.#origin.bytes[i + 1] + imgData.data[i + 2] = this.#origin.bytes[i + 2] + imgData.data[i + 3] = this.#origin.bytes[i + 3] + } + + ctx.putImageData(imgData, 0, 0) + canvas.toBlob(_.resolve, type || this.type, 1) + + return _.promise + } +} + class EventEmitter { // __events__ = Object.create(null) @@ -79,8 +156,34 @@ class EventEmitter { window.native = new EventEmitter() Object.assign(native, { + quit() { + return handler('quit') + }, fs: { read(filepath) {} }, + image(filepath) { + return handler('image', { value: filepath }).then(r => new NativeImage(r)) + }, + clipboard: { + readText() { + return handler('clipboard', { action: 'wait_for_text' }) + }, + writeText(value) { + return handler('clipboard', { action: 'set_text', value }, null) + }, + readImage() { + return handler('clipboard', { action: 'wait_for_image' }) + }, + writeImage(value) { + if (typeof value === 'object') { + value = value.toPixbuf() + } + return handler('clipboard', { action: 'set_image', value }, null) + }, + clear() { + return handler('clipboard', { action: 'clear' }) + } + }, handler }) diff --git a/main.py b/main.py index dd51dda..b9183a1 100755 --- a/main.py +++ b/main.py @@ -2,10 +2,12 @@ import gi, json, os + gi.require_version("Gtk", "3.0") gi.require_version("WebKit2", "4.1") -from gi.repository import Gtk, WebKit2 +from gi.repository import Gtk, Gdk, WebKit2, GLib +from gi.repository.GdkPixbuf import Pixbuf class WebKitWindow(Gtk.Window): @@ -46,6 +48,9 @@ class WebKitWindow(Gtk.Window): # self.webview.load_uri("https://benchmark.wkit.fun") + self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + + self.add(self.webview) @@ -54,7 +59,6 @@ class WebKitWindow(Gtk.Window): def create_tray(self): indicator = Gtk.StatusIcon.new_from_icon_name('youtube') - indicator.connect('activate', self.toggle_visible) return indicator @@ -68,6 +72,8 @@ class WebKitWindow(Gtk.Window): else: self.present() + + def file_path(self, filepath): @@ -76,19 +82,86 @@ class WebKitWindow(Gtk.Window): def on_script_message(self, webview, message): - data = message.get_js_value() - data = json.loads(data.to_json(0)) - print('这是py收到的值: ',data) + + data = json.loads(message.get_js_value().to_json(0)) + event = data.get('event') callback = data.get('callback') - res = {"foo": 123, "bar": (11,22,33)} + params = data.get('data') + match event: case 'fs': pass + case 'clipboard': + output = None + + # 读文本 + if params['action'] == 'wait_for_text': + output = self.clipboard.wait_for_text() + + # 写文本 + elif params['action'] == 'set_text': + self.clipboard.set_text(params['value'], -1) + + # 写图片 + elif params['action'] == 'set_image': + image = params['value'] + # 前端传进来的值, 如果是路径的话, 直接读取 + if type(image) == str: + image = Pixbuf.new_from_file(image) + else: + image = Pixbuf.new_from_data( + data = bytes(image['bytes']), + colorspace = image['colorspace'], + has_alpha = image['has_alpha'], + bits_per_sample = image['bits_per_sample'], + width = image['width'], + height = image['height'], + rowstride = image['rowstride'] + ) + + self.clipboard.set_image(image) + self.clipboard.store() + + # 清除剪切板 + elif params['action'] == 'clear': + self.clipboard.clear() + + # 回调给前端 + if callback and output: + scripts = 'native.$emit("' + callback + '",' + json.dumps(output) + ')' + print(scripts) + self.webview.evaluate_javascript(scripts, -1) + + # 退出app + case 'quit': + Gtk.main_quit() + + # 读取图片, 返回图片像素数据 + case 'image': + filename = params['value'] + pixbuf = Pixbuf.new_from_file(filename) + image = { + "width": pixbuf.get_width(), + "height": pixbuf.get_height(), + "colorspace": pixbuf.get_colorspace(), + "has_alpha": pixbuf. get_has_alpha(), + "bits_per_sample": pixbuf.get_bits_per_sample(), + "rowstride": pixbuf.get_rowstride(), + "filepath": filename, + "bytes": list(pixbuf.get_pixels()) + } + + + scripts = 'native.$emit("' + callback + '",' + json.dumps(image) + ')' + + self.webview.evaluate_javascript(scripts, -1) + case _: if callback : + res = {"foo": 123, "bar": (11,22,33)} scripts = 'native.$emit("' + callback + '",' + json.dumps(res) + ')' print(scripts) self.webview.evaluate_javascript(scripts, -1) @@ -115,6 +188,4 @@ win.show_all() tray = win.create_tray() -print(tray) - Gtk.main() \ No newline at end of file diff --git a/notes/clipboard.py b/notes/clipboard.py new file mode 100644 index 0000000..c5808da --- /dev/null +++ b/notes/clipboard.py @@ -0,0 +1,41 @@ + +import gi + +gi.require_version("Gtk", "3.0") + +from gi.repository import Gtk, Gdk +from gi.repository.GdkPixbuf import Pixbuf + +clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + + +# 读剪切板中的文本 +output = clipboard.wait_for_text() + +# 写文本进剪切板 +clipboard.set_text('blabla', -1) + + + +# 从文件中读取 +filepath = 'xxx.png' +image = Pixbuf.new_from_file(filepath) + +# 从其他地方拿到的图片像素对象 +image = Pixbuf.new_from_data( + data = bytes(image['bytes']), + colorspace = image['colorspace'], + has_alpha = image['has_alpha'], + bits_per_sample = image['bits_per_sample'], + width = image['width'], + height = image['height'], + rowstride = image['rowstride'] +) + +clipboard.set_image(image) +clipboard.store() + + + +# 清除 +clipboard.clear() \ No newline at end of file diff --git a/notes/image.py b/notes/image.py new file mode 100644 index 0000000..a63b25f --- /dev/null +++ b/notes/image.py @@ -0,0 +1,40 @@ +import gi + +gi.require_version("Gtk", "3.0") + +from gi.repository import Gtk, Gdk +from gi.repository.GdkPixbuf import Pixbuf + +# 读取图片, 返回图片像素数据 +filename = 'xxx.png' +pixbuf = Pixbuf.new_from_file(filename) + +# 得到这个对象, 就是可以传给前端的, + +image = { + "width": pixbuf.get_width(), + "height": pixbuf.get_height(), + "colorspace": pixbuf.get_colorspace(), + "has_alpha": pixbuf. get_has_alpha(), + "bits_per_sample": pixbuf.get_bits_per_sample(), + "rowstride": pixbuf.get_rowstride(), + "filepath": filename, + "bytes": list(pixbuf.get_pixels()) +} + +# scripts = 'native.$emit("' + callback + '",' + json.dumps(image) + ')' + +# 倒扣到前端传回来的数据, 调用 Pixbuf.new_from_data 可转回 Pixbuf对象 +pixbuf = Pixbuf.new_from_data( + data = bytes(image['bytes']), + colorspace = image['colorspace'], + has_alpha = image['has_alpha'], + bits_per_sample = image['bits_per_sample'], + width = image['width'], + height = image['height'], + rowstride = image['rowstride'] +) + + + +