diff --git a/plugins/game_reader_test/plugin.py b/plugins/game_reader_test/plugin.py index 8032d31..a4edee2 100644 --- a/plugins/game_reader_test/plugin.py +++ b/plugins/game_reader_test/plugin.py @@ -149,7 +149,10 @@ class GameReaderTestPlugin(BasePlugin): # Tab 1: Quick Test tabs.addTab(self._create_quick_test_tab(), "Quick Test") - # Tab 2: Region Test + # Tab 2: File Test (NEW) + tabs.addTab(self._create_file_test_tab(), "File Test") + + # Tab 3: Region Test tabs.addTab(self._create_region_test_tab(), "Region Test") # Tab 3: History @@ -270,6 +273,87 @@ class GameReaderTestPlugin(BasePlugin): layout.addStretch() return tab + def _create_file_test_tab(self): + """Create file-based OCR test tab for testing with saved screenshots.""" + tab = QWidget() + layout = QVBoxLayout(tab) + + # Info + info = QLabel("Test OCR on an image file (PNG, JPG, BMP)") + info.setStyleSheet("color: #888;") + layout.addWidget(info) + + # File selection + file_layout = QHBoxLayout() + + self.file_path_label = QLabel("No file selected") + self.file_path_label.setStyleSheet("color: #aaa; padding: 8px; background-color: #1a1f2e; border-radius: 4px;") + file_layout.addWidget(self.file_path_label, 1) + + browse_btn = QPushButton("Browse...") + browse_btn.setStyleSheet(""" + QPushButton { + background-color: #4ecdc4; + color: #141f23; + font-weight: bold; + padding: 8px 16px; + } + """) + browse_btn.clicked.connect(self._browse_image_file) + file_layout.addWidget(browse_btn) + + layout.addLayout(file_layout) + + # Backend selection + backend_layout = QHBoxLayout() + backend_layout.addWidget(QLabel("OCR Backend:")) + self.file_backend_combo = QComboBox() + self.file_backend_combo.addItems(["Auto (try all)", "EasyOCR", "Tesseract", "PaddleOCR"]) + backend_layout.addWidget(self.file_backend_combo) + backend_layout.addStretch() + layout.addLayout(backend_layout) + + # Test button + file_test_btn = QPushButton("▶ Run OCR on File") + file_test_btn.setStyleSheet(""" + QPushButton { + background-color: #ff8c42; + color: #141f23; + font-weight: bold; + padding: 12px; + font-size: 14px; + } + """) + file_test_btn.clicked.connect(self._run_file_test) + layout.addWidget(file_test_btn) + + # Results + results_group = QGroupBox("OCR Results") + results_layout = QVBoxLayout(results_group) + + self.file_results_text = QTextEdit() + self.file_results_text.setReadOnly(True) + self.file_results_text.setPlaceholderText("OCR results will appear here...") + self.file_results_text.setStyleSheet(""" + QTextEdit { + background-color: #0d1117; + color: #c9d1d9; + font-family: Consolas, monospace; + font-size: 12px; + } + """) + results_layout.addWidget(self.file_results_text) + + # Stats + self.file_stats_label = QLabel("File: - | Backend: - | Status: Waiting") + self.file_stats_label.setStyleSheet("color: #888;") + results_layout.addWidget(self.file_stats_label) + + layout.addWidget(results_group, 1) + + layout.addStretch() + return tab + def _create_region_test_tab(self): """Create region test tab.""" tab = QWidget() @@ -453,6 +537,107 @@ class GameReaderTestPlugin(BasePlugin): self.w_input.setValue(w) self.h_input.setValue(h) + def _browse_image_file(self): + """Browse for an image file to test OCR on.""" + file_path, _ = QFileDialog.getOpenFileName( + None, + "Select Image File", + "", + "Images (*.png *.jpg *.jpeg *.bmp *.tiff);;All Files (*)" + ) + if file_path: + self.selected_file_path = file_path + self.file_path_label.setText(Path(file_path).name) + self.file_path_label.setStyleSheet("color: #4ecdc4; padding: 8px; background-color: #1a1f2e; border-radius: 4px;") + + def _run_file_test(self): + """Run OCR on the selected image file.""" + if not hasattr(self, 'selected_file_path') or not self.selected_file_path: + QMessageBox.warning(None, "No File", "Please select an image file first!") + return + + backend_map = { + 0: 'auto', + 1: 'easyocr', + 2: 'tesseract', + 3: 'paddle' + } + backend = backend_map.get(self.file_backend_combo.currentIndex(), 'auto') + + self.file_results_text.setPlainText("Processing...") + self.file_stats_label.setText("Processing...") + + # Run OCR in a thread + from threading import Thread + + def process_file(): + try: + from PIL import Image + import time + + start_time = time.time() + + # Load image + image = Image.open(self.selected_file_path) + + # Try OCR backends + text = "" + backend_used = "none" + + if backend in ('auto', 'easyocr'): + try: + import easyocr + reader = easyocr.Reader(['en'], gpu=False, verbose=False) + ocr_result = reader.readtext( + image, + detail=0, + paragraph=True + ) + text = '\n'.join(ocr_result) + backend_used = "easyocr" + except Exception as e: + if backend == 'easyocr': + raise e + + if not text and backend in ('auto', 'tesseract'): + try: + import pytesseract + text = pytesseract.image_to_string(image) + backend_used = "tesseract" + except Exception as e: + if backend == 'tesseract': + raise e + + processing_time = time.time() - start_time + + # Update UI (thread-safe via Qt signals would be better, but this works for simple case) + from PyQt6.QtCore import QMetaObject, Qt, Q_ARG + QMetaObject.invokeMethod( + self.file_results_text, + "setPlainText", + Qt.ConnectionType.QueuedConnection, + Q_ARG(str, text if text else "No text detected") + ) + QMetaObject.invokeMethod( + self.file_stats_label, + "setText", + Qt.ConnectionType.QueuedConnection, + Q_ARG(str, f"File: {Path(self.selected_file_path).name} | Backend: {backend_used} | Time: {processing_time:.2f}s") + ) + + except Exception as e: + from PyQt6.QtCore import QMetaObject, Qt, Q_ARG + QMetaObject.invokeMethod( + self.file_results_text, + "setPlainText", + Qt.ConnectionType.QueuedConnection, + Q_ARG(str, f"Error: {str(e)}") + ) + + thread = Thread(target=process_file) + thread.daemon = True + thread.start() + def _run_quick_test(self): """Run quick OCR test.""" if self.ocr_thread and self.ocr_thread.isRunning():