import sys import csv from PySide6.QtCore import Qt, QTimer, QObject, Signal, Slot from PySide6.QtWidgets import QGraphicsScene, QGraphicsRectItem, QGraphicsPixmapItem,QApplication, QGraphicsTextItem from PySide6.QtGui import QPainter, QImage, QColor, QPixmap, QFont, QFontDatabase import CustomCircleItem import re BG_WIDTH = 3508 BG_HEIGHT = 2480 HEAD_ICON_PREFIX = "resource/head_%d.png" X_OFFSET = 1700 Y_OFFSET = 650 CIRCLE_RADIUS = 617 CIRCLE_X_OFFSET = 750 def is_chinese(text): # Returns True if any character is Chinese return any('\u4e00' <= char <= '\u9fff' for char in text) def is_english(text): # Returns True if all characters are English letters (ignores spaces) return bool(re.fullmatch(r'[A-Za-z\s]+', text)) class ImageGenerator(QObject): finished = Signal() def __init__(self, parent=None): super().__init__(parent) self.scene = QGraphicsScene() self._timer = QTimer(self) self._timer.timeout.connect(self.generate_images) self.colors = self.read_csv("resource/colors.csv") print(f"Loaded colors: {self.colors}") # Add the font file (provide the correct path) self.customFont = self.read_font("resource/TaiwanPearl-SemiBold.ttf") def read_csv(self, path): colors = [] try: with open(path, newline='', encoding='utf-8') as csvfile: reader = csv.reader(csvfile) for row in reader: colors.append(row) if colors: colors.pop(0) # Remove header row if exists except Exception as e: print(f"Error reading {path}: {e}") return colors def read_font(self,path): try: font_id = QFontDatabase.addApplicationFont(path) if font_id != -1: families = QFontDatabase.applicationFontFamilies(font_id) print("Loaded font families:", families) family = families[1] if len(families) > 1 else families[0] customFont = QFont(family) customFont.setPixelSize(80) customFont.setLetterSpacing(QFont.AbsoluteSpacing,15) # Adjust word spacing if needed return customFont else: print("Failed to load font.") return QFont() # fallback to default font except Exception as e: print(f"Error loading font from {path}: {e}") return QFont() @Slot() def start(self): self._timer.start(1000) # Generate images every second @Slot() def stop(self): self._timer.stop() self.finished.emit() def scene_to_image(self, scene, filename): print(f"Saving scene to {filename}...") image = QImage(scene.sceneRect().size().toSize(), QImage.Format_ARGB32) image.fill(Qt.transparent) # Set 300 DPI dpi = 300 dots_per_meter = int(dpi / 0.0254) image.setDotsPerMeterX(dots_per_meter) image.setDotsPerMeterY(dots_per_meter) painter = QPainter(image) scene.render(painter) painter.end() image.save(f"generated_images/{filename}", "PNG") self.stop() @Slot() def generate_images(self, name_csv, out_filename): # Placeholder for image generation logic print("Generating images...1") # Group of rect for i, name in enumerate(name_csv): r =g =b = 0 for j, color in enumerate(self.colors): if color[0] == name[0]: print(f"Adding rect with color: {color}") r, g, b = map(int, color[1:4]) break _idx_x = i % 2 _idx_y = (i%6) // 2 if i % 6 == 0: # Example of adding a simple item to the scene bg_item = QGraphicsRectItem(0, 0, BG_WIDTH, BG_HEIGHT) bg_item.setBrush(Qt.white) self.scene.addItem(bg_item) print("Generating images...2") rect_item = QGraphicsRectItem(30+X_OFFSET*_idx_x, 30+(Y_OFFSET+20)*_idx_y, X_OFFSET, Y_OFFSET, parent= bg_item) rect_item.setPen(Qt.NoPen) #simple pixmap # smaple_item = QGraphicsPixmapItem(QPixmap("resource/sample.jpg"), rect_item) # smaple_item.setPos(rect_item.boundingRect().x()+100, rect_item.boundingRect().y()+25) #draw circle for j in range(2): circle_item = CustomCircleItem.CustomCircleItem(100+(CIRCLE_X_OFFSET*j), 25, CIRCLE_RADIUS, 600, QColor(r, g, b), is_circle=True,parent=rect_item) circle_item.setOpacity(1) #draw head icon head_icon_num = int(name[1]) if len(name) > 1 else 1 head_icon = QGraphicsPixmapItem(QPixmap(HEAD_ICON_PREFIX % head_icon_num), circle_item) head_icon.setPos(circle_item.boundingRect().x(), circle_item.boundingRect().y()) #name item name_item = QGraphicsTextItem() name_str = name[2 + j] if len(name) > 2 + j else "Unknown" if is_chinese(name_str): if len(name_str) == 2: self.customFont.setLetterSpacing(QFont.AbsoluteSpacing, 30) # Adjust word spacing if needed elif len(name_str) == 3: self.customFont.setLetterSpacing(QFont.AbsoluteSpacing, 15) elif len(name_str) == 4: self.customFont.setLetterSpacing(QFont.AbsoluteSpacing, 0) else: self.customFont.setLetterSpacing(QFont.AbsoluteSpacing, 0) name_item.setFont(self.customFont) name_item.setPlainText(name_str) name_item.setDefaultTextColor(QColor(0, 0, 0)) name_item.setPos((circle_item.boundingRect().x()+ circle_item.boundingRect().width()/2 - name_item.boundingRect().width()/2)+10, circle_item.boundingRect().y()+430) self.scene.addItem(name_item) if i > 0 and i % 6 == 5: # Save the current scene to an image file every 5 items self.scene_to_image(self.scene, f"{out_filename}_{i//6}.png") self.scene.clear() print("Image generated and added to scene.") if __name__ == "__main__": app = QApplication(sys.argv) generator = ImageGenerator() generator.finished.connect(app.quit) csv_file = "resource/sample.csv" out_filename = "generated_image" if len(sys.argv) > 2: csv_file = sys.argv[1] out_filename = sys.argv[2] print(f"Loading CSV file: {csv_file}, Output filename: {out_filename}") sample_data = generator.read_csv(csv_file) print(f"Sample data loaded: {sample_data}") generator.generate_images(sample_data, out_filename) #generator.start() # Run the application event loop sys.exit(0)