From 2ed02e2a05d46fae82870271d4644d04d96c4df4 Mon Sep 17 00:00:00 2001 From: King of the all Cookies Date: Wed, 9 Apr 2025 21:33:52 +0300 Subject: [PATCH] Add files via upload --- PxPlus_IBM_VGA_8x16.ttf | Bin 0 -> 70640 bytes main.py | 227 ++++++++++++++++++++++++++++++++++++++++ presets.json | 11 ++ 3 files changed, 238 insertions(+) create mode 100644 PxPlus_IBM_VGA_8x16.ttf create mode 100644 main.py create mode 100644 presets.json diff --git a/PxPlus_IBM_VGA_8x16.ttf b/PxPlus_IBM_VGA_8x16.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3bf32d0f8034091b61f5c3b2a31771f8391a79a8 GIT binary patch literal 70640 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�w@BC!N?JR7}R)H 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 literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 0000000..14ab9fd --- /dev/null +++ b/main.py @@ -0,0 +1,227 @@ +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()) diff --git a/presets.json b/presets.json new file mode 100644 index 0000000..bd9ed26 --- /dev/null +++ b/presets.json @@ -0,0 +1,11 @@ +{ + "Presets": { + "Latin": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + "Latin+Specals": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()_+-={}[]|\\:;\"'<>,.?/~`", + "Cyrillic": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯаабвгдеёжзийклмнопрстуфхцчшщыэюя", + "Cyrillic+Specials": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯаабвгдеёжзийклмнопрстуфхцчшщыэюя!@#$%^&*()_+-={}[]|\\:;\"'<>,.?/~`", + "Latin+Cyrillic+Specials": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯаабвгдеёжзийклмнопрстуфхцчшщыэюя!@#$%^&*()_+-={}[]|\\:;\"'<>,.?/~`", + "Specials": "!@#$%^&*()_+-={}[]|\\:;\"'<>,.?/~`", + "All Characters": "under construction" + } +}