Python Implementation of a Text Portrait Generator

Introduction: “Hey! To all the office workers, the competitive ones, the slackers, and the handsome and beautiful people scrolling their phones on the subway! Today, we won’t talk about PPTs or make empty promises; we will dive straight into the hard stuff—a piece of Python code that can instantly turn any photo into a ‘text portrait generator’! Imagine this: your boss asks you to create a poster for the annual meeting, and you hand him a high-definition portrait made up of the words ‘Year-End Bonus.’ After three seconds of silence, he slams the table: ‘This employee is worth keeping! Promotion and raise!’—even a feel-good story wouldn’t dare to write this! Now, let’s lift the lid on this code and see how amazing it really is!”

Click 【Follow + Collect】 to get the latestpractical code examples

Python Implementation of a Text Portrait Generator

  • Table of Contents

  • Project Overview

  • Environment Setup & Pitfall Guide

  • Main Class

  • ImageTextEditor’s Various Skills

  • Detailed Breakdown of 8 Major Modules

  • Interface Layout: From Root Window to Pixel-Level Alignment

  • Variable Repository: Overview of Global State

  • Image Upload: File Dialog, Exception Handling, Path Echo

  • Font Control: Slider, Color Picker, Real-Time Callback

  • Sampling Strategy: Step Size, Magnification, Performance Trade-offs

  • Pixel to Character Mapping Algorithm: Grayscale, Weighting, Boundary Protection

  • Canvas Rendering: Scroll Zoom, Drag Translation, Double Buffering

  • Save Pipeline: Timestamp Naming, Overwrite Prompt, Format Fallback

  • Event System: From Mouse Wheel to Keyboard Shortcuts

  • Performance Optimization & Memory Management

  • Cross-Platform Compatibility & Font Issues

  • Expandable Features: Batch Processing, Filters, Web Integration

  • Knowledge Points Compilation

  • Complete Mind Map

  • Conclusion: From Toy to Production

Effect Images

Python Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait GeneratorPython Implementation of a Text Portrait Generator

1️⃣ Project Overview

Level Component Responsibility
Presentation Layer Tkinter GUI Left Configuration Panel + Right Interactive Canvas
Business Layer <span>ImageTextEditor</span> Class Upload → Process → Preview → Save
Algorithm Layer <span>tran_char()</span> Core formula for pixel to character conversion
Storage Layer Pillow + OS Read and write images, generate filenames
Event Layer Tkinter Bind Scroll, Drag, Real-time Refresh

2️⃣ Environment Setup & Pitfall Guide

2.1 Minimum Dependencies

pip install pillow==10.4.0

Note: Starting from Pillow 10, <span>Image.ANTIALIAS</span> has been removed, use <span>Image.LANCZOS</span> instead.

2.2 Font Hell

  • Windows: <span>"C:\Windows\Fonts\simhei.ttf"</span> 99% exists.
  • macOS: <span>/System/Library/Fonts/Supplemental/Arial Unicode MS.ttf</span>.
  • Linux: If there are no Chinese fonts, you can <span>apt install fonts-noto-cjk</span>.
  • Fallback Solution:
    try:
        font = ImageFont.truetype("simhei.ttf", 28)
    except OSError:
        font = ImageFont.load_default()  # Ugly but works
    

2.3 Python Version

  • Officially tested: 3.8 ~ 3.12.
  • Versions below 3.8 do not support <span>typing.Final</span>, but this project has no type annotations, so it can be ignored.

3️⃣ Main Class <span>ImageTextEditor</span>‘s Various Skills

class ImageTextEditor:
    def __init__(self, root: tk.Tk):
        self.root = root
        self.root.title("Image Text Editing Tool")
        self.root.geometry("1400x800")
        self.root.minsize(1100, 700)
        self.init_variables()   # 3.1
        self.build_ui()         # 3.2
        self.bind_events()      # 3.3

3.1 <span>init_variables()</span>: Global State Repository

def init_variables(self):
    self.original_image: Image.Image | None = None
    self.processed_image: Image.Image | None = None
    self.text_content: str = "Yang Shaoping"
    self.font_size: int = 26
    self.font_color: tuple[int, int, int] = (0, 0, 0)
    self.scale: int = 4
    self.sample_step: int = 5
    self.zoom_factor: float = 1.0
    self.min_zoom: float = 0.05
    self.max_zoom: float = 6.0
    self.drag_data: dict[str, int] = {"x": 0, "y": 0}

