修复gtk读取图片像素时alpha通道异常的bug
parent
c0011b582d
commit
8ab9ea2dd9
|
@ -0,0 +1 @@
|
||||||
|
__pycache__
|
153
app.js
153
app.js
|
@ -5,58 +5,107 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'es.shim'
|
import 'es.shim'
|
||||||
import { $, bind } from 'wkit'
|
import { html, css, Component } from 'wkit'
|
||||||
|
|
||||||
async function test1() {
|
class App extends Component {
|
||||||
let txt = await native.clipboard.readText()
|
static props = {
|
||||||
$('input').value = txt
|
input: '',
|
||||||
|
img: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
.output {
|
||||||
|
max-width: 100%;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<button @click=${this.test1}>Test 1</button>
|
||||||
|
<button @click=${this.test2}>Test 2</button>
|
||||||
|
|
||||||
|
<a target="_blank" href="about:blank">打开控制台</a>
|
||||||
|
|
||||||
|
<div class="output">loading...</div>
|
||||||
|
|
||||||
|
<input value=${this.input} />
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<button @click=${this.writeImage}>写图片到剪切板</button>
|
||||||
|
<button
|
||||||
|
@click=${async function () {
|
||||||
|
native.quit()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
退出
|
||||||
|
</button>
|
||||||
|
<button @click=${this.createTray}>tray</button>
|
||||||
|
<button @click=${this.register}>screen</button>
|
||||||
|
<img style="width:100px;border:1px solid #09f;" src=${this.img} />
|
||||||
|
<textarea @paste=${this.pasteImg}></textarea>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async test1() {
|
||||||
|
let txt = await native.clipboard.readText()
|
||||||
|
console.log('<><><>', txt)
|
||||||
|
this.input = txt
|
||||||
|
}
|
||||||
|
|
||||||
|
async test2() {
|
||||||
|
native.clipboard.writeText('这是一段写进剪切板的文本')
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeImage() {
|
||||||
|
// let img = await native.image('/code/gtk/webkit/debian.png')
|
||||||
|
// native.clipboard.writeImage(img)
|
||||||
|
native.clipboard.writeImage('/code/gtk/webkit/red.png')
|
||||||
|
// try {
|
||||||
|
// this.img = URL.createObjectURL(await img.export())
|
||||||
|
// } catch (err) {
|
||||||
|
// alert(err)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
quit() {
|
||||||
|
native.quit()
|
||||||
|
}
|
||||||
|
|
||||||
|
createTray() {
|
||||||
|
native.tray()
|
||||||
|
}
|
||||||
|
|
||||||
|
async register() {
|
||||||
|
// console.log(await native.globalShortcut.enabled)
|
||||||
|
|
||||||
|
native.globalShortcut.register('<Ctrl>2', function () {
|
||||||
|
alert('<Ctrl>2被绑定了')
|
||||||
|
})
|
||||||
|
// console.log(await native.screen.getAllDisplays())
|
||||||
|
// console.log(await native.screen.getPrimaryDisplay())
|
||||||
|
}
|
||||||
|
|
||||||
|
async pasteImg(ev) {
|
||||||
|
let items = ev.clipboardData.items
|
||||||
|
|
||||||
|
let img = await window?.native?.clipboard?.readImage()
|
||||||
|
|
||||||
|
console.log(img)
|
||||||
|
|
||||||
|
if (img) {
|
||||||
|
this.img = URL.createObjectURL(await img.export())
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let it of items) {
|
||||||
|
let file = it.getAsFile()
|
||||||
|
if (file) {
|
||||||
|
this.img = URL.createObjectURL(file)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function test2() {
|
App.reg('app')
|
||||||
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($('.btn5'), 'click', async function () {
|
|
||||||
native.tray()
|
|
||||||
})
|
|
||||||
|
|
||||||
bind($('.btn6'), 'click', async function () {
|
|
||||||
// console.log(await native.globalShortcut.enabled)
|
|
||||||
|
|
||||||
native.globalShortcut.register('<Ctrl>2', function () {
|
|
||||||
alert('<Ctrl>2被绑定了')
|
|
||||||
})
|
|
||||||
// console.log(await native.screen.getAllDisplays())
|
|
||||||
// console.log(await native.screen.getPrimaryDisplay())
|
|
||||||
})
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
5
demo.js
5
demo.js
|
@ -1,5 +0,0 @@
|
||||||
import fs from 'iofs'
|
|
||||||
|
|
||||||
let buf = fs.cat('./debian.png')
|
|
||||||
console.log(buf)
|
|
||||||
console.log([...buf], buf.byteLength)
|
|
23
index.html
23
index.html
|
@ -16,30 +16,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<script type="module" src="/app.js"></script>
|
||||||
#output {max-width:100%;white-space: pre-wrap;word-break: break-all;}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<button class="btn1">Test 1</button>
|
<wc-app></wc-app>
|
||||||
<button class="btn2">Test 2</button>
|
|
||||||
|
|
||||||
<a target="_blank" href="about:blank">打开控制台</a>
|
|
||||||
|
|
||||||
<div id="output">loading...</div>
|
|
||||||
|
|
||||||
<input type="text">
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<button class="btn3">写图片到剪切板</button>
|
|
||||||
<button class="btn4">退出</button>
|
|
||||||
<button class="btn5">tray</button>
|
|
||||||
<button class="btn6">screen</button>
|
|
||||||
<img style="width:100px;border:1px solid #09f;" src="" alt="">
|
|
||||||
<textarea></textarea>
|
|
||||||
|
|
||||||
<script type="module" src="/app.js"></script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -83,6 +83,7 @@ class NativeImage {
|
||||||
this.width = obj.width
|
this.width = obj.width
|
||||||
this.height = obj.height
|
this.height = obj.height
|
||||||
this.type = MIME_TYPES[obj.filepath.split('.').pop()]
|
this.type = MIME_TYPES[obj.filepath.split('.').pop()]
|
||||||
|
console.log(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
toPixbuf() {
|
toPixbuf() {
|
||||||
|
@ -179,7 +180,9 @@ Object.assign(native, {
|
||||||
return handler('clipboard', { action: 'set_text', value }, null)
|
return handler('clipboard', { action: 'set_text', value }, null)
|
||||||
},
|
},
|
||||||
readImage() {
|
readImage() {
|
||||||
return handler('clipboard', { action: 'wait_for_image' })
|
return handler('clipboard', { action: 'wait_for_image' }).then(r =>
|
||||||
|
r ? new NativeImage(r) : r
|
||||||
|
)
|
||||||
},
|
},
|
||||||
writeImage(value) {
|
writeImage(value) {
|
||||||
if (typeof value === 'object') {
|
if (typeof value === 'object') {
|
||||||
|
|
39
main.py
39
main.py
|
@ -10,6 +10,8 @@ gi.require_version("Keybinder", "3.0")
|
||||||
from gi.repository import Gtk, Gdk, WebKit2, GLib, Keybinder
|
from gi.repository import Gtk, Gdk, WebKit2, GLib, Keybinder
|
||||||
from gi.repository.GdkPixbuf import Pixbuf
|
from gi.repository.GdkPixbuf import Pixbuf
|
||||||
|
|
||||||
|
from notes.utils import *
|
||||||
|
|
||||||
# 优先尝试使用指示器, 没有再使用 Gtk.StatusIcon
|
# 优先尝试使用指示器, 没有再使用 Gtk.StatusIcon
|
||||||
try:
|
try:
|
||||||
gi.require_version('AyatanaAppIndicator3', '0.1')
|
gi.require_version('AyatanaAppIndicator3', '0.1')
|
||||||
|
@ -22,21 +24,6 @@ except (ValueError, ImportError):
|
||||||
Keybinder.init()
|
Keybinder.init()
|
||||||
|
|
||||||
|
|
||||||
def get_monitor_info(monitor):
|
|
||||||
return {
|
|
||||||
"model": monitor.props.model,
|
|
||||||
"scale_factor": monitor.props.scale_factor,
|
|
||||||
"manufacturer": monitor.props.manufacturer,
|
|
||||||
"refresh_rate": monitor.props.refresh_rate,
|
|
||||||
"is_primary": monitor.is_primary(),
|
|
||||||
"geometry": {
|
|
||||||
"width": monitor.props.geometry.width,
|
|
||||||
"height": monitor.props.geometry.height,
|
|
||||||
"x": monitor.props.geometry.x,
|
|
||||||
"y": monitor.props.geometry.y,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class WebKitWindow(Gtk.Window):
|
class WebKitWindow(Gtk.Window):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -164,6 +151,7 @@ class WebKitWindow(Gtk.Window):
|
||||||
# 前端传进来的值, 如果是路径的话, 直接读取
|
# 前端传进来的值, 如果是路径的话, 直接读取
|
||||||
if type(image) == str:
|
if type(image) == str:
|
||||||
image = Pixbuf.new_from_file(image)
|
image = Pixbuf.new_from_file(image)
|
||||||
|
print(pixbuf_to_dict(image, params['value']))
|
||||||
else:
|
else:
|
||||||
image = Pixbuf.new_from_data(
|
image = Pixbuf.new_from_data(
|
||||||
data = bytes(image['bytes']),
|
data = bytes(image['bytes']),
|
||||||
|
@ -174,18 +162,21 @@ class WebKitWindow(Gtk.Window):
|
||||||
height = image['height'],
|
height = image['height'],
|
||||||
rowstride = image['rowstride']
|
rowstride = image['rowstride']
|
||||||
)
|
)
|
||||||
|
|
||||||
self.clipboard.set_image(image)
|
self.clipboard.set_image(image)
|
||||||
self.clipboard.store()
|
self.clipboard.store()
|
||||||
|
|
||||||
|
# 读图片
|
||||||
|
elif params['action'] == 'wait_for_image':
|
||||||
|
output = self.clipboard.wait_for_image()
|
||||||
|
output = pixbuf_to_dict(output, 'noname.png')
|
||||||
|
|
||||||
# 清除剪切板
|
# 清除剪切板
|
||||||
elif params['action'] == 'clear':
|
elif params['action'] == 'clear':
|
||||||
self.clipboard.clear()
|
self.clipboard.clear()
|
||||||
|
|
||||||
# 回调给前端
|
# 回调给前端
|
||||||
if callback and output:
|
if callback:
|
||||||
scripts = 'native.$emit("' + callback + '",' + json.dumps(output) + ')'
|
scripts = 'native.$emit("' + callback + '",' + json.dumps(output) + ')'
|
||||||
print(scripts)
|
|
||||||
self.webview.evaluate_javascript(scripts, -1)
|
self.webview.evaluate_javascript(scripts, -1)
|
||||||
|
|
||||||
# 退出app
|
# 退出app
|
||||||
|
@ -196,17 +187,7 @@ class WebKitWindow(Gtk.Window):
|
||||||
case 'image':
|
case 'image':
|
||||||
filename = params['value']
|
filename = params['value']
|
||||||
pixbuf = Pixbuf.new_from_file(filename)
|
pixbuf = Pixbuf.new_from_file(filename)
|
||||||
image = {
|
image = pixbuf_to_dict(pixbuf, filename)
|
||||||
"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) + ')'
|
scripts = 'native.$emit("' + callback + '",' + json.dumps(image) + ')'
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @author yutent<yutent.io@gmail.com>
|
||||||
|
# @date 2023/07/28 14:39:33
|
||||||
|
|
||||||
|
|
||||||
|
def get_monitor_info(monitor):
|
||||||
|
return {
|
||||||
|
"model": monitor.props.model,
|
||||||
|
"scale_factor": monitor.props.scale_factor,
|
||||||
|
"manufacturer": monitor.props.manufacturer,
|
||||||
|
"refresh_rate": monitor.props.refresh_rate,
|
||||||
|
"is_primary": monitor.is_primary(),
|
||||||
|
"geometry": {
|
||||||
|
"width": monitor.props.geometry.width,
|
||||||
|
"height": monitor.props.geometry.height,
|
||||||
|
"x": monitor.props.geometry.x,
|
||||||
|
"y": monitor.props.geometry.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def pixbuf_to_dict(pixbuf, filename = ''):
|
||||||
|
has_alpha = pixbuf.get_has_alpha()
|
||||||
|
|
||||||
|
# 没有apha通道时, get_pixels() 得到像素矩阵会出现极个别像素出现alpha通道
|
||||||
|
# 所以, 这里强制设置alpha通道为false, 补全像素矩阵的数据
|
||||||
|
if has_alpha is False:
|
||||||
|
pixbuf = pixbuf.add_alpha(False, 0, 0, 0)
|
||||||
|
|
||||||
|
if pixbuf:
|
||||||
|
image = {
|
||||||
|
"width": pixbuf.get_width(),
|
||||||
|
"height": pixbuf.get_height(),
|
||||||
|
"colorspace": pixbuf.get_colorspace(),
|
||||||
|
"has_alpha": has_alpha,
|
||||||
|
"bits_per_sample": pixbuf.get_bits_per_sample(),
|
||||||
|
"rowstride": pixbuf.get_rowstride(),
|
||||||
|
"filepath": filename,
|
||||||
|
"length": pixbuf.get_byte_length(),
|
||||||
|
"bytes": list(pixbuf.get_pixels())
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
image = None
|
||||||
|
|
||||||
|
return image
|
Reference in New Issue