import sys import os import random import json from PyQt6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QLabel, QSpinBox, QComboBox, QColorDialog, QFileDialog, QGraphicsView, QGraphicsScene, QGraphicsTextItem, QGraphicsRectItem, QSlider, QGraphicsItem) from PyQt6.QtCore import Qt from PyQt6.QtGui import QColor, QFont, QImage, QPainter, QPixmap from PIL import Image, ImageDraw, ImageFont class FontConverter(QWidget): def __init__(self): super().__init__() # Default parameters self.default_cell_width = 16 self.default_cell_height = 16 self.default_text_color = QColor(255, 255, 255) self.default_bg_color = QColor(0, 0, 0) self.default_format = "TIFF" self.font_path = "PxPlus_IBM_VGA_8x16.ttf" # Ensure the font is available self.presets = self.load_presets() self.preview_char = random.choice(self.presets.get('Latin', '')) self.init_ui() def load_presets(self): try: with open('presets.json', 'r', encoding='utf-8') as f: data = json.load(f) return data.get('Presets', {}) except Exception as e: print(f"Failed to load presets: {e}") return {} def init_ui(self): self.setWindowTitle("Font Converter") self.setGeometry(100, 100, 600, 500) # Layouts main_layout = QVBoxLayout() settings_layout = QVBoxLayout() # Font selection self.font_select_button = QPushButton("Select Font") self.font_select_button.clicked.connect(self.select_font) self.font_label = QLabel(f"Selected Font: {self.font_path}") settings_layout.addWidget(self.font_label) settings_layout.addWidget(self.font_select_button) # Cell size controls settings_layout.addWidget(QLabel("Cell size")) self.cell_width_spin = QSpinBox() self.cell_width_spin.setValue(self.default_cell_width) self.cell_width_spin.valueChanged.connect(self.update_preview) self.cell_height_spin = QSpinBox() self.cell_height_spin.setValue(self.default_cell_height) self.cell_height_spin.valueChanged.connect(self.update_preview) settings_layout.addWidget(QLabel("Width")) settings_layout.addWidget(self.cell_width_spin) settings_layout.addWidget(QLabel("Height")) settings_layout.addWidget(self.cell_height_spin) # Color pickers settings_layout.addWidget(QLabel("Text color")) self.text_color_button = QPushButton("Select Text Color") self.text_color_button.clicked.connect(self.select_text_color) settings_layout.addWidget(self.text_color_button) settings_layout.addWidget(QLabel("Background color")) self.bg_color_button = QPushButton("Select Background Color") self.bg_color_button.clicked.connect(self.select_bg_color) settings_layout.addWidget(self.bg_color_button) # Offset controls settings_layout.addWidget(QLabel("Symbol offset")) self.offset_x_slider = QSlider(Qt.Orientation.Horizontal) self.offset_x_slider.setMinimum(0) self.offset_x_slider.setMaximum(64) self.offset_x_slider.setValue(0) self.offset_x_slider.valueChanged.connect(self.update_preview) self.offset_y_slider = QSlider(Qt.Orientation.Horizontal) self.offset_y_slider.setMinimum(0) self.offset_y_slider.setMaximum(64) self.offset_y_slider.setValue(0) self.offset_y_slider.valueChanged.connect(self.update_preview) settings_layout.addWidget(QLabel("Offset X")) settings_layout.addWidget(self.offset_x_slider) settings_layout.addWidget(QLabel("Offset Y")) settings_layout.addWidget(self.offset_y_slider) # Preset selection self.preset_combo = QComboBox() self.preset_combo.addItems(self.presets.keys()) self.preset_combo.currentTextChanged.connect(self.update_symbols_from_preset) settings_layout.addWidget(QLabel("Select Preset")) settings_layout.addWidget(self.preset_combo) # Symbol range input self.symbol_input = QLineEdit(self.preview_char) self.symbol_input.setFixedHeight(80) settings_layout.addWidget(self.symbol_input) # Format selection self.format_combo = QComboBox() self.format_combo.addItems(["TIFF", "PNG", "BMP"]) self.format_combo.setCurrentText(self.default_format) settings_layout.addWidget(QLabel("Image Format")) settings_layout.addWidget(self.format_combo) # Output folder input self.output_folder_input = QLineEdit() self.output_folder_button = QPushButton("Select Output Folder") self.output_folder_button.clicked.connect(self.select_output_folder) folder_layout = QHBoxLayout() folder_layout.addWidget(self.output_folder_input) folder_layout.addWidget(self.output_folder_button) settings_layout.addLayout(folder_layout) # Generate button self.generate_button = QPushButton("Generate Images") self.generate_button.clicked.connect(self.generate_images) settings_layout.addWidget(self.generate_button) # Preview self.preview_scene = QGraphicsScene() self.preview_view = QGraphicsView(self.preview_scene) settings_layout.addWidget(self.preview_view) main_layout.addLayout(settings_layout) self.setLayout(main_layout) self.update_preview() def update_preview(self): # Clear preview scene self.preview_scene.clear() # Get current parameters width = self.cell_width_spin.value() height = self.cell_height_spin.value() offset_x = self.offset_x_slider.value() offset_y = self.offset_y_slider.value() # Create background rectangle bg_color = self.default_bg_color self.preview_scene.addItem(QGraphicsRectItem(0, 0, width, height).setBrush(bg_color)) # Add preview character preview_text_item = QGraphicsTextItem(self.preview_char) preview_text_item.setPos(offset_x, offset_y) preview_text_item.setDefaultTextColor(self.default_text_color) preview_text_item.setFont(QFont(self.font_path, height - 2)) # Adjust font size self.preview_scene.addItem(preview_text_item) def update_symbols_from_preset(self, preset_name): # Update symbol input field based on selected preset symbols = self.presets.get(preset_name, "") self.symbol_input.setText(symbols) self.preview_char = random.choice(symbols) self.update_preview() def select_font(self): font, _ = QFileDialog.getOpenFileName(self, "Select Font", "", "Font Files (*.ttf *.otf)") if font: self.font_path = font self.font_label.setText(f"Selected Font: {font}") self.update_preview() def select_text_color(self): color = QColorDialog.getColor() if color.isValid(): self.default_text_color = color self.update_preview() def select_bg_color(self): color = QColorDialog.getColor() if color.isValid(): self.default_bg_color = color self.update_preview() def select_output_folder(self): folder = QFileDialog.getExistingDirectory(self, "Select Output Folder") if folder: self.output_folder_input.setText(folder) def generate_images(self): width = self.cell_width_spin.value() height = self.cell_height_spin.value() offset_x = self.offset_x_slider.value() offset_y = self.offset_y_slider.value() text_color = self.default_text_color bg_color = self.default_bg_color symbols = self.symbol_input.text() output_folder = self.output_folder_input.text() image_format = self.format_combo.currentText() if not os.path.exists(output_folder): print("Output folder does not exist!") return try: font = ImageFont.truetype(self.font_path, height - 2) except Exception as e: print(f"Failed to load font: {e}") return for char in symbols: if char.isspace(): continue img = Image.new("RGBA", (width, height), bg_color.getRgb()[:3]) draw = ImageDraw.Draw(img) draw.text((offset_x, offset_y), char, font=font, fill=text_color.getRgb()[:3]) safe_char = f"U+{ord(char):04X}" img.save(os.path.join(output_folder, f"{safe_char}.{image_format.lower()}"), format=image_format) print("Images successfully generated.") if __name__ == "__main__": app = QApplication(sys.argv) window = FontConverter() window.show() sys.exit(app.exec())