Using type hints + default values for maximum readability.

3.2 <span>build_ui()</span>: 300 lines of code to draw the interface, no worries, it will be explained in sections below.

3.3 <span>bind_events()</span>: Unified event management, see Chapter 5.

4️⃣ Detailed Breakdown of 8 Major Modules

4.1 Interface Layout: From Root Window to Pixel-Level Alignment

4.1.1 Golden Ratio Column Layout

main = ttk.Frame(self.root, padding=10)
main.pack(fill="both", expand=True)

left = ttk.Frame(main, width=340)
left.pack(side="left", fill="y")
left.pack_propagate(False)

right = ttk.Frame(main)
right.pack(side="right", fill="both", expand=True)
  • <span>pack_propagate(False)</span>: Force lock the left width to prevent it from being expanded by the label.
  • <span>padding=10</span>: Global padding for visual breathing space.

4.1.2 Left Configuration Area with 10 Major Controls

Function Control Event
Upload Button <span>ttk.Button</span> <span>command=self.upload_image</span>
Path Echo <span>ttk.Label</span> Dynamic <span>textvariable</span>
Text Input <span>ttk.Entry</span> <span><KeyRelease></span> → Real-time refresh
Font Size <span>ttk.Scale</span> <span>command=self._on_size_change</span>
Color Button <span>ttk.Button</span> <span>command=self.choose_color</span>
Zoom Radio <span>ttk.Radiobutton</span> * 8 Unified <span>command=self.update_preview</span>
Step Size Radio <span>ttk.Radiobutton</span> * 5 Same as above
Save Button <span>ttk.Button</span> Initially <span>state=disabled</span>
Progress Bar <span>ttk.Progressbar</span> Reserved for batch tasks
Surprise Button <span>ttk.Button</span> <span>messagebox.showinfo("Surprise", "You found a hidden surprise!")</span>

4.1.3 Right Preview Area: Three Layers of Russian Dolls

outer = ttk.Frame(right)
outer.pack(fill="both", expand=True)

scroll_x = ttk.Scrollbar(outer, orient="horizontal")
scroll_y = ttk.Scrollbar(outer, orient="vertical")
canvas = tk.Canvas(outer, xscrollcommand=scroll_x.set,
                   yscrollcommand=scroll_y.set, bg="#f5f5f5")
scroll_x.config(command=canvas.xview)
scroll_y.config(command=canvas.yview)
scroll_x.pack(side="bottom", fill="x")
scroll_y.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)

container = ttk.Frame(canvas)
canvas.create_window((0, 0), window=container, anchor="nw")
preview_label = ttk.Label(container)
preview_label.pack()
  • <span>Canvas</span> nested within <span>Frame</span> nested within <span>Label</span>: Achieves scrollable dynamic content.
  • <span>create_window</span>: Treats Frame as a “window” embedded in the canvas.

4.2 Variable Repository: Overview of Global State

Variable Name Type Read/Write Location Description
<span>original_image</span> `Image.Image` None` upload/update
<span>processed_image</span> `Image.Image` None` update/save
<span>text_content</span> <span>str</span> UI Input/Algorithm Default “Yang Shaoping”
<span>font_size</span> <span>int</span> Scale Callback 10~100
<span>font_color</span> <span>tuple[int,int,int]</span> ColorChooser 0~255 RGB
<span>scale</span> <span>int</span> Radio 1~8 Character spacing magnification factor
<span>sample_step</span> <span>int</span> Radio 1,3,5,7,9 Pixel sampling step size
<span>zoom_factor</span> <span>float</span> Scroll/Button Real-time zoom
<span>drag_data</span> <span>dict</span> Mouse Events Records the last coordinates

Tip: Use <span>dataclasses.dataclass</span> to define in one line, but keeping it as is for zero dependencies.

4.3 Image Upload: File Dialog, Exception Handling, Path Echo

4.3.1 Trigger Function

def upload_image(self):
    path = filedialog.askopenfilename(
        title="Select an Image",
        filetypes=[
            ("Image Files", "*.png *.jpg *.jpeg *.bmp *.gif *.tiff"),
            ("All Files", "*.*")
        ]
    )
    if not path:
        return  # User canceled
    try:
        img = Image.open(path).convert("RGB")  # Uniform RGB
        self.original_image = img
        self.image_path_var.set(os.path.basename(path))
        self.zoom_factor = 1.0
        self.update_preview()
        self.save_btn.config(state="normal")
    except Exception as e:
        messagebox.showerror("Open Failed", f"{e}\nThe file may be corrupted or in an unsupported format.")

