├── Icons
├── eraser.png
├── gear.png
├── manga.png
├── play.png
├── play1.png
├── forward.png
├── forward1.png
├── menu (1).png
├── twitter.png
├── whiteBG.jpg
├── translation.png
├── colordownload.png
├── down-chevron.png
└── darkmode.qrc
├── Code
├── FileHandling.py
├── DownloadTweet.py
├── Retranslate.py
├── Configer.py
├── addText.py
├── RectangleManipulation.py
├── IndividualPage.py
├── Canvas.py
├── TranslateManga.py
├── Translation.py
├── ManualTranslation.py
├── settingsGUI.py
├── Main.py
└── darkmode.py
├── LICENSE.txt
├── requirements.txt
└── README.md
/Icons/eraser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/eraser.png
--------------------------------------------------------------------------------
/Icons/gear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/gear.png
--------------------------------------------------------------------------------
/Icons/manga.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/manga.png
--------------------------------------------------------------------------------
/Icons/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/play.png
--------------------------------------------------------------------------------
/Icons/play1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/play1.png
--------------------------------------------------------------------------------
/Icons/forward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/forward.png
--------------------------------------------------------------------------------
/Icons/forward1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/forward1.png
--------------------------------------------------------------------------------
/Icons/menu (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/menu (1).png
--------------------------------------------------------------------------------
/Icons/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/twitter.png
--------------------------------------------------------------------------------
/Icons/whiteBG.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/whiteBG.jpg
--------------------------------------------------------------------------------
/Icons/translation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/translation.png
--------------------------------------------------------------------------------
/Icons/colordownload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/colordownload.png
--------------------------------------------------------------------------------
/Icons/down-chevron.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asewvtft545456/MangaTranslator/HEAD/Icons/down-chevron.png
--------------------------------------------------------------------------------
/Icons/darkmode.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | whiteBG.jpg
4 | translation.png
5 | down-chevron.png
6 | menu (1).png
7 | forward.png
8 | forward1.png
9 | colordownload.png
10 | play.png
11 | play1.png
12 | gear.png
13 | eraser.png
14 | twitter.png
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Code/FileHandling.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | class FileHandler:
4 | def __init__(self):
5 | self.baseDir = self.findBase()
6 | os.chdir(self.baseDir)
7 |
8 | def findBase(self):
9 | directory = os.getcwd()
10 | if "MangaTranslator" not in directory:
11 | directory = self.find_directory("MangaTranslator")
12 | return directory
13 |
14 | def find_directory(self, folderName):
15 | for r,d,f in os.walk(os.getcwd()):
16 | for folder in d:
17 | if folder == folderName:
18 | return os.path.join(r,folder)
19 |
20 | def deleteFiles(self, directory):
21 | for r,d,f in os.walk(directory):
22 | for file in f:
23 | os.remove(directory+"\\{}".format(file))
24 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2023] [Andrew Nketsiah]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | cohere==5.11.3
2 | altgraph==0.17.3
3 | beautifulsoup4==4.11.1
4 | certifi==2022.12.7
5 | cffi==1.15.1
6 | charset-normalizer==2.1.1
7 | click==8.1.3
8 | colorama==0.4.6
9 | contourpy==1.0.6
10 | cryptography==38.0.4
11 | cycler==0.11.0
12 | deep-translator==1.9.1
13 | deepl-translate==1.2.0
14 | deprecation==2.1.0
15 | dill==0.3.6
16 | docopt==0.6.2
17 | easyocr
18 | filelock==3.16.1
19 | fire==0.5.0
20 | fonttools==4.38.0
21 | fugashi==1.2.1
22 | future==0.18.2
23 | huggingface-hub==0.27.1
24 | idna==3.10
25 | imageio==2.22.4
26 | img2pdf==0.4.4
27 | imgaug==0.4.0
28 | jaconv==0.3
29 | kiwisolver==1.4.4
30 | langid==1.1.6
31 | loguru==0.6.0
32 | lxml==4.9.1
33 | manga-ocr
34 | matplotlib==3.6.2
35 | multiprocess==0.70.14
36 | networkx==2.8.8
37 | ninja==1.11.1
38 | numpy
39 | oauthlib==3.2.2
40 | translators==5.5.5
41 | opencv-contrib-python==4.5.5.62
42 | opencv-python==4.6.0.66
43 | opencv-python-headless==4.5.4.60
44 | packaging==24.2
45 | pathos==0.3.0
46 | pefile==2022.5.30
47 | pikepdf==6.2.5
48 | Pillow
49 | pipreqs==0.4.11
50 | pox==0.3.2
51 | ppft==1.7.6.6
52 | pyclipper==1.3.0.post4
53 | pycparser==2.21
54 | PyExecJS==1.5.1
55 | pyinstaller-hooks-contrib==2022.14
56 | pyparsing==3.0.9
57 | pyperclip==1.8.2
58 | PyQt5==5.15.7
59 | PyQt5-Qt5==5.15.2
60 | PyQt5-sip==12.11.0
61 | python-bidi
62 | python-dateutil==2.8.2
63 | PyWavelets==1.4.1
64 | pywin32-ctypes==0.2.0
65 | PyYAML==6.0.2
66 | qimage2ndarray==1.9.0
67 | regex==2024.11.6
68 | requests==2.32.3
69 | requests-oauthlib==1.3.1
70 | scikit-image==0.19.3
71 | scipy==1.9.3
72 | sentencepiece==0.1.97
73 | shapely==2.0.0
74 | six==1.16.0
75 | soupsieve==2.3.2.post1
76 | termcolor==2.1.1
77 | tifffile==2022.10.10
78 | tokenizers==0.21.0
79 | torch==1.13.0
80 | torchvision==0.14.0
81 | tqdm==4.67.1
82 | transformers==4.48.0
83 | tweepy==4.12.1
84 | typeguard==2.13.3
85 | typer==0.7.0
86 | typing_extensions==4.12.2
87 | unidic-lite==1.0.8
88 | urllib3==2.3.0
89 | win32-setctime==1.1.0
90 | yarg==0.1.9
91 |
--------------------------------------------------------------------------------
/Code/DownloadTweet.py:
--------------------------------------------------------------------------------
1 | import tweepy
2 | import requests
3 | import os
4 | import json
5 | from Configer import Settings
6 | import ast
7 |
8 | class Twitter:
9 | def __init__(self):
10 | self.setting = Settings()
11 | self.setting.getUpdateInfo()
12 | consumer_key = self.setting.consumer_key
13 | consumer_secret = self.setting.consumer_secret
14 | access_token = self.setting.access_token
15 | access_token_secret = self.setting.access_token_secret
16 | bearer_token = ""
17 | if ast.literal_eval(self.setting.bearer_token) == list:
18 | bearer_token = "%".join(ast.literal_eval(self.setting.bearer_token))
19 | else:
20 | bearer_token = self.setting.bearer_token.strip("[]")
21 |
22 | auth = tweepy.OAuth1UserHandler(
23 | consumer_key=consumer_key, consumer_secret=consumer_secret,
24 | access_token=access_token, access_token_secret=access_token_secret
25 | )
26 |
27 | self.api = tweepy.API(auth)
28 |
29 | def getImageUrl(self, link):
30 | self.setting.getUpdateInfo()
31 | try:
32 | imageURL = []
33 | id = link.split('/')[-1]
34 | status = self.api.get_status(str(id))._json
35 | for url in status['extended_entities']['media']:
36 | imageURL.append(url['media_url'])
37 | except:
38 | print("Error")
39 | pass
40 | return imageURL
41 |
42 |
43 | def download(self, urls):
44 | files = []
45 | directory = self.setting.downLoad
46 | try:
47 | for url in urls:
48 | name = directory+'\\'+ url.split('/')[-1]
49 | data = requests.get(url).content
50 | with open(name, 'wb') as file:
51 | file.write(data)
52 | files.append(name)
53 | except:
54 | print("Error")
55 | pass
56 | return files
57 |
--------------------------------------------------------------------------------
/Code/Retranslate.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QRunnable, pyqtSignal, QObject
2 | import qimage2ndarray
3 | import numpy as np
4 | import cv2
5 | from pprint import pprint
6 | from loguru import logger
7 | from Translation import MangaBag
8 |
9 | class ReWorker(QObject):
10 | result = pyqtSignal(object)
11 | finished = pyqtSignal()
12 | progress = pyqtSignal(int)
13 |
14 | class Retranslate(QRunnable):
15 | def __init__(self, storedList, translator, langauge):
16 | super(Retranslate, self).__init__()
17 | self.preList = storedList
18 | self.translator = translator
19 | self.signals = ReWorker()
20 | self.portions = (100 / len(self.preList))/3
21 | self.cnt = 0
22 | self.source = langauge
23 | self.manga = MangaBag()
24 |
25 | def run (self):
26 | newImg = []
27 | try:
28 | for image, rectangles, japanese in self.preList:
29 | if japanese == {}:
30 | newImg.append(image)
31 | continue
32 |
33 | fontSize, thickness = self.manga.getFontSizeThickness(image)
34 | img1 = cv2.imread(r"{}".format(image))
35 | cvImage = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
36 | self.cnt += self.portions
37 | self.signals.progress.emit(self.cnt)
38 |
39 | copyJapanese = japanese.copy()
40 | pprint(copyJapanese)
41 |
42 | newTranslate = self.manga.translate(copyJapanese, self.translator, self.source)
43 | addNewLine1 = self.manga.addNewLine(image, newTranslate, rectangles, cv2.FONT_HERSHEY_DUPLEX, fontSize, thickness)
44 | self.cnt += self.portions
45 | self.signals.progress.emit(self.cnt)
46 |
47 | final = self.manga.write(cvImage, rectangles, addNewLine1, fontSize, thickness)
48 | self.cnt += self.portions
49 | self.signals.progress.emit(self.cnt)
50 |
51 | myarray = np.array(final)
52 | image1 = qimage2ndarray.array2qimage(myarray)
53 | newImg.append(image1)
54 | except:
55 | self.signals.finished.emit()
56 | else:
57 | self.signals.result.emit(newImg)
58 | self.signals.finished.emit()
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MangaTranslator
2 | This is a program that translates manga primary from Japanese to English (tho it can also trans other languages to english).
3 |
4 |
5 | # Installation
6 | Clone or download the repository.
7 | I recommend running the program within a virtual environment.
8 |
9 | If you're using VScode, open the repository, go to the command pallete, type "Create Environment", and click.
10 | Vscode will create the virtual environment and install everything in requirement.txt. If it doesn't type "pip install -r requirements.txt" in the terminal.
11 |
12 | If you don't have VScode, open the repo within your IDE and go to the terminal:
13 | 1) Type "virtualenv venv"
14 | 2) Then activate the virtual environment by typing ".venv\Scripts\activate"
15 | 3) Finally, install the required packages by typing "pip install -r requirements.txt"
16 | 4) Run Main.py
17 |
18 | # Manga Translator
19 |
20 | This is what the App looks like.
21 | On the left, there are four buttons, Automatic, Manual, settings button, and a twitter button.
22 |
23 | # Automatic Translation
24 | By default, the app is set to automatic translation.
25 | You can manipulate the automatic translation by clicking on the automatic button as seen below.
26 |
27 |
28 | The "Combine Overlap" checkbox combines overlapping rectangle and "Combine Neighbors" checkbox combines rectangles within a certain distance, which is decided by the slider. The "Retranslate current page" checkbox translates a single page if you don't like how that page turned out.
29 | Example of automatic translation:
30 |
31 |
32 | # Manual Translation
33 | You can manually translate by clicking on the Manual button. You draw rectangles on the text you want translated.
34 | On the left, you change the color of the rectangles, the text, etc.
35 |
36 | Before:
37 |
38 |
39 | After:
40 |
41 |
42 |
43 | # Settings button
44 | The most important thing here is that you can change the translator. By default it is set to Bing.
45 |
46 | # Twitter button
47 | When you click on the the button, a bar will appear at the top. You can download "manga" from twitter.
48 |
49 | You need to sign up on https://developer.twitter.com to the API key and other required keys.
50 |
51 | Example of a valid link would be: https://twitter.com/sanka_kumaru/status/1589452581910335488
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Code/Configer.py:
--------------------------------------------------------------------------------
1 | import configparser
2 | import os
3 | from FileHandling import FileHandler
4 |
5 | class Settings:
6 | def __init__(self):
7 | self.config = configparser.ConfigParser()
8 | setting = self.getConfig()
9 | self.cropText = setting.get("Paths", "cropText")
10 | self.Translated = setting.get("Paths", "Translated")
11 | self.downLoad = setting.get("Paths", "Download")
12 | self.consumer_key = setting.get("Twitter", "Consumer key", raw=True)
13 | self.consumer_secret = setting.get("Twitter", "Consumer secret", raw=True)
14 | self.access_token = setting.get("Twitter", "Access token", raw=True)
15 | self.access_token_secret = setting.get("Twitter", "Access token secret", raw=True)
16 | self.bearer_token = setting.get("Twitter", "Bearer token", raw=True)
17 |
18 | def createConfig(self):
19 | file = FileHandler()
20 | self.config.add_section("Paths")
21 | if file.find_directory("cropText"):
22 | self.config.set("Paths", "cropText", file.find_directory("cropText"))
23 | else:
24 | path = os.path.join(os.getcwd(),"cropText")
25 | os.mkdir(path)
26 | self.config.set("Paths", "cropText", path)
27 | if file.find_directory("Translated"):
28 | self.config.set("Paths", "Translated", file.find_directory("Translated"))
29 | else:
30 | pathT = os.path.join(os.getcwd(),"Translated")
31 | os.mkdir(pathT)
32 | self.config.set("Paths", "Translated", pathT)
33 | self.config.set("Paths", "Download", "")
34 | self.config.add_section("Twitter")
35 | self.config.set("Twitter", "Consumer key", "None")
36 | self.config.set("Twitter", "Consumer secret", "None")
37 | self.config.set("Twitter", "Access token", "None")
38 | self.config.set("Twitter", "Access token secret", "None")
39 | self.config.set("Twitter", "Bearer token", "None")
40 |
41 |
42 | with open("settings.ini", "w") as setting:
43 | self.config.write(setting)
44 |
45 | def getConfig(self):
46 | if not os.path.exists("settings.ini"):
47 | self.createConfig()
48 |
49 | self.config = configparser.ConfigParser()
50 | self.config.read("settings.ini")
51 | return self.config
52 |
53 | def updateSetting(self, section, setting, value):
54 | self.config = self.getConfig()
55 | self.config.set(section, setting, value)
56 | with open("settings.ini", "w") as updated:
57 | self.config.write(updated)
58 |
59 | def getUpdateInfo(self):
60 | self.cropText = self.config.get("Paths", "cropText")
61 | self.Translated = self.config.get("Paths", "Translated")
62 | self.downLoad = self.config.get("Paths", "Download")
63 | self.consumer_key = self.config.get("Twitter", "Consumer key", raw=True)
64 | self.consumer_secret = self.config.get("Twitter", "Consumer secret", raw=True)
65 | self.access_token = self.config.get("Twitter", "Access token", raw=True)
66 | self.access_token_secret = self.config.get("Twitter", "Access token secret", raw=True)
67 | self.bearer_token = self.config.get("Twitter", "Bearer token", raw=True)
--------------------------------------------------------------------------------
/Code/addText.py:
--------------------------------------------------------------------------------
1 | #Code was written by Yoni Chechik on Stack Overflow
2 | #Original code: https://stackoverflow.com/questions/27647424/opencv-puttext-new-line-character
3 |
4 | from typing import Optional, Tuple
5 |
6 | import cv2
7 | import numpy as np
8 |
9 |
10 | def add_text_to_image(
11 | image_rgb: np.ndarray,
12 | label: str,
13 | top_left_xy: Tuple = (0, 0),
14 | font_scale: float = 1,
15 | font_thickness: float = 1,
16 | font_face=cv2.FONT_HERSHEY_SIMPLEX,
17 | font_color_rgb: Tuple = (0, 0, 255),
18 | bg_color_rgb: Optional[Tuple] = None,
19 | outline_color_rgb: Optional[Tuple] = None,
20 | line_spacing: float = 1,
21 | ):
22 | """
23 | Adds text (including multi line text) to images.
24 | You can also control background color, outline color, and line spacing.
25 |
26 | outline color and line spacing adopted from: https://gist.github.com/EricCousineau-TRI/596f04c83da9b82d0389d3ea1d782592
27 | """
28 | OUTLINE_FONT_THICKNESS = 3 * font_thickness
29 |
30 | im_h, im_w = image_rgb.shape[:2]
31 |
32 | for line in label.splitlines():
33 | x, y = top_left_xy
34 |
35 | # ====== get text size
36 | if outline_color_rgb is None:
37 | get_text_size_font_thickness = font_thickness
38 | else:
39 | get_text_size_font_thickness = OUTLINE_FONT_THICKNESS
40 |
41 | (line_width, line_height_no_baseline), baseline = cv2.getTextSize(
42 | line,
43 | font_face,
44 | font_scale,
45 | get_text_size_font_thickness,
46 | )
47 | line_height = line_height_no_baseline + baseline
48 |
49 | if bg_color_rgb is not None and line:
50 | # === get actual mask sizes with regard to image crop
51 | if im_h - (y + line_height) <= 0:
52 | sz_h = max(im_h - y, 0)
53 | else:
54 | sz_h = line_height
55 |
56 | if im_w - (x + line_width) <= 0:
57 | sz_w = max(im_w - x, 0)
58 | else:
59 | sz_w = line_width
60 |
61 | # ==== add mask to image
62 | if sz_h > 0 and sz_w > 0:
63 | bg_mask = np.zeros((sz_h, sz_w, 3), np.uint8)
64 | bg_mask[:, :] = np.array(bg_color_rgb)
65 | image_rgb[
66 | y : y + sz_h,
67 | x : x + sz_w,
68 | ] = bg_mask
69 |
70 | # === add outline text to image
71 | if outline_color_rgb is not None:
72 | image_rgb = cv2.putText(
73 | image_rgb,
74 | line,
75 | (x, y + line_height_no_baseline), # putText start bottom-left
76 | font_face,
77 | font_scale,
78 | outline_color_rgb,
79 | OUTLINE_FONT_THICKNESS,
80 | cv2.LINE_AA,
81 | )
82 | # === add text to image
83 | image_rgb = cv2.putText(
84 | image_rgb,
85 | line,
86 | (x, y + line_height_no_baseline), # putText start bottom-left
87 | font_face,
88 | font_scale,
89 | font_color_rgb,
90 | font_thickness,
91 | cv2.LINE_AA,
92 | )
93 | top_left_xy = (x, y + int(line_height * line_spacing))
94 |
95 | return image_rgb
96 |
--------------------------------------------------------------------------------
/Code/RectangleManipulation.py:
--------------------------------------------------------------------------------
1 | import math
2 | from pprint import pprint
3 |
4 | class Overlap:
5 | def __init__(self, x1, y1, x2, y2, id):
6 | self.x1 = x1
7 | self.y1 = y1
8 | self.x2 = x2
9 | self.y2 = y2
10 | self.id = id
11 |
12 | def combine(self, other):
13 | x1 = min(self.x1, other.x1)
14 | y1 = min(self.y1, other.y1)
15 | x2 = max(self.x2, other.x2)
16 | y2 = max(self.y2, other.y2)
17 | id = self.id + "_" + other.id
18 | return Overlap(x1, y1, x2, y2, id)
19 |
20 | def is_overlap(self, other):
21 | if (self.x1 < other.x2) and (self.x2 > other.x1) and (self.y1 < other.y2) and (self.y2 > other.y1):
22 | return True
23 | else:
24 | return False
25 |
26 | def combine_overlapping_rectangles(rectangles):
27 | combined_rectangles = {}
28 | for id, rectangle in rectangles.items():
29 | combined = False
30 | for other_id, other_rectangle in combined_rectangles.items():
31 | if rectangle.is_overlap(other_rectangle):
32 | new_rectangle = rectangle.combine(other_rectangle)
33 | combined_rectangles.pop(other_id)
34 | combined_rectangles[new_rectangle.id] = new_rectangle
35 | combined = True
36 | break
37 | if not combined:
38 | combined_rectangles[rectangle.id] = rectangle
39 | return reFormat(combined_rectangles)
40 |
41 | class Combine:
42 | def __init__(self, x1, y1, x2, y2, id):
43 | self.x1 = x1
44 | self.y1 = y1
45 | self.x2 = x2
46 | self.y2 = y2
47 | self.id = id
48 |
49 | def distance_to(self, other):
50 | x_distance = abs(self.x1 - other.x1)
51 | y_distance = abs(self.y1 - other.y1)
52 | return math.sqrt(x_distance**2 + y_distance**2)
53 |
54 | def combine(self, other):
55 | x1 = min(self.x1, other.x1)
56 | y1 = min(self.y1, other.y1)
57 | x2 = max(self.x2, other.x2)
58 | y2 = max(self.y2, other.y2)
59 | id = self.id + "_" + other.id
60 | return Combine(x1, y1, x2, y2, id)
61 |
62 | def combine_rectangles(rectangles, distance_threshold):
63 | combined_rectangles = {}
64 | for id, rectangle in rectangles.items():
65 | combined = False
66 | for other_id, other_rectangle in combined_rectangles.items():
67 | if rectangle.distance_to(other_rectangle) < distance_threshold:
68 | new_rectangle = rectangle.combine(other_rectangle)
69 | combined_rectangles.pop(other_id)
70 | combined_rectangles[new_rectangle.id] = new_rectangle
71 | combined = True
72 | break
73 | if not combined:
74 | combined_rectangles[rectangle.id] = rectangle
75 | return reFormat(combined_rectangles)
76 |
77 | def reFormat(dictionary):
78 | newformat = {}
79 | for z in dictionary:
80 | newformat[z] = [(dictionary[z].x1, dictionary[z].y1), (dictionary[z].x2, dictionary[z].y2)]
81 | return newformat
82 |
83 | def rectanglesCO(newDt, s):
84 | newM = {}
85 | for name in newDt:
86 | m = newDt[name]
87 | if s == 'c':
88 | newM[name] = Combine(m[0][0], m[0][1], m[1][0], m[1][1], name)
89 | else:
90 | newM[name] = Overlap(m[0][0], m[0][1], m[1][0], m[1][1], name)
91 | return newM
92 |
93 |
94 |
--------------------------------------------------------------------------------
/Code/IndividualPage.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | from PyQt5.QtCore import QRunnable, pyqtSignal, QObject
3 | import qimage2ndarray
4 | import numpy as np
5 | from pprint import pprint
6 | from RectangleManipulation import *
7 | from FileHandling import FileHandler
8 | from Configer import Settings
9 | from Translation import MangaBag
10 |
11 |
12 | class Worker(QObject):
13 | result = pyqtSignal(object)
14 | finished = pyqtSignal()
15 | progress = pyqtSignal(int)
16 |
17 |
18 | class SingleTranslate(QRunnable):
19 |
20 | def __init__(self, img, mocr, translator, combN, combO, sliderNum, langauge):
21 | super(SingleTranslate, self).__init__()
22 | self.imag1 = img
23 | self.setting = Settings()
24 | self.handling = FileHandler()
25 | self.manga = MangaBag()
26 | self.name = translator
27 | self.shouldCombN = combN
28 | self.shouldCombO = combO
29 | self.range = sliderNum * self.manga.getRatio(self.imag1) + 4
30 | self.signals = Worker()
31 | self.directory = self.setting.cropText
32 | self.portions = 100/3
33 | self.cnt = 0
34 | self.mocr = mocr
35 | self.source = langauge
36 |
37 |
38 | def locateText(self, image):
39 | myDict = self.manga.get_text(image)
40 | if self.shouldCombN and self.shouldCombO:
41 | bound1 = rectanglesCO(myDict, "c")
42 | bound2 = combine_rectangles(bound1, self.range)
43 | overlap1 = rectanglesCO(bound2, "o")
44 | overlap = combine_overlapping_rectangles(overlap1)
45 | return overlap
46 | elif self.shouldCombN and not(self.shouldCombO):
47 | bound1 = rectanglesCO(myDict, "c")
48 | bound2 = combine_rectangles(bound1, self.range)
49 | return bound2
50 | elif self.shouldCombO and not(self.shouldCombN):
51 | overlap1 = rectanglesCO(bound2, "o")
52 | overlap2 = combine_overlapping_rectangles(overlap1)
53 | return overlap2
54 | else:
55 | return myDict
56 |
57 | def run(self):
58 | try:
59 | fontSize, thickness = self.manga.getFontSizeThickness(self.imag1)
60 | self.img1 = cv2.imread(r"{}".format(self.imag1))
61 | self.image = cv2.cvtColor(self.img1, cv2.COLOR_BGR2RGB)
62 | gotten_text = self.locateText(self.image)
63 | self.cnt += self.portions
64 | self.signals.progress.emit(self.cnt)
65 | # pprint(gotten_text)
66 |
67 | finalText = self.manga.get_japanese(self.image, self.mocr, gotten_text, self.directory)
68 | self.cnt += self.portions
69 | self.signals.progress.emit(self.cnt)
70 | # pprint(finalText)
71 |
72 | newList = self.manga.translate(finalText, self.name, self.source)
73 | self.cnt += self.portions
74 | self.signals.progress.emit(self.cnt)
75 | # pprint(newList)
76 | addNewLine1 = self.manga.addNewLine(self.imag1, newList, gotten_text, cv2.FONT_HERSHEY_DUPLEX, fontSize, thickness)
77 |
78 | final = self.manga.write(self.image, gotten_text, addNewLine1, fontSize, thickness)
79 | myarray = np.array(final)
80 | image = qimage2ndarray.array2qimage(myarray)
81 | self.cnt += self.portions
82 | self.signals.progress.emit(self.cnt)
83 | except:
84 | self.signals.finished.emit()
85 | else:
86 | self.signals.result.emit(image)
87 | self.signals.finished.emit()
88 | finally:
89 | self.handling.deleteFiles(self.directory)
--------------------------------------------------------------------------------
/Code/Canvas.py:
--------------------------------------------------------------------------------
1 | from PyQt5 import QtWidgets, QtGui, QtCore
2 | from PyQt5.QtCore import Qt
3 | from PyQt5.QtCore import Qt, QPoint, QRect, QRectF, pyqtSignal
4 | from PyQt5.QtGui import QPainter, QPen, QPixmap, QColor, QTextOption, QFont, QCursor
5 | from loguru import logger
6 |
7 | class Image(QtWidgets.QLabel):
8 |
9 | def __init__(self, parent):
10 | super(Image, self).__init__(parent=parent)
11 | self.setPixmap(QtGui.QPixmap(":/newPrefix/whiteBG.jpg"))
12 | self.img = None
13 | self.image = QPixmap(":/newPrefix/whiteBG.jpg")
14 | self.begin = QPoint()
15 | self.end = QPoint()
16 | self.flag = False
17 | self.pages = {}
18 | self.connectDict = {}
19 | self.translated = {}
20 | self.japanese = {}
21 | self.color = {
22 | "White" : QColor(255, 255, 255),
23 | "Black" : QColor(0, 0, 0),
24 | "Red" : QColor(255, 0, 0),
25 | "Blue" : QColor(0, 0, 255),
26 | "Green" : QColor(0, 255, 0)
27 | }
28 | self.bg = "White"
29 | self.textColor = "Red"
30 | self.fontNum = 6
31 | self.rect = True
32 | self.scaledDict = {}
33 | self.erase = False
34 |
35 | @logger.catch
36 | def paintEvent(self, event):
37 | super().paintEvent(event)
38 | if self.flag and self.img != None:
39 | if self.erase:
40 | self.changeCursor()
41 | else:
42 | self.setCursor(QCursor(Qt.ArrowCursor))
43 | qp = QPainter(self)
44 | qp.setPen(QPen(self.color[self.textColor], 2, Qt.SolidLine))
45 | if self.rect:
46 | qp.drawRects(self.pages[self.img])
47 | if self.connectDict != {} and self.translated != {}:
48 | for index, words in enumerate(self.translated[self.connectDict[self.img]]):
49 | a, b, c, d, = self.pages[self.img][index].getRect()
50 | if self.bg != "None":
51 | qp.fillRect(self.pages[self.img][index], self.color[self.bg])
52 | qp.setFont(QFont("Comic Sans MS",self.fontNum));
53 | option = QTextOption()
54 | option.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
55 | qp.drawText(QRectF(a, b, c, d), words, option)
56 |
57 | if not self.begin.isNull() and not self.end.isNull():
58 | qp.drawRect(QRect(self.begin, self.end).normalized())
59 | self.setPixmap(self.image)
60 |
61 | def mousePressEvent(self, event):
62 | if self.flag and self.img != None:
63 | if self.erase:
64 | self.changeCursor()
65 | else:
66 | self.setCursor(QCursor(Qt.ArrowCursor))
67 | self.begin = self.end = event.pos()
68 | self.update()
69 | super().mousePressEvent(event)
70 |
71 | @logger.catch
72 | def mouseMoveEvent(self, event):
73 | if self.flag and self.img != None:
74 | if self.erase:
75 | self.changeCursor()
76 | self.end = event.pos()
77 | self.update()
78 | nL = []
79 | p1 = self.end.x()
80 | p2 = self.end.y()
81 | if self.pages[self.img] != []:
82 | for index, rect in enumerate(self.pages[self.img]):
83 | x, y, w, h = rect.getRect()
84 | if p1 >= x and p1 <= x+w and p2 >= y and p2 <= y+h:
85 | nL.append((self.img, index))
86 | for img, index in nL:
87 | del self.pages[img][index]
88 | else:
89 | self.setCursor(QCursor(Qt.ArrowCursor))
90 | self.end = event.pos()
91 | self.update()
92 | super().mouseMoveEvent(event)
93 |
94 | def mouseReleaseEvent(self, event):
95 | if self.flag and self.img != None:
96 | if self.erase:
97 | self.changeCursor()
98 | else:
99 | self.setCursor(QCursor(Qt.ArrowCursor))
100 | r = QRect(self.begin, self.end).normalized()
101 | self.pages[self.img].append(r)
102 | self.begin = self.end = QPoint()
103 | self.update()
104 | super().mouseReleaseEvent(event)
105 |
106 | def changeCursor(self):
107 | cursor = QPixmap(":/newPrefix/eraser.png")
108 | cursorScaled = cursor.scaled(QtCore.QSize(35, 35), Qt.KeepAspectRatio)
109 | currCursor = QCursor(cursorScaled, -1, -1)
110 | self.setCursor(currCursor)
--------------------------------------------------------------------------------
/Code/TranslateManga.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | from PyQt5.QtCore import QRunnable, pyqtSignal, QObject
3 | import qimage2ndarray
4 | import numpy as np
5 | from pprint import pprint
6 | from RectangleManipulation import *
7 | import langid
8 | from FileHandling import FileHandler
9 | from Configer import Settings
10 | from Translation import MangaBag
11 | from loguru import logger
12 |
13 |
14 | class Worker(QObject):
15 | result = pyqtSignal(object)
16 | stored = pyqtSignal(object)
17 | finished = pyqtSignal()
18 | progress = pyqtSignal(int)
19 | pageProgress = pyqtSignal(str)
20 | booleans = pyqtSignal(object)
21 | lang = pyqtSignal(str)
22 |
23 |
24 | class Translate(QRunnable):
25 |
26 | def __init__(self, img:list , mocr, translator,language, combN=False, combO=False, sliderNum=0):
27 | super(Translate, self).__init__()
28 | self.imag1 = img
29 | self.setting = Settings()
30 | self.manga = MangaBag()
31 | self.handling = FileHandler()
32 | self.name = translator
33 | self.shouldCombN = combN
34 | self.shouldCombO = combO
35 | self.range = sliderNum * self.manga.getRatio(self.imag1[0]) + 4
36 | self.signals = Worker()
37 | self.directory = self.setting.cropText
38 | self.portions = (100 / len(self.imag1))/3
39 | self.cnt = 0
40 | self.mocr = mocr
41 | self.source = None if language == "auto" else language
42 | self.ratio = 1
43 |
44 |
45 | def LocateText(self, image):
46 | myDict = self.manga.get_text(image)
47 | if self.shouldCombN and self.shouldCombO:
48 | bound1 = rectanglesCO(myDict, "c")
49 | bound2 = combine_rectangles(bound1, self.range)
50 | overlap1 = rectanglesCO(bound2, "o")
51 | overlap = combine_overlapping_rectangles(overlap1)
52 | return overlap
53 | elif self.shouldCombN and not(self.shouldCombO):
54 | bound3 = rectanglesCO(myDict, "c")
55 | bound4 = combine_rectangles(bound3, self.range)
56 | return bound4
57 | elif self.shouldCombO and not(self.shouldCombN):
58 | overlap3 = rectanglesCO(myDict, "o")
59 | overlap4 = combine_overlapping_rectangles(overlap3)
60 | return overlap4
61 | else:
62 | return myDict
63 |
64 |
65 | def run(self):
66 | finalImg = []
67 | backup = []
68 | counter = 1
69 | try:
70 | for x in self.imag1:
71 | self.signals.pageProgress.emit(f"Translating page {counter} of {len(self.imag1)}")
72 | fontSize, thickness = self.manga.getFontSizeThickness(x)
73 | self.img1 = cv2.imread(r"{}".format(x))
74 | self.image = cv2.cvtColor(self.img1, cv2.COLOR_BGR2RGB)
75 | gotten_text = self.LocateText(self.image)
76 | # pprint(gotten_text)
77 | self.cnt += self.portions
78 | self.signals.progress.emit(self.cnt)
79 |
80 | finalText = self.manga.get_japanese(self.image, self.mocr, gotten_text, self.directory)
81 | self.cnt += self.portions
82 | self.signals.progress.emit(self.cnt)
83 | finalTextcopy = finalText.copy()
84 | # pprint(finalText)
85 |
86 | if self.source == None and finalText != {}:
87 | for y in list(finalText.values()):
88 | if y != []:
89 | self.source = langid.classify(y[0])[0]
90 | break
91 |
92 | newList = self.manga.translate(finalText, self.name, self.source, gotten_text)
93 | self.cnt += self.portions
94 | self.signals.progress.emit(self.cnt)
95 | # pprint(newList)
96 | addNewLine1 = self.manga.addNewLine(x, newList, gotten_text, cv2.FONT_HERSHEY_DUPLEX, fontSize, thickness)
97 |
98 |
99 | final = self.manga.write(self.image, gotten_text, addNewLine1, fontSize, thickness)
100 | myarray = np.array(final)
101 | image = qimage2ndarray.array2qimage(myarray)
102 | finalImg.append(image)
103 | self.cnt += self.portions
104 | backup.append((x, gotten_text, finalTextcopy))
105 | self.signals.progress.emit(self.cnt)
106 | counter += 1
107 | except:
108 | logger.exception("ERROR")
109 | self.signals.finished.emit()
110 | else:
111 | self.signals.result.emit(finalImg)
112 | self.signals.stored.emit(backup)
113 | self.signals.booleans.emit([self.name, self.shouldCombN, self.shouldCombO, self.range])
114 | self.signals.lang.emit(self.source)
115 | self.signals.finished.emit()
116 | finally:
117 | self.handling.deleteFiles(self.directory)
118 |
--------------------------------------------------------------------------------
/Code/Translation.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import math
3 | from deep_translator import MyMemoryTranslator
4 | from loguru import logger
5 | import time
6 | import deepl
7 | import os
8 | import easyocr
9 | from PIL import Image
10 | import cohere
11 | from addText import add_text_to_image
12 | import ast
13 | try:
14 | import translators.server as ts
15 | except ModuleNotFoundError:
16 | import translators as ts
17 |
18 | class MangaBag:
19 |
20 | def chronos(func):
21 | def get_time(*args, **kawrgs):
22 | start = time.time()
23 | x = func(*args, **kawrgs)
24 | end = time.time()
25 | name = ""
26 | if "get_text" in str(func):
27 | name = "EasyOcr"
28 | elif "get_japanese" in str(func):
29 | name = "MangaOcr"
30 | else:
31 | name = "Translator"
32 | logger.info("{} took {} seconds".format(name, (end-start)))
33 | return x
34 | return get_time
35 |
36 | def getFontSizeThickness(self,img):
37 | FONT_SCALE = 6e-4 # Adjust for larger font size in all images
38 | THICKNESS_SCALE = 5e-4 # Adjust for larger thickness in all images
39 |
40 | img = cv2.imread(img)
41 | height, width, _ = img.shape
42 |
43 | font_scale = min(width, height) * FONT_SCALE
44 | thickness = math.ceil(min(width, height) * THICKNESS_SCALE)
45 | return (font_scale, thickness)
46 |
47 | def get_japanese(self, image, mocr, diction, direct):
48 | if diction == {}:
49 | return {}
50 | newList = {}
51 | et = {}
52 | ts = {}
53 | directory = direct
54 | tt = []
55 | for x in diction:
56 | cropped_image = image[abs(diction[x][0][1]):abs(diction[x][1][1]), abs(diction[x][0][0]):abs(diction[x][1][0])]
57 | try:
58 | cv2.imwrite(os.path.join(directory, str(x)+'.jpg'), cropped_image)
59 | except:
60 | logger.exception("Failed cropping!")
61 | et[str(x)] = os.path.join(directory, str(x)+'.jpg')
62 | for root, dirs, files in os.walk(directory):
63 | for x in files:
64 | try:
65 | img = Image.open((root+"\\"+ x).strip())
66 | text = mocr(img)
67 | # print(text)
68 | ts[(root+"\\"+ x).strip()] = text
69 | except:
70 | logger.exception("File Mystery")
71 | mg = et.items()
72 | tg = ts.items()
73 | for coor, direct in mg:
74 | for dir1, jap in tg:
75 | if direct == dir1:
76 | newList[coor] = jap
77 | return newList
78 |
79 | def get_text(self, image):
80 | reader = easyocr.Reader(['ja'], gpu=False)
81 | result = reader.readtext(image, paragraph=True, x_ths=.01, y_ths=.01)
82 | myDict = {}
83 | num = 0
84 | for (bbox, text) in result:
85 | (tl, tr, br, bl) = bbox
86 | tl = (int(tl[0]), int(tl[1]))
87 | tr = (int(tr[0]), int(tr[1]))
88 | br = (int(br[0]), int(br[1]))
89 | bl = (int(bl[0]), int(bl[1]))
90 | if tl[0] < 0 or tl[1] < 0:
91 | tl = (abs(tl[0]), abs(tl[1]))
92 | if br[0] < 0 or br[1] <0:
93 | br = (abs(br[0]), abs(br[1]))
94 | myDict[f"image{num}"] = ([tl , br ])
95 | num += 1
96 | secDic = myDict.copy()
97 | dupKey = []
98 | for rect in myDict:
99 | for key in secDic:
100 | b = secDic[key]
101 | if myDict[rect] == b:
102 | continue
103 | else:
104 | if myDict[rect][0][0] >= b[0][0] and myDict[rect][0][1] >= b[0][1] and myDict[rect][1][0]<= b[1][0] and myDict[rect][1][1] <= b[1][1]:
105 | dupKey.append(rect)
106 | for x in dupKey:
107 | try:
108 | del myDict[x]
109 | except:
110 | continue
111 | return myDict
112 |
113 | def cohere(self, japanese_text, text_location):
114 | translation_request = f"""
115 | translate the following text, extracted from a manga, with as much context as you can gather from the other japanese text
116 | and from any other context you can gather.
117 | Return in the format you received with the english translation:
118 | {japanese_text}
119 | Use the following below to know where the text bubble are to help you translate:
120 | {text_location}
121 | DO NOT ADD ANY ELSE. ONLY RETURN THE FORMAT I ASKED YOU TO.
122 | MAKE SURE THE NUMBER OF LINES OF YOUR OUTPUT IS EQUAL TO THE INPUT I GIVE YOU.
123 | Make sure the output is in the correct syntax so it can be converted to a dictionary using ast.literal_eval().
124 | Make sure it won't cause a keyError. I want the key of the return dictionalry to have double quotes in stead of single quotes.
125 | """
126 | result = self.call_cohere(translation_request)
127 | try:
128 | data_dict = ast.literal_eval(result)
129 | except SyntaxError:
130 | logger.error("SYNTAX ERROR!!!")
131 | data_dict = {}
132 | for key in japanese_text:
133 | context = f"""
134 | Use the following extracted from a manga as context to translate a sentence.
135 | context:
136 | text :{japanese_text}\n
137 | location of that text: {text_location}\n
138 | Sentence to translate: {japanese_text[key]}
139 | RETURN only the translated sentence nothing else.
140 | """
141 | data_dict[key] = self.call_cohere(context)
142 |
143 |
144 | if len(data_dict) < len(japanese_text):
145 | logger.error("KEY ERROR!!!")
146 | for jt in japanese_text:
147 | if jt not in data_dict:
148 | fix_key = f"""
149 | Translate the following line to english.
150 | sentence to translate: {japanese_text[jt]}
151 | use the text below as context to help you translate:
152 | {data_dict}
153 | Return only the translated sentence. nothing else
154 | """
155 | data_dict[jt] = self.call_cohere(fix_key)
156 |
157 |
158 | return data_dict
159 |
160 | def call_cohere(self, request):
161 | co = cohere.ClientV2("api_key")
162 | response = co.chat(
163 | model="command-r-plus",
164 | messages=[
165 | {
166 | "role": "user",
167 | "content": f"""
168 | {request}
169 | """
170 | }
171 | ]
172 | )
173 | return response.message.content[0].text
174 |
175 |
176 | def translate(self, original, name, langauge, location=None):
177 | if original == {}:
178 | return {}
179 | source = langauge
180 | if name == "DeepL":
181 | for key in original:
182 | original[key] = deepl.translate(source_language="JA", target_language="EN", text=original[key])
183 | return original
184 | elif name == "MyMemory":
185 | for key in original:
186 | original[key] = MyMemoryTranslator(source="ja", target='en').translate(original[key])
187 | return original
188 | elif name == "Google":
189 | for jap in original:
190 | original[jap] = str(ts.google(original[jap]))
191 | return original
192 | elif name == "Bing":
193 | for jap in original:
194 | original[jap] = str(ts.bing(original[jap]))
195 | return original
196 | elif name == "Youdao":
197 | for jap in original:
198 | original[jap] = str(ts.youdao(original[jap]))
199 | time.sleep(5)
200 | return original
201 | elif name == "Cohere":
202 | return self.cohere(original, location)
203 |
204 | def addNewLine(self, img, engDict, rectDict, font, scale, thickness):
205 | newDict = {}
206 | for key in rectDict:
207 | coordinate, coordinate1 = tuple(rectDict[key])
208 | x, y = coordinate
209 | x1, y1 = coordinate1
210 | newDict[key] = self.wrap_text_in_rectangle(img, engDict[key], x, y, (x1-x), (y1-y), font, scale, thickness)
211 | return newDict
212 |
213 | def wrap_text_in_rectangle(self, image, text, x, y, width, height, font_face, font_scale, thickness):
214 | # Get the text size
215 | (text_width, text_height), _ = cv2.getTextSize(text, font_face, font_scale, thickness)
216 |
217 | # Calculate the number of lines needed to fit the text within the rectangle
218 | lines = []
219 | line = ""
220 | for word in text.split(" "):
221 | if cv2.getTextSize(line + word, font_face, font_scale, thickness)[0][0] <= width:
222 | line += word + " "
223 | else:
224 | lines.append(line)
225 | line = word + " "
226 | lines.append(line)
227 |
228 | return "\n".join(lines)
229 |
230 |
231 | def getRatio(self, img):
232 | img = cv2.imread(img)
233 | aspect_ratio = 1
234 | height, width, _ = img.shape
235 | if width > height:
236 | aspect_ratio = width / height
237 | else:
238 | aspect_ratio = height/ width
239 | return aspect_ratio
240 |
241 |
242 |
243 | def write(self, img, dict1, list1, font, thick):
244 | if dict1 == {}:
245 | return img
246 | for value in dict1:
247 | try:
248 | cv2.rectangle(img, dict1[value][0], dict1[value][1], (0, 255, 255), 2)
249 | image = add_text_to_image(
250 | img,
251 | list1[value],
252 | font_color_rgb=(255, 0, 0),
253 | top_left_xy=(dict1[value][0][0], dict1[value][0][1]),
254 | font_scale= font,
255 | font_face=cv2.FONT_HERSHEY_DUPLEX,
256 | bg_color_rgb=(255, 255, 255),
257 | font_thickness=thick
258 | )
259 | except:
260 | logger.exception("Mystery")
261 | continue
262 | return image
--------------------------------------------------------------------------------
/Code/ManualTranslation.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtGui import QPixmap
2 | from PyQt5.QtCore import QRunnable, pyqtSignal, QObject, QRectF, QPointF
3 | import numpy as np
4 | from TranslateManga import Translate
5 | import cv2
6 | from pprint import pprint
7 | from deep_translator import MyMemoryTranslator
8 | import deepl
9 | import langid
10 | from FileHandling import FileHandler
11 | from Configer import Settings
12 | from loguru import logger
13 | from PIL import Image
14 | import ast
15 | from Translation import MangaBag
16 | try:
17 | import translators.server as ts
18 | except ModuleNotFoundError:
19 | import translators as ts
20 |
21 | class Worker(QObject):
22 | result = pyqtSignal(object)
23 | finished = pyqtSignal()
24 | progress = pyqtSignal(int)
25 |
26 | class ManualTranslation(QRunnable):
27 | def __init__(self, dictionary, mocr, translator, language, width, height, retranslate=False):
28 | super(ManualTranslation, self).__init__()
29 | self.manualRect = dictionary
30 | self.mocr = mocr
31 | self.translator = translator
32 | self.width = width
33 | self.height = height
34 | self.source = None if language == "auto" else language
35 | self.dictionary = {}
36 | self.signals = Worker()
37 | self.portions = (100)/3
38 | self.cnt = 0
39 | self.handling = FileHandler()
40 | self.setting = Settings()
41 | self.retrans = retranslate
42 | self.scaleDict = {}
43 | self.cohere = MangaBag()
44 |
45 | def scaleRect(self, img1, width, height, scalelist):
46 | scaleDict = scalelist[:]
47 | imageToPredict = cv2.imread(img1, 3)
48 | targetSizeX = width
49 | targetSizeY = height
50 | y_ = imageToPredict.shape[0]
51 | x_ = imageToPredict.shape[1]
52 |
53 | x_scale = targetSizeX / x_
54 | y_scale = targetSizeY / y_
55 | img = cv2.resize(imageToPredict, (targetSizeX, targetSizeY))
56 | img = np.array(img)
57 |
58 | for index, value in enumerate(scaleDict):
59 | x, y, w, h = value.getRect()
60 | (origLeft, origTop, origRight, origBottom) = (x, y, x+w, y+h)
61 |
62 | x = int(np.round(origLeft * x_scale))
63 | y = int(np.round(origTop * y_scale))
64 | xmax = int(np.round(origRight * x_scale))
65 | ymax = int(np.round(origBottom * y_scale))
66 | scaleDict[index] = (x, y, xmax, ymax)
67 | return scaleDict
68 |
69 | def crop(self, formatted):
70 | formattedDict = formatted.copy()
71 | newDict = {}
72 | num = 0
73 | page = 0
74 | for img in formattedDict:
75 | newList = []
76 | pix = QPixmap(img)
77 | canvas = pix.scaled(self.width, self.height)
78 | name1 = f"Translated\\manaul{page}.jpg"
79 | canvas.save(name1)
80 | formattedDict[img] = self.scaleRect(name1, pix.width(), pix.height(), formattedDict[img])
81 | self.dictionary[img] = name1
82 | newDict[name1] = newList
83 | page += 1
84 |
85 | self.scaleDict = formattedDict.copy()
86 | for key in self.scaleDict:
87 | newList = self.scaleDict[key][:]
88 | for index, value in enumerate(newList):
89 | x1, y1, x2, y2 = value
90 | newList[index] = QRectF(QPointF(x1, y1), QPointF(x2, y2))
91 | self.scaleDict[key] = newList
92 |
93 | for imx in formattedDict:
94 | for x in formattedDict[imx]:
95 | try:
96 | name = f"cropText\\manualRect{num}.jpg"
97 | image = cv2.imread(imx)
98 | x1, y1, x2, y2 = x
99 | crop = image[y1:y2, x1:x2]
100 | cv2.imwrite(name, crop)
101 | except:
102 | continue
103 | newDict[self.dictionary[imx]].append(name)
104 | num += 1
105 |
106 | return newDict
107 |
108 | def get_text(self, mocr, diction):
109 | dict1 = {}
110 | for x in diction:
111 | list1 = []
112 | for y in diction[x]:
113 | try:
114 | img = Image.open(y)
115 | text = mocr(img)
116 | list1.append(text)
117 | except:
118 | text = " "
119 | list1.append(text)
120 | # logger.exception("Failed OCR!")
121 | logger.info(f"{x} -> {y}")
122 | dict1[x] = list1
123 | return dict1
124 |
125 |
126 | def translate(self, original, name, langauge):
127 | newDict = {}
128 | if original == {}:
129 | return {}
130 | source = langauge
131 | # print(source)
132 | if name == "DeepL":
133 | for key in original:
134 | h = []
135 | for jap in original[key]:
136 | t = deepl.translate(source_language="JA", target_language="EN", text=jap)
137 | h.append(t)
138 | newDict[key] = h
139 | if self.retrans:
140 | self.cnt += self.portions
141 | self.signals.progress.emit(self.cnt)
142 | elif name == "MyMemory":
143 | for key in original:
144 | h = []
145 | for jap in original[key]:
146 | t = MyMemoryTranslator(source="ja", target='en').translate(jap)
147 | h.append(t)
148 | newDict[key] = h
149 | if self.retrans:
150 | self.cnt += self.portions
151 | self.signals.progress.emit(self.cnt)
152 | elif name == "Google":
153 | for key in original:
154 | h = []
155 | for jap in original[key]:
156 | t = str(ts.google(jap))
157 | h.append(t)
158 | newDict[key] = h
159 | if self.retrans:
160 | self.cnt += self.portions
161 | self.signals.progress.emit(self.cnt)
162 | elif name == "Bing":
163 | for key in original:
164 | h = []
165 | for jap in original[key]:
166 | t = str(ts.bing(jap))
167 | h.append(t)
168 | newDict[key] = h
169 | if self.retrans:
170 | self.cnt += self.portions
171 | self.signals.progress.emit(self.cnt)
172 | elif name == "Youdao":
173 | for key in original:
174 | h = []
175 | for jap in original[key]:
176 | t = str(ts.youdao(jap))
177 | h.append(t)
178 | newDict[key] = h
179 | if self.retrans:
180 | self.cnt += self.portions
181 | self.signals.progress.emit(self.cnt)
182 | elif name == "Cohere":
183 | for key in original:
184 | newDict[key] = self.manaul_cohere(original[key])
185 | if self.retrans:
186 | self.cnt += self.portions
187 | self.signals.progress.emit(self.cnt)
188 | return newDict
189 |
190 | def manaul_cohere(self, need_translate):
191 |
192 | counter = 1
193 | japanese_text = {}
194 | for jap in need_translate:
195 | japanese_text[f'image{counter}'] = jap
196 | counter += 1
197 |
198 | translation_request = f"""
199 | translate the following japanese text, extracted from a manga, with as much context as you can gather from the other japanese text
200 | and from any other context you can gather.
201 | Return in the format you received with the english translation:
202 | {japanese_text}
203 | DO NOT ADD ANY ELSE. ONLY RETURN THE FORMAT I ASKED YOU TO.
204 | MAKE SURE THE NUMBER OF LINES OF YOUR OUTPUT IS EQUAL TO THE INPUT I GIVE YOU.
205 | Make sure the output is in the correct syntax so it can be converted to a dictionary using ast.literal_eval().
206 | Make sure it won't cause a keyError. I want the key of the return dictionalry to have double quotes in stead of single quotes.
207 | """
208 |
209 | result = self.cohere.call_cohere(translation_request)
210 | try:
211 | final = ast.literal_eval(result)
212 | # print(final)
213 | except SyntaxError:
214 | logger.error("SYNTAX ERROR!!!")
215 | final = {}
216 | for key in japanese_text:
217 | context = f"""
218 | Use the following extracted from a manga as context to translate a sentence.
219 | context:
220 | japanese text :{japanese_text}\n
221 | Sentence to translate: {japanese_text[key]}
222 | RETURN only the translated sentence nothing else.
223 | """
224 | final[key] = self.call_cohere(context)
225 |
226 |
227 | if len(final) < len(japanese_text):
228 | logger.error("KEY ERROR!!!")
229 | for jt in japanese_text:
230 | if jt not in final:
231 | fix_key = f"""
232 | Translate the following line to english.
233 | sentence to translate: {japanese_text[jt]}
234 | use the text below as context to help you translate:
235 | {final}
236 | Return only the translated sentence. nothing else
237 | """
238 | final[jt] = self.call_cohere(fix_key)
239 |
240 |
241 | array = []
242 | for key, value in final.items():
243 | array.append(value)
244 | return array
245 |
246 |
247 |
248 |
249 | def formatDict(self):
250 | num = 0
251 | listDict = {}
252 | for x in self.manualRect:
253 | newDict = {}
254 | for value in self.manualRect[x]:
255 | a, b, c, d = value.getRect()
256 | newDict[f"image{num}"] = [(a, b), (c, d)]
257 | num += 1
258 | listDict[x] = newDict
259 | return listDict
260 |
261 | @logger.catch
262 | def run(self):
263 | if self.retrans:
264 | # pprint(self.manualRect)
265 | if self.source == None and self.manualRect != {}:
266 | for x in list(self.manualRect.values()):
267 | if x != []:
268 | self.source = langid.classify(x[0])[0]
269 | break
270 | translated = self.translate(self.manualRect, self.translator, self.source)
271 | # pprint(translated)
272 | self.signals.result.emit(translated)
273 | self.signals.finished.emit()
274 | else:
275 | try:
276 | cropText = self.crop(self.manualRect)
277 | self.cnt += self.portions
278 | self.signals.progress.emit(self.cnt)
279 |
280 | # pprint(self.dictionary)
281 | pprint(cropText)
282 | japanese = self.get_text(self.mocr, cropText)
283 | self.cnt += self.portions
284 | self.signals.progress.emit(self.cnt)
285 |
286 | pprint(japanese)
287 | if self.source == None and japanese != {}:
288 | for x in list(japanese.values()):
289 | if x != []:
290 | self.source = langid.classify(x[0])[0]
291 | break
292 | translated = self.translate(japanese, self.translator, self.source)
293 | pprint(translated)
294 | except:
295 | self.signals.result.emit("ERROR")
296 | self.signals.finished.emit()
297 | else:
298 | self.cnt += self.portions
299 | self.signals.progress.emit(self.cnt)
300 | self.handling.deleteFiles(self.setting.cropText)
301 | self.signals.result.emit((self.dictionary, translated, japanese, self.scaleDict))
302 | self.signals.finished.emit()
--------------------------------------------------------------------------------
/Code/settingsGUI.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'C:/Users/andre/Desktop/QTdesigner/SettingsGUI.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.15.7
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt5 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_Form(object):
15 | def setupUi(self, Form):
16 | Form.setObjectName("Form")
17 | Form.resize(500, 271)
18 | Form.setMinimumSize(QtCore.QSize(500, 271))
19 | Form.setMaximumSize(QtCore.QSize(500, 271))
20 | Form.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
21 | " x2: 1, y2: 0, \n"
22 | " stop: 0 #0f121c, \n"
23 | " stop: 1 #0b0d14);")
24 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form)
25 | self.verticalLayout_2.setObjectName("verticalLayout_2")
26 | self.label_10 = QtWidgets.QLabel(Form)
27 | font = QtGui.QFont()
28 | font.setFamily("Comic Sans MS")
29 | font.setPointSize(10)
30 | self.label_10.setFont(font)
31 | self.label_10.setStyleSheet("color: rgb(255, 255, 255);")
32 | self.label_10.setObjectName("label_10")
33 | self.verticalLayout_2.addWidget(self.label_10, 0, QtCore.Qt.AlignHCenter)
34 | self.formLayout = QtWidgets.QFormLayout()
35 | self.formLayout.setObjectName("formLayout")
36 | self.label = QtWidgets.QLabel(Form)
37 | font = QtGui.QFont()
38 | font.setFamily("Comic Sans MS")
39 | self.label.setFont(font)
40 | self.label.setStyleSheet("color: rgb(255, 255, 255);")
41 | self.label.setObjectName("label")
42 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
43 | self.translatePath = QtWidgets.QLineEdit(Form)
44 | font = QtGui.QFont()
45 | font.setFamily("Comic Sans MS")
46 | self.translatePath.setFont(font)
47 | self.translatePath.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
48 | " x2: 1, y2: 0, \n"
49 | " stop: 0 #0f121c, \n"
50 | " stop: 1 #0b0d14);\n"
51 | "border-radius: 10px;\n"
52 | "border: 2px solid rgb(170, 85, 255);\n"
53 | "color: rgb(255, 255, 255);\n"
54 | "padding-left: 10px;\n"
55 | "padding-right:10px;")
56 | self.translatePath.setObjectName("translatePath")
57 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.translatePath)
58 | self.label_2 = QtWidgets.QLabel(Form)
59 | font = QtGui.QFont()
60 | font.setFamily("Comic Sans MS")
61 | self.label_2.setFont(font)
62 | self.label_2.setStyleSheet("color: rgb(255, 255, 255);")
63 | self.label_2.setObjectName("label_2")
64 | self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2)
65 | self.cropPath = QtWidgets.QLineEdit(Form)
66 | font = QtGui.QFont()
67 | font.setFamily("Comic Sans MS")
68 | self.cropPath.setFont(font)
69 | self.cropPath.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
70 | " x2: 1, y2: 0, \n"
71 | " stop: 0 #0f121c, \n"
72 | " stop: 1 #0b0d14);\n"
73 | "border-radius: 10px;\n"
74 | "border: 2px solid rgb(170, 85, 255);\n"
75 | "color: rgb(255, 255, 255);\n"
76 | "padding-left: 10px;\n"
77 | "padding-right:10px;")
78 | self.cropPath.setObjectName("cropPath")
79 | self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.cropPath)
80 | self.label_3 = QtWidgets.QLabel(Form)
81 | font = QtGui.QFont()
82 | font.setFamily("Comic Sans MS")
83 | self.label_3.setFont(font)
84 | self.label_3.setStyleSheet("color: rgb(255, 255, 255);")
85 | self.label_3.setObjectName("label_3")
86 | self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_3)
87 | self.deeplKey = QtWidgets.QLineEdit(Form)
88 | font = QtGui.QFont()
89 | font.setFamily("Comic Sans MS")
90 | self.deeplKey.setFont(font)
91 | self.deeplKey.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
92 | " x2: 1, y2: 0, \n"
93 | " stop: 0 #0f121c, \n"
94 | " stop: 1 #0b0d14);\n"
95 | "border-radius: 10px;\n"
96 | "border: 2px solid rgb(170, 85, 255);\n"
97 | "color: rgb(255, 255, 255);\n"
98 | "padding-left: 10px;\n"
99 | "padding-right:10px;")
100 | self.deeplKey.setObjectName("deeplKey")
101 | self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.deeplKey)
102 | self.verticalLayout_2.addLayout(self.formLayout)
103 | self.label_4 = QtWidgets.QLabel(Form)
104 | font = QtGui.QFont()
105 | font.setFamily("Comic Sans MS")
106 | font.setPointSize(12)
107 | font.setBold(False)
108 | font.setItalic(False)
109 | font.setWeight(50)
110 | self.label_4.setFont(font)
111 | self.label_4.setStyleSheet("color: rgb(255, 255, 255);\n"
112 | "font: 12pt \"Comic Sans MS\";")
113 | self.label_4.setObjectName("label_4")
114 | self.verticalLayout_2.addWidget(self.label_4, 0, QtCore.Qt.AlignHCenter)
115 | self.formLayout_2 = QtWidgets.QFormLayout()
116 | self.formLayout_2.setObjectName("formLayout_2")
117 | self.label_5 = QtWidgets.QLabel(Form)
118 | font = QtGui.QFont()
119 | font.setFamily("Comic Sans MS")
120 | self.label_5.setFont(font)
121 | self.label_5.setStyleSheet("color: rgb(255, 255, 255);")
122 | self.label_5.setObjectName("label_5")
123 | self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_5)
124 | self.consumerKey = QtWidgets.QLineEdit(Form)
125 | font = QtGui.QFont()
126 | font.setFamily("Comic Sans MS")
127 | self.consumerKey.setFont(font)
128 | self.consumerKey.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
129 | " x2: 1, y2: 0, \n"
130 | " stop: 0 #0f121c, \n"
131 | " stop: 1 #0b0d14);\n"
132 | "border-radius: 10px;\n"
133 | "border: 2px solid rgb(170, 85, 255);\n"
134 | "color: rgb(255, 255, 255);\n"
135 | "padding-left: 10px;\n"
136 | "padding-right:10px;")
137 | self.consumerKey.setObjectName("consumerKey")
138 | self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.consumerKey)
139 | self.label_6 = QtWidgets.QLabel(Form)
140 | font = QtGui.QFont()
141 | font.setFamily("Comic Sans MS")
142 | self.label_6.setFont(font)
143 | self.label_6.setStyleSheet("color: rgb(255, 255, 255);")
144 | self.label_6.setObjectName("label_6")
145 | self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_6)
146 | self.consumerSecret = QtWidgets.QLineEdit(Form)
147 | font = QtGui.QFont()
148 | font.setFamily("Comic Sans MS")
149 | self.consumerSecret.setFont(font)
150 | self.consumerSecret.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
151 | " x2: 1, y2: 0, \n"
152 | " stop: 0 #0f121c, \n"
153 | " stop: 1 #0b0d14);\n"
154 | "border-radius: 10px;\n"
155 | "border: 2px solid rgb(170, 85, 255);\n"
156 | "color: rgb(255, 255, 255);\n"
157 | "padding-left: 10px;\n"
158 | "padding-right:10px;")
159 | self.consumerSecret.setObjectName("consumerSecret")
160 | self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.consumerSecret)
161 | self.label_7 = QtWidgets.QLabel(Form)
162 | font = QtGui.QFont()
163 | font.setFamily("Comic Sans MS")
164 | self.label_7.setFont(font)
165 | self.label_7.setStyleSheet("color: rgb(255, 255, 255);")
166 | self.label_7.setObjectName("label_7")
167 | self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_7)
168 | self.accessToken = QtWidgets.QLineEdit(Form)
169 | font = QtGui.QFont()
170 | font.setFamily("Comic Sans MS")
171 | self.accessToken.setFont(font)
172 | self.accessToken.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
173 | " x2: 1, y2: 0, \n"
174 | " stop: 0 #0f121c, \n"
175 | " stop: 1 #0b0d14);\n"
176 | "border-radius: 10px;\n"
177 | "border: 2px solid rgb(170, 85, 255);\n"
178 | "color: rgb(255, 255, 255);\n"
179 | "padding-left: 10px;\n"
180 | "padding-right:10px;")
181 | self.accessToken.setObjectName("accessToken")
182 | self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.accessToken)
183 | self.label_9 = QtWidgets.QLabel(Form)
184 | font = QtGui.QFont()
185 | font.setFamily("Comic Sans MS")
186 | self.label_9.setFont(font)
187 | self.label_9.setStyleSheet("color: rgb(255, 255, 255);")
188 | self.label_9.setObjectName("label_9")
189 | self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_9)
190 | self.accessTokenSecret = QtWidgets.QLineEdit(Form)
191 | font = QtGui.QFont()
192 | font.setFamily("Comic Sans MS")
193 | self.accessTokenSecret.setFont(font)
194 | self.accessTokenSecret.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
195 | " x2: 1, y2: 0, \n"
196 | " stop: 0 #0f121c, \n"
197 | " stop: 1 #0b0d14);\n"
198 | "border-radius: 10px;\n"
199 | "border: 2px solid rgb(170, 85, 255);\n"
200 | "color: rgb(255, 255, 255);\n"
201 | "padding-left: 10px;\n"
202 | "padding-right:10px;")
203 | self.accessTokenSecret.setObjectName("accessTokenSecret")
204 | self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.accessTokenSecret)
205 | self.label_8 = QtWidgets.QLabel(Form)
206 | font = QtGui.QFont()
207 | font.setFamily("Comic Sans MS")
208 | self.label_8.setFont(font)
209 | self.label_8.setStyleSheet("color: rgb(255, 255, 255);")
210 | self.label_8.setObjectName("label_8")
211 | self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_8)
212 | self.bearerToken = QtWidgets.QLineEdit(Form)
213 | font = QtGui.QFont()
214 | font.setFamily("Comic Sans MS")
215 | self.bearerToken.setFont(font)
216 | self.bearerToken.setStyleSheet("background-color: QLinearGradient( x1: 0, y1: 0,\n"
217 | " x2: 1, y2: 0, \n"
218 | " stop: 0 #0f121c, \n"
219 | " stop: 1 #0b0d14);\n"
220 | "border-radius: 10px;\n"
221 | "border: 2px solid rgb(170, 85, 255);\n"
222 | "color: rgb(255, 255, 255);\n"
223 | "padding-left: 10px;\n"
224 | "padding-right:10px;")
225 | self.bearerToken.setObjectName("bearerToken")
226 | self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.bearerToken)
227 | self.verticalLayout_2.addLayout(self.formLayout_2)
228 | self.saveSet = QtWidgets.QPushButton(Form)
229 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
230 | sizePolicy.setHorizontalStretch(0)
231 | sizePolicy.setVerticalStretch(0)
232 | sizePolicy.setHeightForWidth(self.saveSet.sizePolicy().hasHeightForWidth())
233 | self.saveSet.setSizePolicy(sizePolicy)
234 | self.saveSet.setMaximumSize(QtCore.QSize(50, 20))
235 | font = QtGui.QFont()
236 | font.setFamily("Comic Sans MS")
237 | self.saveSet.setFont(font)
238 | self.saveSet.setStyleSheet("background-color: rgb(170, 0, 255);\n"
239 | "border-radius: 10px;\n"
240 | "width:60px;\n"
241 | "height:30px;")
242 | self.saveSet.setObjectName("saveSet")
243 | self.verticalLayout_2.addWidget(self.saveSet, 0, QtCore.Qt.AlignHCenter)
244 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
245 | self.verticalLayout_2.addItem(spacerItem)
246 |
247 | self.retranslateUi(Form)
248 | QtCore.QMetaObject.connectSlotsByName(Form)
249 |
250 | def retranslateUi(self, Form):
251 | _translate = QtCore.QCoreApplication.translate
252 | Form.setWindowTitle(_translate("Form", "Form"))
253 | self.label_10.setText(_translate("Form", "Folder Paths"))
254 | self.label.setText(_translate("Form", "Translated Folder:"))
255 | self.label_2.setText(_translate("Form", "CropText Folder:"))
256 | self.label_3.setText(_translate("Form", "Download Path:"))
257 | self.label_4.setText(_translate("Form", "Twitter"))
258 | self.label_5.setText(_translate("Form", "Consumer key:"))
259 | self.label_6.setText(_translate("Form", "Consumer secret:"))
260 | self.label_7.setText(_translate("Form", "Access token:"))
261 | self.label_9.setText(_translate("Form", "Access token secret:"))
262 | self.label_8.setText(_translate("Form", "Bearer token:"))
263 | self.saveSet.setText(_translate("Form", "Save"))
264 |
265 |
266 | if __name__ == "__main__":
267 | import sys
268 | app = QtWidgets.QApplication(sys.argv)
269 | Form = QtWidgets.QWidget()
270 | ui = Ui_Form()
271 | ui.setupUi(Form)
272 | Form.show()
273 | sys.exit(app.exec_())
274 |
--------------------------------------------------------------------------------
/Code/Main.py:
--------------------------------------------------------------------------------
1 | from PyQt5 import QtCore, QtGui
2 | from PyQt5.QtWidgets import QFileDialog, QShortcut
3 | from PyQt5.QtGui import QPixmap
4 | import sys
5 | from PyQt5 import QtWidgets
6 | from darkmode import Ui_MainWindow
7 | from Canvas import Image
8 | from PyQt5.QtCore import QThreadPool, pyqtSignal, Qt, QPoint, QPropertyAnimation, QEventLoop
9 | from TranslateManga import Translate
10 | from DownloadTweet import Twitter
11 | from Retranslate import Retranslate
12 | from PIL import ImageQt
13 | import img2pdf
14 | from FileHandling import FileHandler
15 | from Configer import Settings
16 | from settingsGUI import Ui_Form
17 | from manga_ocr import MangaOcr
18 | from IndividualPage import SingleTranslate
19 | from PyQt5.QtGui import QPixmap, QColor, QTextOption, QFont, QPen
20 | from loguru import logger
21 | from ManualTranslation import ManualTranslation
22 | from loguru import logger
23 | from pprint import pprint
24 |
25 | class interact(QtWidgets.QMainWindow, Ui_MainWindow):
26 | active = pyqtSignal()
27 |
28 | def __init__(self):
29 | super(interact, self).__init__()
30 | self.setupUi(self)
31 | self.resize(970, 940)
32 | self.appMod()
33 | self.stylesheet1()
34 | self.buttonConnections()
35 | self.widgetSizes()
36 | self.setting = Settings()
37 | self.handling = FileHandler()
38 | self.thread = QThreadPool()
39 | self.index = 0
40 | self.newIndex = 0
41 | self.translatedFiles = []
42 | self.files = []
43 | self.isClicked = False
44 | self.shownSetting = False
45 | self.bar.setValue(0)
46 | # self.bar.setFormat("Translating....")
47 | self.bar.setGeometry(self.width()//2-65, self.height()//2, 200, 30)
48 | self.bar.setVisible(False)
49 | self.bar.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
50 | self.fontsize.setMaximum(15)
51 | # self.translator = "Cohere"
52 | self.translator = "DeepL"
53 | # self.translateOptions.setCurrentIndex(5)
54 | self.translateOptions.setCurrentIndex(2)
55 | self.range = 0
56 | self.combineN = False
57 | self.rangeSlider.setEnabled(False)
58 | self.combineO = True
59 | self.changeTranslation = []
60 | self.checkthing = []
61 | self.single = False
62 | self.ocr = MangaOcr()
63 | self.orgLanguage = None
64 | self.clearButton.hide()
65 | self.saveButton.hide()
66 | self.editRect.hide()
67 | self.clearButton.clicked.connect(self.clear)
68 | self.im.adjustSize()
69 | self.shownWidget = False
70 | self.searchwidget.hide()
71 | self.recycle = {}
72 | self.num = -1
73 | self.isSort = False
74 | self.widget_2.hide()
75 | self.AutoWidget.hide()
76 | self.ManualWidget.hide()
77 | self.advanceSettings1()
78 | self.side_menu.hide()
79 | self.ISPCode = {
80 | "Japanese": "ja",
81 | "Korean": "ko",
82 | "Chinese": "zh",
83 | "Auto detect": "auto"
84 | }
85 | self.originalLang = "ja"
86 |
87 |
88 | def appMod(self):
89 | self.setWindowTitle("MangaTranslator")
90 | self.setWindowIcon(QtGui.QIcon(":/newPrefix/translation.png"))
91 | self.translateOptions.addItem('Youdao')
92 | self.translateOptions.addItem('MyMemory')
93 | self.translateOptions.addItem("Cohere")
94 | self.bGcolor.addItem("None")
95 | self.Form = QtWidgets.QWidget()
96 | self.ui = Ui_Form()
97 | self.ui.setupUi(self.Form)
98 | self.Form.setAttribute(Qt.WA_DeleteOnClose)
99 | self.Form.setMinimumSize(QtCore.QSize(720, 415))
100 | self.im = Image(self.imageWidget)
101 | self.im.setScaledContents(True)
102 | self.on1 = False
103 | self.on2 = False
104 | self.on3 = False
105 | QShortcut(QtCore.Qt.Key_Right, self, self.moveRight)
106 | QShortcut(QtCore.Qt.Key_Left, self, self.moveLeft)
107 |
108 | def widgetSizes(self):
109 | self.imageWidget.setMaximumSize(QtCore.QSize(900,800))
110 | self.translate.setMinimumSize(QtCore.QSize(130, 40))
111 | self.upload.setMinimumSize(QtCore.QSize(130, 40))
112 | self.saveButton.setMinimumSize(QtCore.QSize(130, 40))
113 | self.editRect.setMinimumSize(QtCore.QSize(250, 45))
114 | self.ui.saveSet.setMinimumSize(QtCore.QSize(100, 30))
115 | self.ui.label_4.setText("Twitter")
116 | self.header.setMinimumSize(QtCore.QSize(0, 100))
117 | self.header.setMaximumSize(QtCore.QSize(16777215, 100))
118 | self.pushButton_5.setIconSize(QtCore.QSize(60, 60))
119 | self.pushButton_2.setIconSize(QtCore.QSize(60, 60))
120 | self.menu.setIconSize(QtCore.QSize(30, 30))
121 | self.side_menu.setMinimumWidth(255)
122 |
123 |
124 | def buttonConnections(self):
125 | self.upload.clicked.connect(self.upload1)
126 | self.rightArrow.clicked.connect(self.moveRight)
127 | self.leftArrow.clicked.connect(self.moveLeft)
128 | self.translate.clicked.connect(self.translate1)
129 | self.translate.clicked.connect(self.showProgress)
130 | self.pushButton_5.clicked.connect(self.showSet)
131 | self.pushButton_6.clicked.connect(self.linkUpload)
132 | self.advanced.clicked.connect(self.advanceSettings)
133 | self.ui.saveSet.clicked.connect(self.getInfo)
134 | self.translateOptions.currentTextChanged.connect(self.choosenTranslator)
135 | self.Textcolor.currentTextChanged.connect(self.textColors)
136 | self.bGcolor.currentTextChanged.connect(self.backgroundColor)
137 | self.rangeSlider.valueChanged.connect(self.chooseRange)
138 | self.fontsize.valueChanged.connect(self.chooseFontNumber)
139 | self.combineNeighbors.stateChanged.connect(self.showCombN)
140 | self.combineOverLap.stateChanged.connect(self.showCombO)
141 | self.singlePtranslate.stateChanged.connect(self.getCurr)
142 | self.saveButton.clicked.connect(self.saveImages)
143 | self.horizontalLayout_5.addWidget(self.im)
144 | self.manualButton.clicked.connect(self.changeToManual)
145 | self.automaticButton.clicked.connect(self.changeToAutomatic)
146 | self.sortButton.stateChanged.connect(self.sortFile)
147 | self.removeRect.stateChanged.connect(self.removeRectangle)
148 | self.pushButton_2.clicked.connect(self.showSearch)
149 | self.undoButton.clicked.connect(self.undo)
150 | self.redoButton.clicked.connect(self.redo)
151 | self.eraseButton.clicked.connect(self.startErase)
152 | self.menu.clicked.connect(self.showMenu)
153 | self.languages.currentTextChanged.connect(self.langOption)
154 |
155 |
156 | def stylesheet1(self):
157 | self.bar.setStyleSheet(
158 | """ QProgressBar {
159 | border: 2px solid #3F51B5;
160 | border-radius: 5px;
161 | text-align: center;
162 | font-weight: bold;
163 | }
164 |
165 | QProgressBar::chunk {
166 | background-color: #3F51B5;
167 | width: 10px;
168 | margin: 0.5px;
169 | border-radius:1px;
170 | }""")
171 | font = QFont()
172 | font.setFamily("Comic Sans MS")
173 | self.bar.setFont(font)
174 |
175 |
176 |
177 | def changeToManual(self):
178 | self.im.flag = True
179 | self.drawOnPages()
180 | self.AutoWidget.hide()
181 | self.ManualWidget.show()
182 | self.editRect.show()
183 | self.widget_2.hide()
184 | if self.on1:
185 | self.ManualWidget.hide()
186 | self.on1= False
187 | else:
188 | self.on1 = True
189 | self.on2 = False
190 | self.on3 = False
191 | self.automaticButton.setStyleSheet("QPushButton:\n"
192 | "{\n"
193 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
194 | " x2: 1, y2: 0, \n"
195 | " stop: 0 #c471f5, \n"
196 | " stop: 1 #fa71cd );\n"
197 | "}"
198 | "QPushButton:hover:!pressed\n"
199 | "{\n"
200 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
201 | " x2: 1, y2: 0, \n"
202 | " stop: 0 #c471f5, \n"
203 | " stop: 1 #fa71cd );\n"
204 | "}")
205 | self.manualButton.setStyleSheet("QPushButton{\n"
206 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
207 | " x2: 1, y2: 0, \n"
208 | " stop: 0 #c471f5, \n"
209 | " stop: 1 #fa71cd );\n"
210 | "}\n"
211 | "QPushButton:hover:!pressed\n"
212 | "{\n"
213 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
214 | " x2: 1, y2: 0, \n"
215 | " stop: 0 #c471f5, \n"
216 | " stop: 1 #fa71cd );\n"
217 | "}")
218 |
219 |
220 |
221 | def changeToAutomatic(self):
222 | self.im.flag = False
223 | self.ManualWidget.hide()
224 | self.AutoWidget.show()
225 | self.editRect.hide()
226 | self.widget_2.hide()
227 | if self.on2:
228 | self.AutoWidget.hide()
229 | self.on2= False
230 | else:
231 | self.on2 = True
232 | self.on1 = False
233 | self.on3 = False
234 | self.manualButton.setStyleSheet("QPushButton:\n"
235 | "{\n"
236 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
237 | " x2: 1, y2: 0, \n"
238 | " stop: 0 #c471f5, \n"
239 | " stop: 1 #fa71cd );\n"
240 | "}"
241 | "QPushButton:hover:!pressed\n"
242 | "{\n"
243 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
244 | " x2: 1, y2: 0, \n"
245 | " stop: 0 #c471f5, \n"
246 | " stop: 1 #fa71cd );\n"
247 | "}")
248 | self.automaticButton.setStyleSheet("QPushButton{\n"
249 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
250 | " x2: 1, y2: 0, \n"
251 | " stop: 0 #c471f5, \n"
252 | " stop: 1 #fa71cd );\n"
253 | "}\n"
254 | "QPushButton:hover:!pressed\n"
255 | "{\n"
256 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
257 | " x2: 1, y2: 0, \n"
258 | " stop: 0 #c471f5, \n"
259 | " stop: 1 #fa71cd );\n"
260 | "}")
261 |
262 | if self.files != []:
263 | self.showImage()
264 |
265 | def advanceSettings1(self):
266 | self.ui.translatePath.setText(str(self.setting.Translated))
267 | self.ui.cropPath.setText(str(self.setting.cropText))
268 | self.ui.deeplKey.setText(str(self.setting.downLoad))
269 | self.ui.consumerKey.setText(str(self.setting.consumer_key))
270 | self.ui.consumerSecret.setText(str(self.setting.consumer_secret))
271 | self.ui.accessToken.setText(str(self.setting.access_token))
272 | self.ui.accessTokenSecret.setText(str(self.setting.access_token_secret))
273 | self.ui.bearerToken.setText(str(self.setting.bearer_token))
274 |
275 | def advanceSettings(self):
276 | self.ui.translatePath.setText(str(self.setting.Translated))
277 | self.ui.cropPath.setText(str(self.setting.cropText))
278 | self.ui.deeplKey.setText(str(self.setting.downLoad))
279 | self.ui.consumerKey.setText(str(self.setting.consumer_key))
280 | self.ui.consumerSecret.setText(str(self.setting.consumer_secret))
281 | self.ui.accessToken.setText(str(self.setting.access_token))
282 | self.ui.accessTokenSecret.setText(str(self.setting.access_token_secret))
283 | self.ui.bearerToken.setText(str(self.setting.bearer_token))
284 |
285 | self.Form.show()
286 |
287 | def getInfo(self):
288 | save = self.ui.translatePath.text()
289 | crop = self.ui.cropPath.text()
290 | download = self.ui.deeplKey.text()
291 | consumer_key = self.ui.consumerKey.text()
292 | consumer_secret = self.ui.consumerSecret.text()
293 | access_token = self.ui.accessToken.text()
294 | access_token_secret = self.ui.accessTokenSecret.text()
295 | bearer_token = self.ui.bearerToken.text()
296 | if save != self.setting.Translated:
297 | self.setting.updateSetting("Paths", "Translated", save)
298 | self.ui.translatePath.setText(save)
299 |
300 | if crop != self.setting.cropText:
301 | self.setting.updateSetting("Paths", "cropText", crop)
302 | self.ui.cropPath.setText(crop)
303 |
304 | if download != self.setting.downLoad:
305 | self.setting.updateSetting("Paths", "Download", download)
306 | self.ui.deeplKey.setText(download)
307 |
308 | if consumer_key != self.setting.consumer_key:
309 | self.setting.updateSetting("Twitter", "Consumer key", consumer_key)
310 | self.ui.consumerKey.setText(consumer_key)
311 |
312 | if consumer_secret != self.setting.consumer_secret:
313 | self.setting.updateSetting("Twitter", "Consumer secret", consumer_secret)
314 | self.ui.consumerSecret.setText(consumer_secret)
315 |
316 | if access_token != self.setting.access_token:
317 | self.setting.updateSetting("Twitter", "Access token", access_token)
318 | self.ui.accessToken.setText(access_token)
319 |
320 | if access_token_secret != self.setting.access_token_secret:
321 | self.setting.updateSetting("Twitter", "Access token secret", access_token_secret)
322 | self.ui.accessTokenSecret.setText(access_token_secret)
323 |
324 | if bearer_token != self.setting.bearer_token:
325 | if "%" in bearer_token:
326 | bearer_token = str(bearer_token.split("%"))
327 | self.setting.updateSetting("Twitter", "Bearer token", bearer_token)
328 | self.ui.bearerToken.setText(bearer_token)
329 |
330 | def sortFile(self, n):
331 | if n and self.files != []:
332 | self.fileSorting()
333 | self.showImage()
334 | self.isSort = True
335 |
336 | def fileSorting(self):
337 | nd = {}
338 | conn = {}
339 | sortedFiles = []
340 | temp = []
341 | for file in self.files:
342 | sp = file.split("/")
343 | nd[sp[-1].split(".")[0]] = file
344 | # pprint(nd)
345 | for n in nd.keys():
346 | if n.isdigit():
347 | temp.append(int(n))
348 | conn[int(n)] = n
349 | else:
350 | conn[n] = n
351 | temp.append(n)
352 | temp.sort()
353 | for x in temp:
354 | sortedFiles.append(nd[conn[x]])
355 | self.files = sortedFiles
356 |
357 |
358 | def removeRectangle(self, n):
359 | if n:
360 | self.im.rect = False
361 | else:
362 | self.im.rect = True
363 |
364 | def changeTrans(self, n):
365 | if n != None or n != []:
366 | self.changeTranslation = n
367 |
368 | def changeCheckThing(self, n):
369 | if n != None or n != []:
370 | self.checkthing = n
371 |
372 | def showSet(self):
373 | self.widget_2.show()
374 | self.AutoWidget.hide()
375 | self.ManualWidget.hide()
376 | if self.on3:
377 | self.widget_2.hide()
378 | self.on3 = False
379 | else:
380 | self.on3 = True
381 | self.on2 = False
382 | self.on1 = False
383 |
384 | def showMenu(self):
385 | self.side_menu.show()
386 | if self.shownSetting:
387 | self.side_menu.hide()
388 | self.shownSetting= False
389 | else:
390 | self.shownSetting = True
391 |
392 | def showSearch(self):
393 | self.searchwidget.show()
394 |
395 | if self.shownWidget:
396 | self.searchwidget.hide()
397 | self.shownWidget = False
398 | else:
399 | self.shownWidget = True
400 |
401 | def startErase(self):
402 | if self.im.erase:
403 | self.im.erase = False
404 | self.eraseButton.setStyleSheet("QPushButton{\n"
405 | "border:none;\n"
406 | "width:150px;\n"
407 | "height:50px;\n"
408 | "border-radius:5px;\n"
409 | "}\n"
410 | "QPushButton:hover:!pressed{\n"
411 | "border:1px solid rgb(170, 0, 255);\n"
412 | "}\n"
413 | "\n"
414 | "")
415 | else:
416 | self.im.erase = True
417 | self.eraseButton.setStyleSheet("QPushButton{\n"
418 | "width:150px;\n"
419 | "height:50px;\n"
420 | "border-radius:5px;\n"
421 | "border:2px solid rgb(170, 0, 255);\n"
422 | "}\n"
423 | "QPushButton:hover:!pressed{\n"
424 | "border:1px solid rgb(170, 0, 255);\n"
425 | "}\n"
426 | "\n"
427 | "")
428 |
429 | def choosenTranslator(self, i):
430 | self.translator = i
431 |
432 | def backgroundColor(self, i):
433 | self.im.bg = i
434 |
435 | def orgLang(self, i):
436 | self.orgLanguage = i
437 |
438 | def langOption(self, i):
439 | self.originalLang = self.ISPCode[i]
440 |
441 | def textColors(self, i):
442 | self.im.textColor = i
443 |
444 | def chooseRange(self, i):
445 | self.range = i
446 | self.rangeLabel.setText(f"Range: {self.range}px")
447 |
448 | def chooseFontNumber(self, i):
449 | self.im.fontNum = i
450 | self.label_4.setText(f"Font Size: {self.im.fontNum}")
451 |
452 | def showCombN (self, i):
453 | if i == 0:
454 | self.combineN = False
455 | self.rangeSlider.setEnabled(False)
456 | else:
457 | self.combineN = True
458 | self.rangeSlider.setEnabled(True)
459 |
460 | def showCombO (self, i):
461 | if i == 0:
462 | self.combineO = False
463 | else:
464 | self.combineO = True
465 |
466 | def getCurr(self, i):
467 | if i != 0:
468 | self.single = True
469 | else:
470 | self.single = False
471 |
472 | def clear(self):
473 | self.im.pages.clear()
474 | self.im.connectDict.clear()
475 | self.im.translated.clear()
476 | self.im.japanese.clear()
477 | self.files.clear()
478 | self.recycle.clear()
479 | self.num = -1
480 | self.index = 0
481 | self.im.img = None
482 | self.im.setPixmap(QPixmap(":/newPrefix/whiteBG.jpg"))
483 |
484 | def undo(self):
485 | lastRect = self.im.img
486 | if self.im.pages != {} and self.im.pages[lastRect] != []:
487 | if lastRect not in self.recycle:
488 | self.recycle[lastRect] = [self.im.pages[lastRect][-1]]
489 | else:
490 | self.recycle[lastRect].append(self.im.pages[lastRect][-1])
491 | if self.im.pages[lastRect] != []:
492 | del self.im.pages[lastRect][-1]
493 |
494 | def redo(self):
495 | lastRect = self.im.img
496 | if self.recycle != {} and self.recycle[lastRect] != []:
497 | self.im.pages[lastRect].append(self.recycle[lastRect][self.num])
498 | self.num -= -1
499 |
500 | def linkUpload(self):
501 | if self.files != [] and self.isClicked:
502 | self.isClicked = False
503 | self.index = 0
504 | self.changeTranslation.clear()
505 | self.im.pages.clear()
506 | self.im.connectDict.clear()
507 | self.im.translated.clear()
508 | self.im.japanese.clear()
509 | if self.setting.downLoad == "":
510 | directory = QFileDialog.getExistingDirectory(self, 'Select a directory')
511 | self.setting.updateSetting("Paths", "Download", directory)
512 | self.setting.getUpdateInfo()
513 | self.ui.deeplKey.setText(directory)
514 | try:
515 | if self.setting.consumer_key == "None" or self.setting.consumer_secret == "None" or self.setting.access_token == "None" or self.setting.access_token_secret == "None" or self.setting.bearer_token == "None":
516 | self.Form.show()
517 | loop = QEventLoop()
518 | self.Form.destroyed.connect(loop.quit)
519 | loop.exec()
520 | print("finished")
521 | self.setting.getUpdateInfo()
522 | link = self.linkBar.text()
523 | twitter = Twitter()
524 | images = twitter.getImageUrl(link)
525 | self.files = twitter.download(images)
526 | if self.files != []:
527 | self.im.img = self.files[0]
528 | self.showImage()
529 | self.linkBar.clear()
530 | except:
531 | logger.exception("Not Downloadable")
532 |
533 |
534 |
535 | def upload1(self):
536 | filenames, _ = QFileDialog.getOpenFileNames(
537 | None,
538 | "QFileDialog.getOpenFileNames()",
539 | "",
540 | "Image files (*.jpg *.png *.jpeg *.jfif)"
541 | )
542 | if filenames != []:
543 | if self.files != [] and self.isClicked:
544 | self.files.clear()
545 | self.index = 0
546 | self.isClicked = False
547 | self.im.pages.clear()
548 | self.im.japanese.clear()
549 | self.im.translated.clear()
550 | self.im.connectDict.clear()
551 | self.recycle.clear()
552 | self.num = -1
553 | self.handling.deleteFiles(self.setting.Translated)
554 | for file in filenames:
555 | self.files.append(file)
556 | if self.files != []:
557 | self.im.img = self.files[0]
558 | if self.isSort:
559 | self.fileSorting()
560 | self.showImage()
561 | if self.isClicked == False:
562 | self.translatedFiles.clear()
563 | self.saveButton.hide()
564 | self.changeTranslation.clear()
565 | self.newIndex = 0
566 |
567 | def saveImages(self):
568 | if self.translatedFiles == [] and not self.im.flag:
569 | pass
570 | elif self.translatedFiles != [] and not self.im.flag:
571 | filename = QFileDialog.getSaveFileName(self, 'Save File')
572 | imgDirectory = []
573 | num = 0
574 | for img in self.translatedFiles:
575 | image = ImageQt.fromqimage(img)
576 | imgName = f"Translated\img{num}.jpg"
577 | imgDirectory.append(imgName)
578 | image.save(imgName)
579 | num += 1
580 | with open((filename[0]+".pdf"), "wb") as f:
581 | f.write(img2pdf.convert(imgDirectory))
582 | else:
583 | filename = QFileDialog.getSaveFileName(self, 'Save File')
584 | imgDirectory = []
585 | pageCopy = self.im.scaledDict
586 | nums = 0
587 | for img in pageCopy:
588 | try:
589 | num = 0
590 | pix = QPixmap(img)
591 | qp = QtGui.QPainter(pix)
592 | qp.setPen(QPen(self.im.color[self.im.textColor], 2, Qt.SolidLine))
593 | qp.drawPixmap(pix.rect(), pix)
594 | if self.im.rect:
595 | qp.drawRects(self.im.scaledDict[img])
596 | for index, words in enumerate(self.im.translated[self.im.connectDict[img]]):
597 | if self.im.bg != "None":
598 | qp.fillRect(self.im.scaledDict[img][index], self.im.color[self.im.bg])
599 | qp.setFont(QFont("Comic Sans MS",self.im.fontNum * 2))
600 | option = QTextOption()
601 | option.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
602 | qp.drawText(self.im.scaledDict[img][index], words, option)
603 | imName = f"Translated\Truetrans{nums}.jpg"
604 | imgDirectory.append(imName)
605 | pix.save(imName)
606 | nums += 1
607 | qp.end()
608 | except:
609 | logger.exception("Something went wrong!")
610 | with open((filename[0]+".pdf"), "wb") as f:
611 | f.write(img2pdf.convert(imgDirectory))
612 |
613 | def moveRight(self):
614 | if self.isClicked and not self.im.flag:
615 | if self.newIndex >= len(self.translatedFiles)-1:
616 | self.newIndex = len(self.translatedFiles)-1
617 | else:
618 | self.newIndex += 1
619 | else:
620 | if self.index >= len(self.files)-1:
621 | self.index = len(self.files)-1
622 | else:
623 | self.index += 1
624 | if self.files != []:
625 | self.showImage()
626 | self.drawOnPages()
627 |
628 | def moveLeft(self):
629 | if self.isClicked and not self.im.flag:
630 | if self.newIndex <= 0:
631 | self.newIndex = 0
632 | else:
633 | self.newIndex -= 1
634 | else:
635 | if self.index <= 0:
636 | self.index = 0
637 | else:
638 | self.index -= 1
639 | if self.files != []:
640 | self.showImage()
641 | self.drawOnPages()
642 |
643 | def drawOnPages(self):
644 | if self.im.flag and self.files != []:
645 | for img in self.files:
646 | if img not in self.im.pages:
647 | self.im.pages[img] = []
648 | currentP = self.files[self.index]
649 | self.im.img = currentP
650 |
651 | @logger.catch
652 | def showImage(self):
653 | if self.isClicked and not self.im.flag and self.translatedFiles != []:
654 | self.saveButton.show()
655 | im = self.translatedFiles[self.newIndex]
656 | pix = QPixmap(im)
657 | self.im.setPixmap(pix)
658 | elif self.isClicked and self.im.flag:
659 | self.drawOnPages()
660 | im = self.files[self.index]
661 | pix = QPixmap(im)
662 | self.im.image = pix
663 | self.saveButton.show()
664 | else:
665 | pix = QPixmap(self.files[self.index])
666 | self.im.image = pix
667 | size = pix.size()
668 | self.clearButton.show()
669 | if size.width() > size.height():
670 | self.imageWidget.setMaximumSize(QtCore.QSize(990,680))
671 | else:
672 | self.imageWidget.setMaximumSize(QtCore.QSize(700,800))
673 | if not self.im.flag:
674 | self.im.setPixmap(self.im.image)
675 | self.drawOnPages()
676 |
677 | def afterThread(self, translated):
678 | if translated != None or translated != []:
679 | self.isClicked = True
680 | self.translatedFiles = translated
681 | self.index = 0
682 | self.newIndex = 0
683 | QtCore.QTimer.singleShot(0, self.showImage)
684 | print("THREAD COMPLETE!")
685 |
686 | def singleAfterThread(self, page):
687 | if page != None:
688 | self.translatedFiles[self.newIndex] = page
689 | QtCore.QTimer.singleShot(0, self.showImage)
690 | print("THREAD COMPLETE!")
691 |
692 | def manualAfterThread(self, e):
693 | if e != "ERROR":
694 | self.isClicked = True
695 | QtCore.QTimer.singleShot(0, self.showImage)
696 | self.im.connectDict = e[0]
697 | self.im.translated = e[1]
698 | self.im.japanese = e[2]
699 | self.im.scaledDict = e[3]
700 | self.index = 0
701 | self.newIndex = 0
702 | print("THREAD COMPLETE!")
703 |
704 | def manualRetranslate(self, e):
705 | self.im.translated = e
706 | print("THREAD COMPLETE!")
707 |
708 | def translatingCurrentPage(self, progress):
709 | self.bar.setFormat(progress)
710 |
711 | def changeProgress(self, status):
712 | self.bar.setValue(status)
713 |
714 | def showProgress(self):
715 | if self.files != []:
716 | self.bar.setVisible(True)
717 | self.translate.setEnabled(False)
718 |
719 | def hideProgress(self):
720 | self.bar.setVisible(False)
721 | self.bar.setValue(0)
722 | self.translate.setEnabled(True)
723 |
724 |
725 | def translate1(self):
726 | self.clearButton.hide()
727 | if self.files == []:
728 | pass
729 | elif self.im.flag and self.im.connectDict == {} and self.im.translated == {}:
730 | logger.info("Manual Translation")
731 | # print(self.im.pages)
732 | self.worker = ManualTranslation(self.im.pages, self.ocr, self.translator, self.originalLang, self.im.width(), self.im.height())
733 | self.worker.signals.result.connect(self.manualAfterThread)
734 | self.worker.signals.finished.connect(self.hideProgress)
735 | self.worker.signals.progress.connect(self.changeProgress)
736 | self.thread.start(self.worker)
737 | elif self.im.flag and self.im.connectDict != {} and self.im.translated != {}:
738 | self.worker = ManualTranslation(self.im.japanese, self.ocr, self.translator, self.originalLang, self.im.width(), self.im.height(), True)
739 | self.worker.signals.result.connect(self.manualRetranslate)
740 | self.worker.signals.finished.connect(self.hideProgress)
741 | self.worker.signals.progress.connect(self.changeProgress)
742 | self.thread.start(self.worker)
743 | elif self.single and self.isClicked:
744 | logger.info("Translating current page!")
745 | self.worker = SingleTranslate(self.files[self.newIndex], self.ocr, self.translator, self.combineN, self.combineO, self.range, self.orgLanguage)
746 | self.worker.signals.result.connect(self.singleAfterThread)
747 | self.worker.signals.finished.connect(self.hideProgress)
748 | self.worker.signals.progress.connect(self.changeProgress)
749 | self.thread.start(self.worker)
750 |
751 | elif self.checkthing != [] and self.changeTranslation != [] and self.checkthing[1] == self.combineN and self.checkthing[2] == self.combineO and self.checkthing[3] == self.range:
752 | logger.info(f"Using {self.translator}!")
753 | self.worker = Retranslate(self.changeTranslation, self.translator, self.orgLanguage)
754 | self.worker.signals.result.connect(self.afterThread)
755 | self.worker.signals.finished.connect(self.hideProgress)
756 | self.worker.signals.progress.connect(self.changeProgress)
757 | self.thread.start(self.worker)
758 | else:
759 | logger.info("Manga Translation")
760 | self.worker = Translate(self.files, self.ocr, self.translator, self.originalLang, self.combineN, self.combineO, self.range)
761 | self.worker.signals.result.connect(self.afterThread)
762 | self.worker.signals.stored.connect(self.changeTrans)
763 | self.worker.signals.booleans.connect(self.changeCheckThing)
764 | self.worker.signals.finished.connect(self.hideProgress)
765 | self.worker.signals.progress.connect(self.changeProgress)
766 | self.worker.signals.lang.connect(self.orgLang)
767 | self.worker.signals.pageProgress.connect(self.translatingCurrentPage)
768 | self.thread.start(self.worker)
769 |
770 |
771 | if __name__ == "__main__":
772 | import sys
773 | app =QtWidgets.QApplication(sys.argv)
774 | w = interact()
775 | w.show()
776 | sys.exit(app.exec())
777 |
--------------------------------------------------------------------------------
/Code/darkmode.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'C:/Users/andre/Desktop/QTdesigner/tutorial.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.15.7
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt5 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_MainWindow(object):
15 | def setupUi(self, MainWindow):
16 | MainWindow.setObjectName("MainWindow")
17 | MainWindow.resize(613, 574)
18 | MainWindow.setStyleSheet("")
19 | self.centralwidget = QtWidgets.QWidget(MainWindow)
20 | self.centralwidget.setStyleSheet("*{\n"
21 | " border: none;\n"
22 | " background-color: rgb(0, 0, 0);\n"
23 | " color: #fff;\n"
24 | "}\n"
25 | "#centralwidget{\n"
26 | " background-color: rgb(0, 0, 0);\n"
27 | "}\n"
28 | "#side_menu{\n"
29 | " background-color: #071e26;\n"
30 | " border-radius: 20px;\n"
31 | "}\n"
32 | "QPushButton{\n"
33 | " padding: 10px;\n"
34 | " background-color: #040f13;\n"
35 | " border-radius: 5px;\n"
36 | "}\n"
37 | "#main_body{\n"
38 | " background-color: #071e26;\n"
39 | " border-radius: 10px;\n"
40 | "}")
41 | self.centralwidget.setObjectName("centralwidget")
42 | self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
43 | self.verticalLayout.setContentsMargins(-1, 1, -1, -1)
44 | self.verticalLayout.setSpacing(0)
45 | self.verticalLayout.setObjectName("verticalLayout")
46 | self.header = QtWidgets.QFrame(self.centralwidget)
47 | self.header.setMinimumSize(QtCore.QSize(0, 50))
48 | self.header.setMaximumSize(QtCore.QSize(16777215, 50))
49 | self.header.setStyleSheet("")
50 | self.header.setFrameShape(QtWidgets.QFrame.StyledPanel)
51 | self.header.setFrameShadow(QtWidgets.QFrame.Raised)
52 | self.header.setObjectName("header")
53 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.header)
54 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
55 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
56 | self.frame = QtWidgets.QFrame(self.header)
57 | self.frame.setMinimumSize(QtCore.QSize(150, 0))
58 | self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
59 | self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
60 | self.frame.setObjectName("frame")
61 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.frame)
62 | self.horizontalLayout_4.setObjectName("horizontalLayout_4")
63 | self.menu = QtWidgets.QPushButton(self.frame)
64 | self.menu.setMinimumSize(QtCore.QSize(0, 0))
65 | font = QtGui.QFont()
66 | font.setFamily("Comic Sans MS")
67 | font.setPointSize(10)
68 | self.menu.setFont(font)
69 | self.menu.setStyleSheet("background-color: rgb(0, 0, 0);")
70 | icon = QtGui.QIcon()
71 | icon.addPixmap(QtGui.QPixmap(":/newPrefix/menu (1).png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
72 | self.menu.setIcon(icon)
73 | self.menu.setIconSize(QtCore.QSize(20, 20))
74 | self.menu.setObjectName("menu")
75 | self.horizontalLayout_4.addWidget(self.menu)
76 | self.horizontalLayout_2.addWidget(self.frame, 0, QtCore.Qt.AlignLeft)
77 | self.searchwidget = QtWidgets.QWidget(self.header)
78 | self.searchwidget.setMinimumSize(QtCore.QSize(0, 50))
79 | self.searchwidget.setObjectName("searchwidget")
80 | self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.searchwidget)
81 | self.horizontalLayout_6.setObjectName("horizontalLayout_6")
82 | self.topLayout = QtWidgets.QHBoxLayout()
83 | self.topLayout.setObjectName("topLayout")
84 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
85 | self.topLayout.addItem(spacerItem)
86 | self.linkBar = QtWidgets.QLineEdit(self.searchwidget)
87 | self.linkBar.setMaximumSize(QtCore.QSize(400, 36))
88 | font = QtGui.QFont()
89 | self.linkBar.setFont(font)
90 | self.linkBar.setStyleSheet("background-color: rgb(0, 0, 0);\n"
91 | "border: 2px solid rgb(255, 255, 255);\n"
92 | "border-radius:10px;\n"
93 | "padding-left: 10px;\n"
94 | "font-size:20px;\n"
95 | "padding-top:10px;\n"
96 | "color: rgb(255, 255, 255);")
97 | self.linkBar.setText("")
98 | self.linkBar.setObjectName("linkBar")
99 | self.topLayout.addWidget(self.linkBar)
100 | self.pushButton_6 = QtWidgets.QPushButton(self.searchwidget)
101 | self.pushButton_6.setMaximumSize(QtCore.QSize(54, 40))
102 | self.pushButton_6.setStyleSheet("QPushButton{\n"
103 | "height:40;\n"
104 | "width: 50;\n"
105 | "border-radius: 7px;\n"
106 | "padding: 10px;\n"
107 | " background-color: rgb(0, 0, 0);\n"
108 | "}\n"
109 | "QPushButton:hover:!pressed\n"
110 | "{\n"
111 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
112 | " x2: 1, y2: 0, \n"
113 | " stop: 0 #fa71cd, \n"
114 | " stop: 1 #c471f5);\n"
115 | "}")
116 | self.pushButton_6.setText("")
117 | icon1 = QtGui.QIcon()
118 | icon1.addPixmap(QtGui.QPixmap(":/newPrefix/colordownload.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
119 | self.pushButton_6.setIcon(icon1)
120 | self.pushButton_6.setIconSize(QtCore.QSize(30, 30))
121 | self.pushButton_6.setObjectName("pushButton_6")
122 | self.topLayout.addWidget(self.pushButton_6)
123 | spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
124 | self.topLayout.addItem(spacerItem1)
125 | self.topLayout.setStretch(1, 1)
126 | self.horizontalLayout_6.addLayout(self.topLayout)
127 | self.horizontalLayout_2.addWidget(self.searchwidget)
128 | self.frame_3 = QtWidgets.QFrame(self.header)
129 | self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
130 | self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
131 | self.frame_3.setObjectName("frame_3")
132 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.frame_3)
133 | self.horizontalLayout_3.setObjectName("horizontalLayout_3")
134 | self.horizontalLayout_2.addWidget(self.frame_3)
135 | self.verticalLayout.addWidget(self.header)
136 | self.frame_2 = QtWidgets.QFrame(self.centralwidget)
137 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
138 | sizePolicy.setHorizontalStretch(0)
139 | sizePolicy.setVerticalStretch(0)
140 | sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth())
141 | self.frame_2.setSizePolicy(sizePolicy)
142 | self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
143 | self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
144 | self.frame_2.setObjectName("frame_2")
145 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame_2)
146 | self.horizontalLayout.setContentsMargins(-1, 7, -1, -1)
147 | self.horizontalLayout.setObjectName("horizontalLayout")
148 | self.side_menu = QtWidgets.QWidget(self.frame_2)
149 | self.side_menu.setMinimumSize(QtCore.QSize(160, 150))
150 | self.side_menu.setStyleSheet("background-color: rgb(0, 0, 0);")
151 | self.side_menu.setObjectName("side_menu")
152 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.side_menu)
153 | self.verticalLayout_2.setContentsMargins(-1, 10, -1, -1)
154 | self.verticalLayout_2.setObjectName("verticalLayout_2")
155 | self.automaticButton = QtWidgets.QPushButton(self.side_menu)
156 | font = QtGui.QFont()
157 | font.setFamily("Comic Sans MS")
158 | font.setPointSize(10)
159 | self.automaticButton.setFont(font)
160 | self.automaticButton.setStyleSheet("QPushButton:hover:!pressed\n"
161 | "{\n"
162 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
163 | " x2: 1, y2: 0, \n"
164 | " stop: 0 #c471f5, \n"
165 | " stop: 1 #fa71cd );\n"
166 | "}")
167 | self.automaticButton.setObjectName("automaticButton")
168 | self.verticalLayout_2.addWidget(self.automaticButton)
169 | self.AutoWidget = QtWidgets.QWidget(self.side_menu)
170 | self.AutoWidget.setObjectName("AutoWidget")
171 | self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.AutoWidget)
172 | self.verticalLayout_6.setObjectName("verticalLayout_6")
173 | self.innerSettings = QtWidgets.QVBoxLayout()
174 | self.innerSettings.setContentsMargins(-1, -1, 4, -1)
175 | self.innerSettings.setSpacing(5)
176 | self.innerSettings.setObjectName("innerSettings")
177 | self.rectangleLabel = QtWidgets.QLabel(self.AutoWidget)
178 | font = QtGui.QFont()
179 | font.setFamily("Comic Sans MS")
180 | self.rectangleLabel.setFont(font)
181 | self.rectangleLabel.setObjectName("rectangleLabel")
182 | self.innerSettings.addWidget(self.rectangleLabel, 0, QtCore.Qt.AlignHCenter)
183 | self.combineOverLap = QtWidgets.QCheckBox(self.AutoWidget)
184 | font = QtGui.QFont()
185 | font.setFamily("Comic Sans MS")
186 | self.combineOverLap.setFont(font)
187 | self.combineOverLap.setStyleSheet("")
188 | self.combineOverLap.setChecked(True)
189 | self.combineOverLap.setObjectName("combineOverLap")
190 | self.innerSettings.addWidget(self.combineOverLap, 0, QtCore.Qt.AlignLeft)
191 | self.combineNeighbors = QtWidgets.QCheckBox(self.AutoWidget)
192 | font = QtGui.QFont()
193 | font.setFamily("Comic Sans MS")
194 | self.combineNeighbors.setFont(font)
195 | self.combineNeighbors.setStyleSheet("")
196 | self.combineNeighbors.setObjectName("combineNeighbors")
197 | self.innerSettings.addWidget(self.combineNeighbors, 0, QtCore.Qt.AlignLeft)
198 | self.rangeLabel = QtWidgets.QLabel(self.AutoWidget)
199 | font = QtGui.QFont()
200 | font.setFamily("Comic Sans MS")
201 | self.rangeLabel.setFont(font)
202 | self.rangeLabel.setStyleSheet("height:20;")
203 | self.rangeLabel.setObjectName("rangeLabel")
204 | self.innerSettings.addWidget(self.rangeLabel)
205 | self.rangeSlider = QtWidgets.QSlider(self.AutoWidget)
206 | self.rangeSlider.setOrientation(QtCore.Qt.Horizontal)
207 | self.rangeSlider.setObjectName("rangeSlider")
208 | self.innerSettings.addWidget(self.rangeSlider)
209 | self.singlePtranslate = QtWidgets.QCheckBox(self.AutoWidget)
210 | font = QtGui.QFont()
211 | font.setFamily("Comic Sans MS")
212 | font.setPointSize(8)
213 | self.singlePtranslate.setFont(font)
214 | self.singlePtranslate.setIconSize(QtCore.QSize(12, 12))
215 | self.singlePtranslate.setObjectName("singlePtranslate")
216 | self.innerSettings.addWidget(self.singlePtranslate, 0, QtCore.Qt.AlignLeft)
217 | self.verticalLayout_6.addLayout(self.innerSettings)
218 | self.verticalLayout_2.addWidget(self.AutoWidget)
219 | self.manualButton = QtWidgets.QPushButton(self.side_menu)
220 | font = QtGui.QFont()
221 | font.setFamily("Comic Sans MS")
222 | font.setPointSize(10)
223 | self.manualButton.setFont(font)
224 | self.manualButton.setStyleSheet("QPushButton:hover:!pressed\n"
225 | "{\n"
226 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
227 | " x2: 1, y2: 0, \n"
228 | " stop: 0 #c471f5, \n"
229 | " stop: 1 #fa71cd );\n"
230 | "}")
231 | self.manualButton.setObjectName("manualButton")
232 | self.verticalLayout_2.addWidget(self.manualButton)
233 | self.ManualWidget = QtWidgets.QWidget(self.side_menu)
234 | self.ManualWidget.setObjectName("ManualWidget")
235 | self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.ManualWidget)
236 | self.verticalLayout_7.setSpacing(2)
237 | self.verticalLayout_7.setObjectName("verticalLayout_7")
238 | self.manualSet = QtWidgets.QVBoxLayout()
239 | self.manualSet.setSpacing(4)
240 | self.manualSet.setObjectName("manualSet")
241 | self.label_2 = QtWidgets.QLabel(self.ManualWidget)
242 | font = QtGui.QFont()
243 | font.setFamily("Comic Sans MS")
244 | self.label_2.setFont(font)
245 | self.label_2.setObjectName("label_2")
246 | self.manualSet.addWidget(self.label_2)
247 | self.Textcolor = QtWidgets.QComboBox(self.ManualWidget)
248 | font = QtGui.QFont()
249 | font.setFamily("Comic Sans MS")
250 | self.Textcolor.setFont(font)
251 | self.Textcolor.setStyleSheet("QComboBox{\n"
252 | "border-color: rgb(85, 170, 255);\n"
253 | "border-radius: 5px;\n"
254 | "}\n"
255 | "QComboBox::on{\n"
256 | "border: 2px solid #c2dbfe;\n"
257 | "}\n"
258 | "QComboBox::drop-down{\n"
259 | "border:0px;\n"
260 | "}\n"
261 | "QComboBox QListView\n"
262 | "{\n"
263 | " border-style: none;\n"
264 | " background-color: white;\n"
265 | "}\n"
266 | "QComboBox::down-arrow\n"
267 | "{\n"
268 | " \n"
269 | " \n"
270 | " \n"
271 | " image: url(:/newPrefix/down-chevron.png);\n"
272 | " width: 10px;\n"
273 | " height: 10px;\n"
274 | "}")
275 | self.Textcolor.setObjectName("Textcolor")
276 | self.Textcolor.addItem("")
277 | self.Textcolor.addItem("")
278 | self.Textcolor.addItem("")
279 | self.Textcolor.addItem("")
280 | self.Textcolor.addItem("")
281 | self.manualSet.addWidget(self.Textcolor)
282 | self.label_3 = QtWidgets.QLabel(self.ManualWidget)
283 | font = QtGui.QFont()
284 | font.setFamily("Comic Sans MS")
285 | self.label_3.setFont(font)
286 | self.label_3.setObjectName("label_3")
287 | self.manualSet.addWidget(self.label_3)
288 | self.bGcolor = QtWidgets.QComboBox(self.ManualWidget)
289 | font = QtGui.QFont()
290 | font.setFamily("Comic Sans MS")
291 | self.bGcolor.setFont(font)
292 | self.bGcolor.setStyleSheet("QComboBox{\n"
293 | "border-color: rgb(85, 170, 255);\n"
294 | "}\n"
295 | "QComboBox::on{\n"
296 | "border: 2px solid #c2dbfe;\n"
297 | "}\n"
298 | "QComboBox::drop-down{\n"
299 | "border:0px;\n"
300 | "}\n"
301 | "QComboBox QListView\n"
302 | "{\n"
303 | " border-style: none;\n"
304 | " background-color: white;\n"
305 | "}\n"
306 | "QComboBox::down-arrow\n"
307 | "{\n"
308 | " \n"
309 | " \n"
310 | " \n"
311 | " image: url(:/newPrefix/down-chevron.png);\n"
312 | " width: 10px;\n"
313 | " height: 10px;\n"
314 | "}")
315 | self.bGcolor.setObjectName("bGcolor")
316 | self.bGcolor.addItem("")
317 | self.bGcolor.addItem("")
318 | self.bGcolor.addItem("")
319 | self.bGcolor.addItem("")
320 | self.bGcolor.addItem("")
321 | self.manualSet.addWidget(self.bGcolor)
322 | self.label_4 = QtWidgets.QLabel(self.ManualWidget)
323 | font = QtGui.QFont()
324 | font.setFamily("Comic Sans MS")
325 | self.label_4.setFont(font)
326 | self.label_4.setObjectName("label_4")
327 | self.manualSet.addWidget(self.label_4)
328 | self.fontsize = QtWidgets.QSlider(self.ManualWidget)
329 | self.fontsize.setToolTipDuration(1)
330 | self.fontsize.setMaximum(15)
331 | self.fontsize.setProperty("value", 6)
332 | self.fontsize.setSliderPosition(6)
333 | self.fontsize.setOrientation(QtCore.Qt.Horizontal)
334 | self.fontsize.setObjectName("fontsize")
335 | self.manualSet.addWidget(self.fontsize)
336 | self.removeRect = QtWidgets.QCheckBox(self.ManualWidget)
337 | font = QtGui.QFont()
338 | font.setFamily("Comic Sans MS")
339 | self.removeRect.setFont(font)
340 | self.removeRect.setObjectName("removeRect")
341 | self.manualSet.addWidget(self.removeRect)
342 | self.verticalLayout_7.addLayout(self.manualSet)
343 | self.verticalLayout_2.addWidget(self.ManualWidget)
344 | self.pushButton_5 = QtWidgets.QPushButton(self.side_menu)
345 | self.pushButton_5.setStyleSheet("QPushButton:hover:!pressed\n"
346 | "{\n"
347 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
348 | " x2: 1, y2: 0, \n"
349 | " stop: 0 #c471f5, \n"
350 | " stop: 1 #fa71cd );\n"
351 | "}")
352 | self.pushButton_5.setText("")
353 | icon2 = QtGui.QIcon()
354 | icon2.addPixmap(QtGui.QPixmap(":/newPrefix/gear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
355 | self.pushButton_5.setIcon(icon2)
356 | self.pushButton_5.setIconSize(QtCore.QSize(20, 20))
357 | self.pushButton_5.setObjectName("pushButton_5")
358 | self.verticalLayout_2.addWidget(self.pushButton_5)
359 | self.widget_2 = QtWidgets.QWidget(self.side_menu)
360 | self.widget_2.setObjectName("widget_2")
361 | self.verticalLayout_10 = QtWidgets.QVBoxLayout(self.widget_2)
362 | self.verticalLayout_10.setObjectName("verticalLayout_10")
363 | self.verticalLayout_9 = QtWidgets.QVBoxLayout()
364 | self.verticalLayout_9.setObjectName("verticalLayout_9")
365 | self.sortButton = QtWidgets.QCheckBox(self.widget_2)
366 | font = QtGui.QFont()
367 | font.setFamily("Comic Sans MS")
368 | self.sortButton.setFont(font)
369 | self.sortButton.setObjectName("sortButton")
370 | self.verticalLayout_9.addWidget(self.sortButton)
371 | self.label = QtWidgets.QLabel(self.widget_2)
372 | font = QtGui.QFont()
373 | font.setFamily("Comic Sans MS")
374 | self.label.setFont(font)
375 | self.label.setObjectName("label")
376 | self.verticalLayout_9.addWidget(self.label)
377 | self.translateOptions = QtWidgets.QComboBox(self.widget_2)
378 | font = QtGui.QFont()
379 | font.setFamily("Comic Sans MS")
380 | self.translateOptions.setFont(font)
381 | self.translateOptions.setStyleSheet("QComboBox{\n"
382 | "border-color: rgb(85, 170, 255);\n"
383 | "}\n"
384 | "QComboBox::on{\n"
385 | "border: 2px solid #c2dbfe;\n"
386 | "}\n"
387 | "QComboBox::drop-down{\n"
388 | "border:0px;\n"
389 | "}\n"
390 | "QComboBox QListView\n"
391 | "{\n"
392 | " border-style: none;\n"
393 | " background-color: white;\n"
394 | "}\n"
395 | "QComboBox::down-arrow\n"
396 | "{\n"
397 | " image: url(:/newPrefix/down-chevron.png);\n"
398 | " width: 10px;\n"
399 | " height: 10px;\n"
400 | "}\n"
401 | "")
402 | self.translateOptions.setObjectName("translateOptions")
403 | self.translateOptions.addItem("")
404 | self.translateOptions.addItem("")
405 | self.translateOptions.addItem("")
406 | self.verticalLayout_9.addWidget(self.translateOptions)
407 | self.label_5 = QtWidgets.QLabel(self.widget_2)
408 | font = QtGui.QFont()
409 | font.setFamily("Comic Sans MS")
410 | self.label_5.setFont(font)
411 | self.label_5.setObjectName("label_5")
412 | self.verticalLayout_9.addWidget(self.label_5)
413 | self.languages = QtWidgets.QComboBox(self.widget_2)
414 | font = QtGui.QFont()
415 | font.setFamily("Comic Sans MS")
416 | self.languages.setFont(font)
417 | self.languages.setStyleSheet("QComboBox{\n"
418 | "border-color: rgb(85, 170, 255);\n"
419 | "}\n"
420 | "QComboBox::on{\n"
421 | "border: 2px solid #c2dbfe;\n"
422 | "}\n"
423 | "QComboBox::drop-down{\n"
424 | "border:0px;\n"
425 | "}\n"
426 | "QComboBox QListView\n"
427 | "{\n"
428 | " border-style: none;\n"
429 | " background-color: white;\n"
430 | "}\n"
431 | "QComboBox::down-arrow\n"
432 | "{\n"
433 | " image: url(:/newPrefix/down-chevron.png);\n"
434 | " width: 10px;\n"
435 | " height: 10px;\n"
436 | "}")
437 | self.languages.setObjectName("languages")
438 | self.languages.addItem("")
439 | self.languages.addItem("")
440 | self.languages.addItem("")
441 | self.languages.addItem("")
442 | self.verticalLayout_9.addWidget(self.languages)
443 | self.advanced = QtWidgets.QPushButton(self.widget_2)
444 | font = QtGui.QFont()
445 | font.setFamily("Comic Sans MS")
446 | self.advanced.setFont(font)
447 | self.advanced.setStyleSheet("QPushButton{\n"
448 | "height:20;\n"
449 | "width: 50;\n"
450 | "padding: 10px;\n"
451 | "background-color: #040f13;\n"
452 | "border-radius: 5px;\n"
453 | "}\n"
454 | "QPushButton:hover:!pressed\n"
455 | "{\n"
456 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
457 | " x2: 1, y2: 0, \n"
458 | " stop: 0 #fa71cd, \n"
459 | " stop: 1 #c471f5);\n"
460 | "}")
461 | self.advanced.setObjectName("advanced")
462 | self.verticalLayout_9.addWidget(self.advanced)
463 | self.verticalLayout_10.addLayout(self.verticalLayout_9)
464 | self.verticalLayout_2.addWidget(self.widget_2)
465 | self.pushButton_2 = QtWidgets.QPushButton(self.side_menu)
466 | self.pushButton_2.setStyleSheet("QPushButton:hover:!pressed\n"
467 | "{\n"
468 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
469 | " x2: 1, y2: 0, \n"
470 | " stop: 0 #c471f5, \n"
471 | " stop: 1 #fa71cd );\n"
472 | "}")
473 | self.pushButton_2.setText("")
474 | icon3 = QtGui.QIcon()
475 | icon3.addPixmap(QtGui.QPixmap(":/newPrefix/twitter.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
476 | self.pushButton_2.setIcon(icon3)
477 | self.pushButton_2.setIconSize(QtCore.QSize(20, 20))
478 | self.pushButton_2.setObjectName("pushButton_2")
479 | self.verticalLayout_2.addWidget(self.pushButton_2)
480 | spacerItem2 = QtWidgets.QSpacerItem(135, 60, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
481 | self.verticalLayout_2.addItem(spacerItem2)
482 | self.horizontalLayout.addWidget(self.side_menu, 0, QtCore.Qt.AlignLeft)
483 | self.main_body = QtWidgets.QFrame(self.frame_2)
484 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
485 | sizePolicy.setHorizontalStretch(0)
486 | sizePolicy.setVerticalStretch(0)
487 | sizePolicy.setHeightForWidth(self.main_body.sizePolicy().hasHeightForWidth())
488 | self.main_body.setSizePolicy(sizePolicy)
489 | self.main_body.setMinimumSize(QtCore.QSize(200, 200))
490 | self.main_body.setFrameShape(QtWidgets.QFrame.StyledPanel)
491 | self.main_body.setFrameShadow(QtWidgets.QFrame.Raised)
492 | self.main_body.setObjectName("main_body")
493 | self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.main_body)
494 | self.verticalLayout_5.setObjectName("verticalLayout_5")
495 | self.verticalLayout_4 = QtWidgets.QVBoxLayout()
496 | self.verticalLayout_4.setSpacing(6)
497 | self.verticalLayout_4.setObjectName("verticalLayout_4")
498 | self.editRect = QtWidgets.QFrame(self.main_body)
499 | self.editRect.setMinimumSize(QtCore.QSize(80, 30))
500 | self.editRect.setMaximumSize(QtCore.QSize(150, 30))
501 | self.editRect.setToolTipDuration(0)
502 | self.editRect.setStyleSheet("background-color: rgb(255, 255, 255);\n"
503 | "border-radius:10px;")
504 | self.editRect.setFrameShape(QtWidgets.QFrame.NoFrame)
505 | self.editRect.setObjectName("editRect")
506 | self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.editRect)
507 | self.horizontalLayout_7.setContentsMargins(8, -1, -1, -1)
508 | self.horizontalLayout_7.setSpacing(5)
509 | self.horizontalLayout_7.setObjectName("horizontalLayout_7")
510 | self.undoButton = QtWidgets.QPushButton(self.editRect)
511 | self.undoButton.setMinimumSize(QtCore.QSize(20, 20))
512 | self.undoButton.setMaximumSize(QtCore.QSize(25, 16777215))
513 | self.undoButton.setStyleSheet("QPushButton{\n"
514 | "border:none;\n"
515 | "width:20px;\n"
516 | "height:20px;\n"
517 | "border-radius:5px;\n"
518 | "}\n"
519 | "QPushButton:hover:!pressed{\n"
520 | "border:1px solid rgb(170, 0, 255);\n"
521 | "}")
522 | self.undoButton.setText("")
523 | icon4 = QtGui.QIcon()
524 | icon4.addPixmap(QtGui.QPixmap(":/newPrefix/forward1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
525 | self.undoButton.setIcon(icon4)
526 | self.undoButton.setIconSize(QtCore.QSize(20, 20))
527 | self.undoButton.setObjectName("undoButton")
528 | self.horizontalLayout_7.addWidget(self.undoButton)
529 | self.eraseButton = QtWidgets.QPushButton(self.editRect)
530 | self.eraseButton.setMinimumSize(QtCore.QSize(20, 20))
531 | self.eraseButton.setMaximumSize(QtCore.QSize(40, 16777215))
532 | self.eraseButton.setStyleSheet("QPushButton{\n"
533 | "border:none;\n"
534 | "width:20px;\n"
535 | "height:20px;\n"
536 | "border-radius:5px;\n"
537 | "}\n"
538 | "QPushButton:hover:!pressed{\n"
539 | "border:1px solid rgb(170, 0, 255);\n"
540 | "}\n"
541 | "\n"
542 | "")
543 | self.eraseButton.setText("")
544 | icon5 = QtGui.QIcon()
545 | icon5.addPixmap(QtGui.QPixmap(":/newPrefix/eraser.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
546 | self.eraseButton.setIcon(icon5)
547 | self.eraseButton.setIconSize(QtCore.QSize(20, 20))
548 | self.eraseButton.setObjectName("eraseButton")
549 | self.horizontalLayout_7.addWidget(self.eraseButton)
550 | self.redoButton = QtWidgets.QPushButton(self.editRect)
551 | self.redoButton.setMinimumSize(QtCore.QSize(20, 20))
552 | self.redoButton.setMaximumSize(QtCore.QSize(25, 16777215))
553 | self.redoButton.setStyleSheet("QPushButton{\n"
554 | "border:none;\n"
555 | "width:20px;\n"
556 | "height:20px;\n"
557 | "border-radius:5px;\n"
558 | "}\n"
559 | "QPushButton:hover:!pressed{\n"
560 | "border:1px solid rgb(170, 0, 255);\n"
561 | "}")
562 | self.redoButton.setText("")
563 | icon6 = QtGui.QIcon()
564 | icon6.addPixmap(QtGui.QPixmap(":/newPrefix/forward.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
565 | self.redoButton.setIcon(icon6)
566 | self.redoButton.setIconSize(QtCore.QSize(20, 20))
567 | self.redoButton.setObjectName("redoButton")
568 | self.horizontalLayout_7.addWidget(self.redoButton)
569 | self.verticalLayout_4.addWidget(self.editRect, 0, QtCore.Qt.AlignHCenter)
570 | self.imageDisplay = QtWidgets.QHBoxLayout()
571 | self.imageDisplay.setObjectName("imageDisplay")
572 | self.leftArrow = QtWidgets.QPushButton(self.main_body)
573 | self.leftArrow.setMaximumSize(QtCore.QSize(70, 90))
574 | self.leftArrow.setStyleSheet("QPushButton{\n"
575 | "height:90;\n"
576 | "width: 70;\n"
577 | "border-radius: 25px;\n"
578 | "padding: 10px;\n"
579 | "background-color: #040f13;\n"
580 | "}\n"
581 | "QPushButton:hover:!pressed\n"
582 | "{\n"
583 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
584 | " x2: 1, y2: 0, \n"
585 | " stop: 0 #c471f5, \n"
586 | " stop: 1 #fa71cd );\n"
587 | "}")
588 | self.leftArrow.setText("")
589 | icon7 = QtGui.QIcon()
590 | icon7.addPixmap(QtGui.QPixmap(":/newPrefix/play1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
591 | self.leftArrow.setIcon(icon7)
592 | self.leftArrow.setIconSize(QtCore.QSize(50, 50))
593 | self.leftArrow.setObjectName("leftArrow")
594 | self.imageDisplay.addWidget(self.leftArrow)
595 | self.imageWidget = QtWidgets.QWidget(self.main_body)
596 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
597 | sizePolicy.setHorizontalStretch(0)
598 | sizePolicy.setVerticalStretch(0)
599 | sizePolicy.setHeightForWidth(self.imageWidget.sizePolicy().hasHeightForWidth())
600 | self.imageWidget.setSizePolicy(sizePolicy)
601 | self.imageWidget.setMinimumSize(QtCore.QSize(0, 0))
602 | self.imageWidget.setMaximumSize(QtCore.QSize(400, 300))
603 | self.imageWidget.setStyleSheet("background-color: #040f13;\n"
604 | "border-radius: 10px")
605 | self.imageWidget.setObjectName("imageWidget")
606 | self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.imageWidget)
607 | self.horizontalLayout_5.setObjectName("horizontalLayout_5")
608 | self.imageDisplay.addWidget(self.imageWidget)
609 | self.rightArrow = QtWidgets.QPushButton(self.main_body)
610 | self.rightArrow.setMaximumSize(QtCore.QSize(70, 90))
611 | self.rightArrow.setStyleSheet("QPushButton{\n"
612 | "height:90;\n"
613 | "width: 70;\n"
614 | "border-radius: 25px;\n"
615 | "padding: 10px;\n"
616 | "background-color: #040f13;\n"
617 | "}\n"
618 | "QPushButton:hover:!pressed\n"
619 | "{\n"
620 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
621 | " x2: 1, y2: 0, \n"
622 | " stop: 0 #c471f5, \n"
623 | " stop: 1 #fa71cd );\n"
624 | "}")
625 | self.rightArrow.setText("")
626 | icon8 = QtGui.QIcon()
627 | icon8.addPixmap(QtGui.QPixmap(":/newPrefix/play.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
628 | self.rightArrow.setIcon(icon8)
629 | self.rightArrow.setIconSize(QtCore.QSize(50, 50))
630 | self.rightArrow.setObjectName("rightArrow")
631 | self.imageDisplay.addWidget(self.rightArrow)
632 | self.imageDisplay.setStretch(1, 1)
633 | self.verticalLayout_4.addLayout(self.imageDisplay)
634 | self.bar = QtWidgets.QProgressBar(self.main_body)
635 | self.bar.setMinimumSize(QtCore.QSize(200, 30))
636 | self.bar.setMaximumSize(QtCore.QSize(200, 30))
637 | self.bar.setStyleSheet("QProgressBar {\n"
638 | " border: 2px solid #3F51B5;\n"
639 | " border-radius: 5px;\n"
640 | " text-align: center;\n"
641 | " font-weight: bold;\n"
642 | "}\n"
643 | "\n"
644 | "QProgressBar::chunk {\n"
645 | " background-color: #3F51B5;\n"
646 | " width: 10px;\n"
647 | " margin: 0.5px;\n"
648 | " border-radius:1px;\n"
649 | "}")
650 | self.bar.setProperty("value", 24)
651 | self.bar.setObjectName("bar")
652 | self.verticalLayout_4.addWidget(self.bar, 0, QtCore.Qt.AlignHCenter)
653 | self.actionButtons = QtWidgets.QHBoxLayout()
654 | self.actionButtons.setSpacing(10)
655 | self.actionButtons.setObjectName("actionButtons")
656 | spacerItem3 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
657 | self.actionButtons.addItem(spacerItem3)
658 | self.upload = QtWidgets.QPushButton(self.main_body)
659 | self.upload.setMaximumSize(QtCore.QSize(130, 45))
660 | font = QtGui.QFont()
661 | font.setFamily("Comic Sans MS")
662 | font.setPointSize(10)
663 | self.upload.setFont(font)
664 | self.upload.setStyleSheet("QPushButton{\n"
665 | "height:20;\n"
666 | "width: 30;\n"
667 | "border-radius: 7px;\n"
668 | "padding: 10px;\n"
669 | "background-color: #040f13;\n"
670 | "}\n"
671 | "QPushButton:hover:!pressed\n"
672 | "{\n"
673 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
674 | " x2: 1, y2: 0, \n"
675 | " stop: 0 #c471f5, \n"
676 | " stop: 1 #fa71cd );\n"
677 | "}")
678 | self.upload.setObjectName("upload")
679 | self.actionButtons.addWidget(self.upload)
680 | self.translate = QtWidgets.QPushButton(self.main_body)
681 | self.translate.setMaximumSize(QtCore.QSize(130, 45))
682 | font = QtGui.QFont()
683 | font.setFamily("Comic Sans MS")
684 | font.setPointSize(10)
685 | self.translate.setFont(font)
686 | self.translate.setStyleSheet("QPushButton{\n"
687 | "height:20;\n"
688 | "width: 30;\n"
689 | "border-radius: 7px;\n"
690 | "padding: 5px;\n"
691 | "background-color: #040f13;\n"
692 | "}\n"
693 | "QPushButton:hover:!pressed\n"
694 | "{\n"
695 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
696 | " x2: 1, y2: 0, \n"
697 | " stop: 0 #c471f5, \n"
698 | " stop: 1 #fa71cd );\n"
699 | "}")
700 | self.translate.setObjectName("translate")
701 | self.actionButtons.addWidget(self.translate)
702 | self.saveButton = QtWidgets.QPushButton(self.main_body)
703 | self.saveButton.setMaximumSize(QtCore.QSize(130, 45))
704 | font = QtGui.QFont()
705 | font.setFamily("Comic Sans MS")
706 | font.setPointSize(10)
707 | self.saveButton.setFont(font)
708 | self.saveButton.setStyleSheet("QPushButton{\n"
709 | "height:20;\n"
710 | "width: 30;\n"
711 | "border-radius: 7px;\n"
712 | "padding: 10px;\n"
713 | "background-color: #040f13;\n"
714 | "}\n"
715 | "QPushButton:hover:!pressed\n"
716 | "{\n"
717 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
718 | " x2: 1, y2: 0, \n"
719 | " stop: 0 #c471f5, \n"
720 | " stop: 1 #fa71cd );\n"
721 | "}")
722 | self.saveButton.setObjectName("saveButton")
723 | self.actionButtons.addWidget(self.saveButton)
724 | self.clearButton = QtWidgets.QPushButton(self.main_body)
725 | self.clearButton.setMaximumSize(QtCore.QSize(130, 45))
726 | font = QtGui.QFont()
727 | font.setFamily("Comic Sans MS")
728 | font.setPointSize(10)
729 | self.clearButton.setFont(font)
730 | self.clearButton.setStyleSheet("QPushButton{\n"
731 | "height:20;\n"
732 | "width: 30;\n"
733 | "border-radius: 7px;\n"
734 | "padding: 10px;\n"
735 | "background-color: #040f13;\n"
736 | "}\n"
737 | "QPushButton:hover:!pressed\n"
738 | "{\n"
739 | "background-color: QLinearGradient( x1: 0, y1: 0,\n"
740 | " x2: 1, y2: 0, \n"
741 | " stop: 0 #c471f5, \n"
742 | " stop: 1 #fa71cd );\n"
743 | "}")
744 | self.clearButton.setObjectName("clearButton")
745 | self.actionButtons.addWidget(self.clearButton)
746 | spacerItem4 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
747 | self.actionButtons.addItem(spacerItem4)
748 | self.actionButtons.setStretch(1, 1)
749 | self.actionButtons.setStretch(2, 1)
750 | self.actionButtons.setStretch(3, 1)
751 | self.actionButtons.setStretch(4, 1)
752 | self.verticalLayout_4.addLayout(self.actionButtons)
753 | self.verticalLayout_5.addLayout(self.verticalLayout_4)
754 | self.horizontalLayout.addWidget(self.main_body)
755 | self.verticalLayout.addWidget(self.frame_2)
756 | MainWindow.setCentralWidget(self.centralwidget)
757 |
758 | self.retranslateUi(MainWindow)
759 | QtCore.QMetaObject.connectSlotsByName(MainWindow)
760 |
761 | def retranslateUi(self, MainWindow):
762 | _translate = QtCore.QCoreApplication.translate
763 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
764 | self.menu.setText(_translate("MainWindow", "Menu"))
765 | self.linkBar.setPlaceholderText(_translate("MainWindow", "Download from Twitter"))
766 | self.automaticButton.setText(_translate("MainWindow", "Automatic"))
767 | self.rectangleLabel.setText(_translate("MainWindow", "Rectangles"))
768 | self.combineOverLap.setText(_translate("MainWindow", "CombineOverlap"))
769 | self.combineNeighbors.setText(_translate("MainWindow", "CombineNeighbors"))
770 | self.rangeLabel.setText(_translate("MainWindow", "Range"))
771 | self.singlePtranslate.setText(_translate("MainWindow", "Retranslate current page"))
772 | self.manualButton.setText(_translate("MainWindow", "Manual"))
773 | self.label_2.setText(_translate("MainWindow", "Colors:"))
774 | self.Textcolor.setItemText(0, _translate("MainWindow", "Red"))
775 | self.Textcolor.setItemText(1, _translate("MainWindow", "Blue"))
776 | self.Textcolor.setItemText(2, _translate("MainWindow", "Green"))
777 | self.Textcolor.setItemText(3, _translate("MainWindow", "Black"))
778 | self.Textcolor.setItemText(4, _translate("MainWindow", "White"))
779 | self.label_3.setText(_translate("MainWindow", "Background Color:"))
780 | self.bGcolor.setItemText(0, _translate("MainWindow", "White"))
781 | self.bGcolor.setItemText(1, _translate("MainWindow", "Red"))
782 | self.bGcolor.setItemText(2, _translate("MainWindow", "Blue"))
783 | self.bGcolor.setItemText(3, _translate("MainWindow", "Green"))
784 | self.bGcolor.setItemText(4, _translate("MainWindow", "Black"))
785 | self.label_4.setText(_translate("MainWindow", "Font Size: 6"))
786 | self.removeRect.setText(_translate("MainWindow", "Remove rectangles"))
787 | self.sortButton.setText(_translate("MainWindow", "Sort pages by file name"))
788 | self.label.setText(_translate("MainWindow", "Translators:"))
789 | self.translateOptions.setItemText(0, _translate("MainWindow", "Bing"))
790 | self.translateOptions.setItemText(1, _translate("MainWindow", "Google"))
791 | self.translateOptions.setItemText(2, _translate("MainWindow", "DeepL"))
792 | self.label_5.setText(_translate("MainWindow", "From language:"))
793 | self.languages.setItemText(0, _translate("MainWindow", "Japanese"))
794 | self.languages.setItemText(1, _translate("MainWindow", "Korean"))
795 | self.languages.setItemText(2, _translate("MainWindow", "Chinese"))
796 | self.languages.setItemText(3, _translate("MainWindow", "Auto detect"))
797 | self.advanced.setText(_translate("MainWindow", "Advanced Option"))
798 | self.upload.setText(_translate("MainWindow", "Upload"))
799 | self.translate.setText(_translate("MainWindow", "Translate"))
800 | self.saveButton.setText(_translate("MainWindow", "Save"))
801 | self.clearButton.setText(_translate("MainWindow", "Clear"))
802 | import darkmode_rc
803 |
804 |
805 | if __name__ == "__main__":
806 | import sys
807 | app = QtWidgets.QApplication(sys.argv)
808 | MainWindow = QtWidgets.QMainWindow()
809 | ui = Ui_MainWindow()
810 | ui.setupUi(MainWindow)
811 | MainWindow.show()
812 | sys.exit(app.exec_())
813 |
--------------------------------------------------------------------------------