main.py
# _*_ coding: utf-8 _*_
"""
Time: 2021/7/11 15:47
Author: WJY(YunYiJia)
Version: V 0.1
File: main.py
Describe: Blog link: https://blog.csdn.net/MeYungle
"""
from pynput.keyboard import Key, Listener
from view import ExampleApp
class Run:
def __init__(self):
self.press_ctrl = False
self.press_alt = False
self.running = False
# 监听按下
def on_press(self, key):
if key == Key.ctrl_l:
self.press_ctrl = True
if key == Key.alt_l:
self.press_alt = True
if self.press_alt and str(key) == '<68>':
if not self.running: # 如果没有在运行中
self.running = True
print('启动程序')
app = ExampleApp()
app.mainloop()
self.running = False
# 监听抬起
def on_release(self, key):
if key == Key.ctrl_l:
self.press_ctrl = False
if key == Key.alt_l:
self.press_ctrl = False
def listener_key(self):
print('监听热键Ctrl + Alt + D')
with Listener(on_press=self.on_press, on_release=self.on_release) as listener:
listener.join()
# 停止监视
listener.stop()
if __name__ == '__main__':
run = Run()
run.listener_key()
baiDuAI.py
# _*_ coding: utf-8 _*_
"""
Time: 2021/7/11 15:21
Author: WJY(YunYiJia)
Version: V 0.1
File: baiDuAI.py
Describe: Blog link: https://blog.csdn.net/MeYungle
"""
# encoding:utf-8
import random
import time
import requests
from hashlib import md5
# 百度Ai开放平台
# client_id 为官网获取的AK, client_secret 为官网获取的SK
def get_token():
host = 'https://aip.baidubce.com/oauth/2.0/token'
params = {
"grant_type": "client_credentials",
"client_id": "wZn5KOfHTystucXXXXXXXX",
"client_secret": "7uxYWK5KdyBXXXXXXXXXXX"
}
response = requests.get(host, params=params)
if response:
return response.json()['access_token']
def ocr_api(img_io):
import base64
request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general"
# 二进制方式打开图片文件
# f = open('txtImg.jpg', 'rb')
img = base64.b64encode(img_io)
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(request_url, params={'access_token': get_token()}, data={"image": img}, headers=headers)
if response:
print(response.json())
return response.json().get('words_result', [])
def fanyi(word):
# return fanyi_by_baidu(word)
return fanyi_by_youdao(word)
# 百度翻译开放平台
# 有查询限制,免费接口每秒只能查询一次
def fanyi_by_baidu(word):
params = {
'q': str(word),
'from': 'en',
'to': 'zh',
'appid': '20210711000800000',
'salt': str(int(time.time()))
}
sign_str = params['appid'] + params['q'] + params['salt'] + 'aPw7Lixxxxxxxxxx'
sign = md5(sign_str.encode()).hexdigest()
url = 'https://fanyi-api.baidu.com/api/trans/vip/translate'
res = requests.get(url, params={**params, 'sign': sign})
print(res.json())
return res.json()['trans_result'][0]['dst']
# 无限制
def fanyi_by_youdao(word, lang=None):
if lang is None:
lang = ['AUTO', 'AUTO']
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36',
'Referer': 'http://fanyi.youdao.com/',
'Cookie': 'OUTFOX_SEARCH_USER_ID=-148473857@10.169.0.83; JSESSIONID=aaafbpaaZm1Q5-_wxwLgx; OUTFOX_SEARCH_USER_ID_NCOO=982336911.512214; ___rl__test__cookies=1587617780880',
}
data = {
'i': word, 'from': lang[0], 'to': lang[1], 'smartresult': 'dict', 'client': 'fanyideskweb',
'salt': None, 'sign': None, 'ts': None,
'bv': md5(headers['User-Agent'].encode('utf-8')).hexdigest(),
'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
ts = str(int(time.time()) * 1000)
salt = ts + str(int(random.random() * 10))
data['i'] = word
data['ts'] = ts
data['salt'] = salt
data['sign'] = md5(f"fanyideskweb{word}{salt}Y2FYu%TNSbMCxc3t2u^XT".encode('utf-8')).hexdigest()
# 发送请求 提取数据
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
response = requests.post(url, data=data, headers=headers)
print(word)
print(response.text)
res = response.json().get('translateResult')
# print(res)
# 如果无法识别语种则使用 英译中 进行翻译
return ''.join([res['tgt'] for res in res[0]]) if res else fanyi_by_youdao(word, ['en', 'zh-CHS'])
if __name__ == '__main__':
print(fanyi('hello'))
view.py
# _*_ coding: utf-8 _*_
"""
Time: 2021/7/11 12:19
Author: WJY(YunYiJia)
Version: V 0.1
File: view.py
Describe: Blog link: https://blog.csdn.net/MeYungle
"""
import ctypes
import time
import tkinter as tk
from PIL import Image, ImageTk, ImageFilter, ImageGrab
from io import BytesIO
from baiDuAI import ocr_api, fanyi
# 调用api设置成由应用程序缩放(防止模糊)
ctypes.windll.shcore.SetProcessDpiAwareness(1)
# 调用api获得当前的缩放因子(当前缩放比例)
# ScaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)
def xy_change(x_begin, y_begin, x_end, y_end):
if x_begin < x_end:
min_x = x_begin
max_x = x_end
else:
min_x = x_end
max_x = x_begin
if y_begin < y_end:
min_y = y_begin
max_y = y_end
else:
min_y = y_end
max_y = y_begin
return (min_x, min_y), (max_x, max_y)
def img_as_io(img):
buffer = BytesIO() # 创建二进制数据IO缓存
img.save(buffer, 'PNG') # 保存到缓存
return buffer.getvalue() # 再读取缓存
def txt_colour_compute(img):
"""
:param img: PIL图片对象
:return: 根据图片的四个角的颜色值,获取图片颜色的反色
"""
img_value = img.load() # 加载图片颜色值分布
x, y = img.size # 截取的区域图片大小
average_value = sum(img_value[1, 1] + img_value[x - 1, 1] + img_value[1, y - 1] + img_value[x - 1, y - 1])
return 'white' if average_value < 1530 else 'black'
class ExampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
# 设置缩放因子
# self.tk.call('tk', 'scaling', ScaleFactor / 75)
self.width = self.winfo_screenwidth() # 获取当前屏幕宽度 缩放后的(不符合需求后期要改)
self.height = self.winfo_screenheight() # 获取当前屏幕高度
self.attributes("-fullscreen", True) # 铺满全屏
self.x = self.y = 0
# 创建画布,设置无边框
self.canvas = tk.Canvas(self, width=self.width, height=self.height, cursor="cross", bd=0, highlightthickness=0)
self.canvas.pack(side="top", fill="both", expand=True)
self.canvas.bind("<ButtonPress-1>", self.on_button_press) # 绑定鼠标左键按下
self.canvas.bind("<B1-Motion>", self.on_move_press) # 绑定鼠标移动
self.canvas.bind("<ButtonRelease-1>", self.on_button_release) # 绑定鼠标左键抬起
self.canvas.bind("<ButtonRelease-3>", lambda x: self.destroy()) # 绑定右键 退出主事件循环
self.rect = None
self.start_x = None
self.start_y = None
self.region_bg = None
self.txt_colour = None
self.translate_result = []
self._draw_image()
def _draw_image(self):
# self.im = Image.open('01.png')
self.im = ImageGrab.grab() # 截取屏幕
self.im = self.im.resize((self.width, self.height), Image.LANCZOS) # 缩放图片
self.tk_im = ImageTk.PhotoImage(self.im) # 图片对象转换
self.canvas.create_image(0, 0, anchor="nw", image=self.tk_im) # 创建画布图片
def on_button_press(self, event):
# 保存鼠标拖动开始位置
self.start_x = event.x
self.start_y = event.y
for res in self.translate_result:
self.canvas.delete(res)
self.translate_result.clear()
# 如果不存在则创建矩形
if not self.rect:
# 创建矩形,设置矩形线条颜色
self.rect = self.canvas.create_rectangle(self.x, self.y, 1, 1, outline='Orange')
def on_move_press(self, event):
cur_x, cur_y = (event.x, event.y)
# 拖动鼠标时展开矩形
self.canvas.coords(self.rect, self.start_x, self.start_y, cur_x, cur_y)
def on_button_release(self, event):
start_xy, end_xy = xy_change(self.start_x, self.start_y, event.x, event.y) # 坐标处理处理反向截取矩形
self.start_x, self.start_y = start_xy
endx, endy = end_xy
region = self.im.crop((*start_xy, endx + 1, endy + 1)) # 截取矩形内的图像(加大1px防止有边线)
if sum(region.size) > 10: # 判断是否位误触截取区域小于10px不做操作
self.translate(region)
def translate(self, region):
self.txt_colour = txt_colour_compute(region) # 粗略计算文本颜色
self.region_bg = ImageTk.PhotoImage(region.filter(ImageFilter.GaussianBlur(radius=3))) # 高斯模糊后当作背景
bg = self.canvas.create_image(self.start_x, self.start_y, anchor="nw", image=self.region_bg) # 添加文字背景
self.translate_result.append(bg) # 把文字背景添加到本次翻译结果列表,方便一次性删除
msg_inx = self.canvas.create_text( # 添加提示文字
*map(lambda a, b: a + b, (self.start_x, self.start_y), (60, 12)), text='正在翻译请稍后', font=("微软雅黑", 12),
fill=self.txt_colour
)
words = ocr_api(img_as_io(region)) # img对象转BytesIO后 调用Baidu文字识别api
for word in words:
self.add_txt(
fanyi(word['words']),
word['location']['left'],
word['location']['top'],
word['location']['width'],
word['location']['height']
)
# time.sleep(1) # 因百度免费api每秒查询量为1所以这里睡眠1秒
self.canvas.delete(msg_inx) # 删除提示文字
def add_txt(self, word, word_x, word_y, word_w, word_h):
"""
:param word: 文字
:param word_x: 文字x坐标(在截取图片中的坐标/相对坐标)
:param word_y: 文字y坐标(相对相对坐标)
:param word_w: 文字宽度
:param word_h: 文字高度
:return:
"""
start_xy = self.start_x, self.start_y # 起始坐标
word_xy = word_x, word_y # 文字坐标
word_width_height = int(word_w // 2), int(word_h // 2) # 文字宽高
location = map(lambda a, b, c: a + b + c, start_xy, word_xy, word_width_height) # 定位文字位置
# 下面这行代码用于控制文字位置、样式、大小和颜色
inx = self.canvas.create_text(*location, text=word, font=("微软雅黑", int(word_h // 2)), fill=self.txt_colour)
self.translate_result.append(inx)
if __name__ == "__main__":
app = ExampleApp()
app.mainloop()