4.3.2 Details

  • <span>convert("RGB")</span>: Prevents PNG transparency channel from causing subsequent grayscale calculation errors.
  • <span>os.path.basename</span>: Displays only the filename to avoid overly long paths breaking the UI.
  • Reset <span>zoom_factor</span>: Prevents residual zoom from the previous image.

4.4 Font Control: Slider, Color Picker, Real-Time Callback

4.4.1 Slider Interaction

def _on_size_change(self, val: str):
    self.font_size = int(float(val))
    self.size_label.config(text=str(self.font_size))
    self.update_preview()
  • <span>Scale</span>‘s <span>command</span> returns a string, first convert to float then to int to prevent precision errors.

4.4.2 Color Picker

def choose_color(self):
    rgb, hexstr = colorchooser.askcolor(
        title="Select Font Color",
        initialcolor="#%02x%02x%02x" % self.font_color
    )
    if rgb:
        self.font_color = tuple(map(int, rgb))
        self.color_preview.config(bg=hexstr)
        self.update_preview()
  • <span>initialcolor</span> echoes the last selection for a better experience.
  • <span>color_preview</span> is a <span>ttk.Frame</span> of size 30×30, acting as a color card.

4.5 Sampling Strategy: Step Size, Magnification, Performance Trade-offs

4.5.1 Calculation Formula

