-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate-og-images.py
More file actions
232 lines (199 loc) · 9.7 KB
/
generate-og-images.py
File metadata and controls
232 lines (199 loc) · 9.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#!/usr/bin/env python3
"""Generate Open Graph images for DevToolbox pages."""
from PIL import Image, ImageDraw, ImageFont
import os
OUTPUT_DIR = "/var/www/web-ceo/og"
os.makedirs(OUTPUT_DIR, exist_ok=True)
# OG image dimensions (1200x630 is the standard)
WIDTH = 1200
HEIGHT = 630
# Colors matching the dark theme
BG_COLOR = (15, 17, 23) # #0f1117
SURFACE = (26, 29, 39) # #1a1d27
PRIMARY = (59, 130, 246) # #3b82f6
ACCENT = (16, 185, 129) # #10b981
TEXT = (228, 228, 231) # #e4e4e7
MUTED = (156, 163, 175) # #9ca3af
BORDER = (42, 46, 58) # #2a2e3a
def get_font(size):
"""Get a font, falling back to default."""
font_paths = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
]
for path in font_paths:
if os.path.exists(path):
return ImageFont.truetype(path, size)
return ImageFont.load_default()
def get_regular_font(size):
"""Get a regular weight font."""
font_paths = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
]
for path in font_paths:
if os.path.exists(path):
return ImageFont.truetype(path, size)
return ImageFont.load_default()
def get_mono_font(size):
"""Get a monospace font."""
font_paths = [
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
]
for path in font_paths:
if os.path.exists(path):
return ImageFont.truetype(path, size)
return ImageFont.load_default()
def create_og_image(title, subtitle, category, filename):
"""Create a branded OG image."""
img = Image.new('RGB', (WIDTH, HEIGHT), BG_COLOR)
draw = ImageDraw.Draw(img)
# Draw gradient-like accent bar at top
for i in range(6):
alpha = 1.0 - (i / 6)
color = tuple(int(c * alpha + BG_COLOR[j] * (1 - alpha)) for j, c in enumerate(PRIMARY))
draw.rectangle([0, i, WIDTH, i + 1], fill=color)
# Draw border rectangle
draw.rectangle([40, 40, WIDTH - 40, HEIGHT - 40], outline=BORDER, width=2)
# Draw inner surface
draw.rectangle([42, 42, WIDTH - 42, HEIGHT - 42], fill=SURFACE)
# Logo area
mono_font = get_mono_font(24)
draw.rounded_rectangle([70, 70, 130, 105], radius=4, fill=PRIMARY)
draw.text((78, 72), "{ }", fill=(255, 255, 255), font=mono_font)
brand_font = get_font(28)
draw.text((145, 72), "DevToolbox", fill=TEXT, font=brand_font)
# Category badge
if category:
cat_font = get_regular_font(18)
bbox = draw.textbbox((0, 0), category, font=cat_font)
cat_w = bbox[2] - bbox[0] + 24
cat_x = WIDTH - 42 - cat_w - 30
draw.rounded_rectangle([cat_x, 70, cat_x + cat_w, 100], radius=12, fill=PRIMARY)
draw.text((cat_x + 12, 73), category, fill=(255, 255, 255), font=cat_font)
# Main title - wrap if needed
title_font = get_font(48)
# Simple word wrap
words = title.split()
lines = []
current_line = ""
for word in words:
test = current_line + " " + word if current_line else word
bbox = draw.textbbox((0, 0), test, font=title_font)
if bbox[2] - bbox[0] > WIDTH - 180:
if current_line:
lines.append(current_line)
current_line = word
else:
current_line = test
if current_line:
lines.append(current_line)
y = 180
for line in lines[:3]: # Max 3 lines
draw.text((70, y), line, fill=TEXT, font=title_font)
y += 60
# Subtitle
if subtitle:
sub_font = get_regular_font(24)
draw.text((70, y + 20), subtitle, fill=MUTED, font=sub_font)
# Bottom accent line
draw.rectangle([42, HEIGHT - 80, WIDTH - 42, HEIGHT - 78], fill=PRIMARY)
# Bottom text
bottom_font = get_regular_font(18)
draw.text((70, HEIGHT - 68), "Free • Private • No Signup", fill=MUTED, font=bottom_font)
draw.text((WIDTH - 280, HEIGHT - 68), "devtoolbox.dev", fill=PRIMARY, font=bottom_font)
img.save(os.path.join(OUTPUT_DIR, filename), "PNG", optimize=True)
def main():
print("Generating OG images...")
# Default/homepage OG image
create_og_image(
"Developer Tools That Just Work",
"38 free tools, 14 cheat sheets, 9 blog posts",
"",
"default.png"
)
print(" default.png")
# Tool pages
tools = {
"json-formatter": ("JSON Formatter & Validator", "Format, validate, and beautify JSON data"),
"base64": ("Base64 Encoder / Decoder", "Encode and decode Base64 data"),
"regex-tester": ("Regex Tester", "Test regular expressions in real-time"),
"sql-formatter": ("SQL Formatter", "Format and beautify SQL queries"),
"css-gradient": ("CSS Gradient Generator", "Create beautiful gradients visually"),
"json-path-finder": ("JSON Path Finder", "Find and extract JSON paths visually"),
"image-to-base64": ("Image to Base64 Encoder", "Convert images to data URIs"),
"html-beautifier": ("HTML Beautifier", "Format and indent HTML code"),
"js-minifier": ("JavaScript Minifier", "Minify and compress JavaScript code"),
"yaml-validator": ("YAML Validator", "Validate and format YAML documents"),
"jwt-decoder": ("JWT Decoder", "Decode and inspect JSON Web Tokens"),
"hash-generator": ("Hash Generator", "Generate MD5, SHA-1, SHA-256 hashes"),
"color-picker": ("Color Picker & Converter", "Pick colors and convert formats"),
"diff-checker": ("Diff Checker", "Compare two texts side by side"),
"uuid-generator": ("UUID Generator", "Generate random UUIDs/GUIDs"),
"qr-code-generator": ("QR Code Generator", "Generate QR codes from text"),
"password-generator": ("Password Generator", "Generate secure passwords"),
"timestamp": ("Unix Timestamp Converter", "Convert timestamps and dates"),
"cron-parser": ("Cron Expression Parser", "Parse and explain cron schedules"),
"url-encode": ("URL Encoder / Decoder", "Encode and decode URLs"),
"css-minifier": ("CSS Minifier", "Minify and compress CSS code"),
"markdown-preview": ("Markdown Preview", "Preview Markdown with live rendering"),
"html-entity": ("HTML Entity Encoder", "Encode and decode HTML entities"),
"json-to-csv": ("JSON to CSV Converter", "Convert JSON data to CSV"),
"json-schema-validator": ("JSON Schema Validator", "Validate JSON against schemas"),
"number-base-converter": ("Number Base Converter", "Convert binary, octal, hex"),
"ip-lookup": ("IP Address Lookup", "Look up IP information"),
"text-case-converter": ("Text Case Converter", "Convert text between cases"),
"lorem-ipsum": ("Lorem Ipsum Generator", "Generate placeholder text"),
"http-tester": ("HTTP Request Tester", "Send HTTP requests like a mini Postman"),
"code-screenshot": ("Code Screenshot Generator", "Beautiful code screenshots with themes"),
"ascii-art": ("ASCII Art Text Generator", "Turn text into ASCII art with FIGlet fonts"),
"json-diff": ("JSON Diff & Compare", "Deep compare two JSON objects"),
"regex-debugger": ("Regex Debugger & Visualizer", "Debug regex with match highlighting"),
"box-shadow": ("CSS Box Shadow Generator", "Visual box-shadow editor with presets"),
"markdown-table": ("Markdown Table Generator", "Create Markdown tables visually"),
"jwt-generator": ("JWT Generator", "Create and sign JSON Web Tokens"),
"chmod-calculator": ("Chmod Calculator", "Calculate Linux file permissions"),
}
for slug, (title, subtitle) in tools.items():
create_og_image(title, subtitle, "TOOL", f"tool-{slug}.png")
print(f" tool-{slug}.png")
# Cheatsheet pages
cheatsheets = {
"http-status-codes": "HTTP Status Codes",
"git-commands": "Git Commands",
"css-flexbox": "CSS Flexbox",
"css-grid": "CSS Grid",
"docker-commands": "Docker Commands",
"sql-basics": "SQL Basics",
"bash-shortcuts": "Bash Shortcuts",
"vim-shortcuts": "Vim Shortcuts",
"linux-permissions": "Linux Permissions",
"python-string-methods": "Python String Methods",
"javascript-array-methods": "JavaScript Array Methods",
"kubernetes-commands": "Kubernetes Commands",
"typescript-types": "TypeScript Types",
"react-hooks": "React Hooks",
}
for slug, title in cheatsheets.items():
create_og_image(f"{title} Cheat Sheet", "Quick reference for developers", "CHEAT SHEET", f"cs-{slug}.png")
print(f" cs-{slug}.png")
# Blog posts
blogs = {
"json-api-debugging-tips": "10 JSON API Debugging Tips",
"regex-guide-for-beginners": "Regex Guide for Beginners",
"http-status-codes-explained": "HTTP Status Codes Explained",
"cron-job-schedule-guide": "Cron Job Scheduling Guide",
"css-performance-optimization": "CSS Performance Optimization",
"git-commands-every-developer-should-know": "25 Git Commands You Should Know",
"javascript-array-methods-complete-guide": "JavaScript Array Methods Guide",
"docker-containers-beginners-guide": "Docker Containers for Beginners",
"typescript-tips-and-tricks": "15 TypeScript Tips and Tricks",
}
for slug, title in blogs.items():
create_og_image(title, "Developer tutorial and guide", "BLOG", f"blog-{slug}.png")
print(f" blog-{slug}.png")
print(f"\nDone! Generated {len(tools) + len(cheatsheets) + len(blogs) + 1} OG images in {OUTPUT_DIR}")
if __name__ == "__main__":
main()