├── 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 | image 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 | image 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 | image 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 | image 38 | 39 | After: 40 | 41 | image 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 | image 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 | --------------------------------------------------------------------------------