This repository has been archived on 2023-09-06. You can view files and clone it, but cannot push or open issues/pull-requests.
yutent
/
py-gtk-notes
Archived
1
0
Fork 0

修复gtk读取图片像素时alpha通道异常的bug

master
yutent 2023-07-28 17:51:37 +08:00
parent c0011b582d
commit 8ab9ea2dd9
9 changed files with 164 additions and 108 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__

115
app.js
View File

@ -5,44 +5,79 @@
*/ */
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: ''
} }
async function test2() { static styles = css`
native.clipboard.writeText('这是一段写进剪切板的文本') .output {
// native.handler('blabla', { foo: 'bar' }).then(r => { max-width: 100%;
// $('#output').innerHTML = JSON.stringify(r) white-space: pre-wrap;
// }) word-break: break-all;
} }
`
bind($('.btn1'), 'click', test1) render() {
bind($('.btn2'), 'click', test2) return html`
bind($('.btn3'), 'click', async function () { <button @click=${this.test1}>Test 1</button>
// window.open('about:blank') <button @click=${this.test2}>Test 2</button>
// let img = await native.clipboard.writeImage('/code/gtk/webkit/debian.png')
let img = await native.image('/code/gtk/webkit/debian.png') <a target="_blank" href="about:blank">打开控制台</a>
native.clipboard.writeImage(img)
// native.clipboard.writeImage('/code/gtk/webkit/debian.png') <div class="output">loading...</div>
try {
$('img').src = URL.createObjectURL(await img.export()) <input value=${this.input} />
} catch (err) {
alert(err) <hr />
} <button @click=${this.writeImage}>写图片到剪切板</button>
}) <button
bind($('.btn4'), 'click', async function () { @click=${async function () {
native.quit() native.quit()
// native.clipboard.clear() }}
}) >
退出
</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>
`
}
bind($('.btn5'), 'click', async function () { 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() native.tray()
}) }
bind($('.btn6'), 'click', async function () { async register() {
// console.log(await native.globalShortcut.enabled) // console.log(await native.globalShortcut.enabled)
native.globalShortcut.register('<Ctrl>2', function () { native.globalShortcut.register('<Ctrl>2', function () {
@ -50,13 +85,27 @@ bind($('.btn6'), 'click', async function () {
}) })
// console.log(await native.screen.getAllDisplays()) // console.log(await native.screen.getAllDisplays())
// console.log(await native.screen.getPrimaryDisplay()) // console.log(await native.screen.getPrimaryDisplay())
}) }
bind($('textarea'), 'paste', async function (ev) { async pasteImg(ev) {
let items = ev.clipboardData.items 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) { for (let it of items) {
let file = it.getAsFile() let file = it.getAsFile()
$('img').src = URL.createObjectURL(file) if (file) {
this.img = URL.createObjectURL(file)
break break
} }
}) }
}
}
App.reg('app')

View File

@ -1,5 +0,0 @@
import fs from 'iofs'
let buf = fs.cat('./debian.png')
console.log(buf)
console.log([...buf], buf.byteLength)

View File

@ -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>

View File

@ -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
View File

@ -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
notes/__init__.py Normal file
View File

46
notes/utils.py Normal file
View File

@ -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

BIN
red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B