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 { $, bind } from 'wkit'
import { html, css, Component } from 'wkit'
async function test1() {
let txt = await native.clipboard.readText()
$('input').value = txt
class App extends Component {
static props = {
input: '',
img: ''
}
async function test2() {
native.clipboard.writeText('这是一段写进剪切板的文本')
// native.handler('blabla', { foo: 'bar' }).then(r => {
// $('#output').innerHTML = JSON.stringify(r)
// })
static styles = css`
.output {
max-width: 100%;
white-space: pre-wrap;
word-break: break-all;
}
`
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 () {
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()
// 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()
})
}
bind($('.btn6'), 'click', async function () {
async register() {
// console.log(await native.globalShortcut.enabled)
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.getPrimaryDisplay())
})
}
bind($('textarea'), 'paste', async function (ev) {
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()
$('img').src = URL.createObjectURL(file)
if (file) {
this.img = URL.createObjectURL(file)
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>
<style>
#output {max-width:100%;white-space: pre-wrap;word-break: break-all;}
</style>
<script type="module" src="/app.js"></script>
</head>
<body>
<button class="btn1">Test 1</button>
<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>
<wc-app></wc-app>
</body>
</html>

View File

@ -83,6 +83,7 @@ class NativeImage {
this.width = obj.width
this.height = obj.height
this.type = MIME_TYPES[obj.filepath.split('.').pop()]
console.log(obj)
}
toPixbuf() {
@ -179,7 +180,9 @@ Object.assign(native, {
return handler('clipboard', { action: 'set_text', value }, null)
},
readImage() {
return handler('clipboard', { action: 'wait_for_image' })
return handler('clipboard', { action: 'wait_for_image' }).then(r =>
r ? new NativeImage(r) : r
)
},
writeImage(value) {
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.GdkPixbuf import Pixbuf
from notes.utils import *
# 优先尝试使用指示器, 没有再使用 Gtk.StatusIcon
try:
gi.require_version('AyatanaAppIndicator3', '0.1')
@ -22,21 +24,6 @@ except (ValueError, ImportError):
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):
def __init__(self):
@ -164,6 +151,7 @@ class WebKitWindow(Gtk.Window):
# 前端传进来的值, 如果是路径的话, 直接读取
if type(image) == str:
image = Pixbuf.new_from_file(image)
print(pixbuf_to_dict(image, params['value']))
else:
image = Pixbuf.new_from_data(
data = bytes(image['bytes']),
@ -174,18 +162,21 @@ class WebKitWindow(Gtk.Window):
height = image['height'],
rowstride = image['rowstride']
)
self.clipboard.set_image(image)
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':
self.clipboard.clear()
# 回调给前端
if callback and output:
if callback:
scripts = 'native.$emit("' + callback + '",' + json.dumps(output) + ')'
print(scripts)
self.webview.evaluate_javascript(scripts, -1)
# 退出app
@ -196,17 +187,7 @@ class WebKitWindow(Gtk.Window):
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())
}
image = pixbuf_to_dict(pixbuf, filename)
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