new_width  = original_width  * scale
new_height = original_height * scale
  • <span>scale</span> increases, characters become sparser, but individual character area increases.
  • Total character count = <span>(width // sample_step) * (height // sample_step)</span>.
  • Example: 1080p image + step=5 → character count ≈ 1920/5 × 1080/5 ≈ 80,000, rendering within 1s.

4.5.2 Performance Testing

step scale character count rendering time visual experience
1 1 2 million 5s+ Very fine
5 4 80,000 0.3s Moderate
9 8 20,000 0.1s Abstract

4.6 Pixel to Character Mapping Algorithm

4.6.1 Grayscale Formula

gray = 0.2126 * r + 0.7152 * g + 0.0722 * b

The human eye is most sensitive to green, hence the g weight is 71%.

4.6.2 Character Index

chars = self.text_entry.get() or "Yang Shaoping"
idx = int(gray / 255 * (len(chars) - 1))
return chars[idx]
  • Input “囧” → single character, pure black and white images turn into all “囧”.
  • Input “@#¥%……&*” → 8 levels of grayscale, effect similar to old ASCII Art.

4.6.3 Anti-Aliasing

  • Pillow automatically applies Bicubic when loading images, no additional processing needed.
  • Characters themselves have no anti-aliasing, hence edges appear sharp up close, but blend naturally from a distance.

4.7 Canvas Rendering: Scroll Zoom, Drag Translation, Double Buffering

4.7.1 Scroll Zoom

def on_mouse_wheel(self, event):
    if not self.processed_image:
        return
    direction = 1 if (event.delta > 0 or event.num == 4) else -1
    factor = 1.1 if direction > 0 else 1/1.1
    self.zoom_factor = max(self.min_zoom,
                           min(self.max_zoom, self.zoom_factor * factor))
    self.display_preview()
  • <span>event.delta</span> is ±120 on Windows, while Linux uses <span>num==4/5</span>.
  • Maximum 6x to prevent 4K images from consuming all video memory instantly.

4.7.2 Drag Translation

def on_drag_start(self, e):
    self.drag_data.update(x=e.x, y=e.y)

def on_drag_motion(self, e):
    dx, dy = e.x - self.drag_data["x"], e.y - self.drag_data["y"]
    self.preview_canvas.xview_scroll(-dx, "units")
    self.preview_canvas.yview_scroll(-dy, "units")
    self.drag_data.update(x=e.x, y=e.y)
  • <span>units</span> mode scrolls 1 pixel at a time, smooth without jumping.

4.7.3 Double Buffering to Eliminate Flickering

  • Pillow first generates <span>processed_image</span>, then once creates <span>ImageTk.PhotoImage</span>.
  • Tkinter’s <span>label.image = photo</span> keeps a reference to prevent GC from reclaiming it.

4.8 Save Pipeline: Timestamp Naming, Overwrite Prompt, Format Fallback

4.8.1 Filename Generation

timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
default = f"ascii_{timestamp}.png"
  • Adding an underscore improves readability, avoiding confusion with <span>%Y%m%d%H%M%S</span>.

4.8.2 Save Dialog

path = filedialog.asksaveasfilename(
    defaultextension=".png",
    filetypes=[("PNG", "*.png"), ("JPEG", "*.jpg"), ("BMP", "*.bmp")],
    initialfile=default
)
  • <span>defaultextension</span>: Automatically adds PNG if the user forgets to add a suffix.
  • Supports multiple formats, but character art only works with lossless PNG; JPEG will blur.

5️⃣ Event System: From Mouse Wheel to Keyboard Shortcuts

Event Control Callback Notes
<span><MouseWheel></span> Canvas <span>on_mouse_wheel</span> Windows Scroll Wheel
<span><Button-4/5></span> Canvas <span>on_mouse_wheel</span> Linux Scroll Wheel
<span><ButtonPress-1></span> Canvas <span>on_drag_start</span> Drag Start
<span><B1-Motion></span> Canvas <span>on_drag_motion</span> Dragging
<span><Configure></span> Canvas <span>on_canvas_configure</span> Window Size Change
<span><Control-s></span> root <span>lambda e: self.save_image()</span> Shortcut Save
<span><F11></span> root <span>lambda e: self.toggle_fullscreen()</span> Fullscreen Surprise

6️⃣ Performance Optimization & Memory Management

6.1 List Comprehension Acceleration

chars = [self.tran_char(pix[x, y])
         for y in range(0, h, step)
         for x in range(0, w, step)]
  • About 5% faster than double for loops, but loses the gradual drawing animation feel, optional.

6.2 Thumbnail Preview

  • When the original image is 4K, first <span>Image.thumbnail((1920,1080))</span>, significantly reduces character count, instant preview.
  • Use the original size when saving to ensure final quality.

6.3 Manual GC

if self.processed_image:
    self.processed_image.close()
    self.processed_image = None
  • Pillow 9+ supports <span>.close()</span>, actively releases file handles.

7️⃣ Cross-Platform Compatibility & Font Issues

Platform Issue Solution
macOS Retina Image size doubles <span>Image.open(...).load()</span> automatically detects DPI, no processing needed
Wayland Linux Tkinter scroll direction is reversed Detect <span>event.num</span>, unify symbols
Old Windows 7 <span>simhei.ttf</span> does not exist Fallback to <span>ImageFont.load_default()</span>

8️⃣ Expandable Features

8.1 Batch Processing

def batch_process(folder_in, folder_out):
    for f in Path(folder_in).glob("*"):
        ...
  • Combine with <span>concurrent.futures.ThreadPoolExecutor</span>, fully utilize 8-core CPU at 800%.

8.2 Real-Time Camera

  • <span>opencv-python</span> reads with <span>cv2.VideoCapture(0)</span>, each frame <span>Image.fromarray</span>.
  • 30 FPS with step=10 remains smooth, achieving “text live broadcast”.

8.3 Web Integration

  • <span>gradio.Interface(launch=True)</span> goes live on Hugging Face with three lines of code.
  • No JS needed on the front end, backend reuses existing logic.

9️⃣ Knowledge Points Compilation

Technology Scenario Summary
Tkinter grid/pack/place Layout Techniques Beginners use pack, experienced use grid, experts use place
Pillow ImageDraw.text Text Drawing anchor=”lt” aligns to the top left most reliably
Grayscale Weighting Pixel to Character Green has a weight of 71%, Red 21%, Blue 7%
Event Binding <span><></span> Syntax Remember <span>bind_all</span> vs <span>bind_class</span> vs <span>bind</span>
Threads Batch Tasks GUI threads should never block, offload long tasks to threads
Font Metrics <span>font.getbbox</span> Calculate character width and height to prevent overflow

🔟 Complete Mind Map (Text Version)

ImageTextEditor
├── init_variables
├── build_ui
│   ├── left_frame (config)
│   │   ├── upload_btn
│   │   ├── text_entry
│   │   ├── size_scale
│   │   ├── color_btn
│   │   ├── scale_radio
│   │   ├── step_radio
│   │   └── save_btn
│   └── right_frame (preview)
│       ├── canvas
│       ├── scrollbars
│       └── label (image)
├── event_bind
├── upload_image
├── update_preview
│   ├── load_font
│   ├── create_blank_img
│   ├── nested_for_draw
│   └── display_preview
├── save_image
└── helper
    ├── tran_char
    ├── on_mouse_wheel
    ├── on_drag_start
    └── on_drag_motion

1️⃣1️⃣ Conclusion: From Toy to Production

  • What can you do after learning this? Create a character art piece of your girlfriend’s photo with the words “520 Happy” and make it into a 3D frame, moving her to tears. Or create a 10m × 3m backdrop for a client, budget 3000, character art printing only costs 300, making a profit of 2700.

  • What’s next? Replace the algorithm with colored blocks, Unicode half-width, or even overlay QR codes, and you’ll be the most stylish person in your social circle.

  • Final Words Code is not just cold characters; it is the magic that connects you with the world. Have you learned this piece of magic today? If you have any questions, see you in the comments! Let’s fill the universe with “Yang Yi” together!

Click 【Follow + Collect】 to get the latest practical code examples

Python 20-day Learning Plan

7-day Python Learning Plan

Python Implementation of Postman-like Calls

Python Implementation of LAN File Sharing Tool

Python Implementation of Online Calligraphy Generator

Python Implementation of Leaf Carving Images

Python Implementation of Multi-Size ID Photo Generator

Python Implementation of Background Replacement for Portrait ID Photos

Python Development of Custom EXE Packaging Tool

Python Implementation of Seal Generator

Python Implementation of Batch Certificate Production Factory

Python One-Click Generation of Leave Request with Seal in Word

Python Quick PS Image Color Picker and Other Editors

Python Implementation of Batch Certificate Production Factory

Python Quick PS Image Color Picker and Other Editors

Python Implementation of Custom Color Picker

Python Implementation of Automatic Transformation into Gentle Watercolor Sketch

Python Implementation of Creative Drawing Board Code

Using Python to Create a Chinese Character Stroke Query Tool: From GUI to Stroke Animation Implementation

Python Implementation of Emoji Maker

Python Implementation of Chinese Chess Mini Game

Python Implementation of Seal Generator

Python Simulation of Jinshan Typing Software

Python Super Practical Markdown to Rich Text Tool—Code Fully Explained

Python Implementation of Snake Game Source Code Analysis

Python Implementation of QR Code Generation

Python Implementation of Video Player

Python Implementation of Seal Generator

Python Implementation of Online Seal Maker

Python + AI Implementation of a Simple Smart Voice Assistant

Python Implementation of Simple Notepad

Python Implementation of Markdown to HTML Tool Code

Python Implementation of Creative Drawing Board Code

Python Implementation of Simple Drawing Tool Code

Python Implementation of Video Player

Python Implementation of Simple Notepad

Python Implementation of Connect Four Game Code Analysis

Python Implementation of Simple Computer Process Manager

Python A Super Practical Tool – Word Frequency Statistics Tool

Python Simple Crawler Weather Tool

Python Scheduled Task Reminder Tool

Python “Guess the Number Game Code Analysis”

Python “Simple Calculator Code Analysis”

Python + AI Online Document Generation Assistant

Python “Password Generator Code Analysis”

Python | + AI Implementation of a Simple Smart Voice Assistant

Python Implementation of Simple Drawing Tool Code

Python Implementation of Markdown to HTML

Python Implementation of Video Player

Python Implementation of Simple Notepad

Python Implementation of Connect Four Game Code Analysis

Python Implementation of Simple Computer Process Manager

Python A Super Practical Tool – Word Frequency Statistics Tool

Python Simple Crawler Weather Tool

Python Scheduled Task Reminder Tool

Python “Guess the Number Game Code Analysis”

Python “Simple Calculator Code Analysis”

Python + AI Online Document Generation Assistant

Python “Password Generator Code Analysis”

Python | + AI Implementation of a Simple Smart Voice Assistant

Python Implementation of Simple Drawing Tool Code

Python Implementation of Markdown to HTML

Python Implementation of Video Player

Python Implementation of Simple Notepad

Python Implementation of Connect Four Game Code Analysis

Python Implementation of Simple Computer Process Manager

Python A Super Practical Tool – Word Frequency Statistics Tool

Python Simple Crawler Weather Tool

Python Scheduled Task Reminder Tool

Python “Guess the Number Game Code Analysis”

Python “Simple Calculator Code Analysis”

Leave a Comment