Skip to content

Instantly share code, notes, and snippets.

@htlin222
Last active February 23, 2026 18:25
Show Gist options
  • Select an option

  • Save htlin222/fda5fcea3726bb04b97913ca735bb99b to your computer and use it in GitHub Desktop.

Select an option

Save htlin222/fda5fcea3726bb04b97913ca735bb99b to your computer and use it in GitHub Desktop.
Generate a grid overlay image for Google Slides (720x405) for designers — 6x6 big grid, 16x8 small cells, 7px unit, with position labels and dashed guides
from PIL import Image, ImageDraw, ImageFont
# Scale factor
scale = 5
# Parameters (original units)
big_cols, big_rows = 6, 6
small_w, small_h = 16, 8
cell_px = 7 * scale
# Total size
width = big_cols * small_w * cell_px
height = big_rows * small_h * cell_px
# Add padding so border strokes aren't clipped
pad = 2 * scale
img = Image.new("RGB", (width + pad, height + pad), "white")
draw = ImageDraw.Draw(img)
# Draw column backgrounds (1 small cell padding on each side of each big block)
col_bg = "#E8E8E8"
big_step_x_px = small_w * cell_px
for i in range(big_cols):
x1 = i * big_step_x_px + cell_px # 1 cell padding from left
x2 = (i + 1) * big_step_x_px - cell_px # 1 cell padding from right
draw.rectangle([(x1, 0), (x2, height + pad)], fill=col_bg) # extend to full height incl pad
# Draw small grid lines (light gray)
for x in range(0, width + 1, cell_px):
draw.line([(x, 0), (x, height)], fill="#D0D0D0", width=3)
for y in range(0, height + 1, cell_px):
draw.line([(0, y), (width, y)], fill="#D0D0D0", width=3)
# Draw big grid lines (dark)
for x in range(0, width + 1, small_w * cell_px):
draw.line([(x, 0), (x, height)], fill="#AAAAAA", width=scale)
for y in range(0, height + 1, small_h * cell_px):
draw.line([(0, y), (width, y)], fill="#AAAAAA", width=scale)
# Place grid centered on scaled canvas
canvas_w, canvas_h = 720 * scale, 405 * scale
canvas = Image.new("RGB", (canvas_w, canvas_h), "white")
offset_x = (canvas_w - (width + pad)) // 2
offset_y = (canvas_h - (height + pad)) // 2
canvas.paste(img, (offset_x, offset_y))
# Extend column backgrounds to canvas top and bottom edges
cdraw_bg = ImageDraw.Draw(canvas)
for i in range(big_cols):
x1 = offset_x + i * small_w * cell_px + cell_px
x2 = offset_x + (i + 1) * small_w * cell_px - cell_px
# Top extension
cdraw_bg.rectangle([(x1, 0), (x2, offset_y)], fill=col_bg)
# Bottom extension
cdraw_bg.rectangle([(x1, offset_y + height + pad), (x2, canvas_h)], fill=col_bg)
# Extend big grid lines as dashes to canvas edges
cdraw = ImageDraw.Draw(canvas)
dash_len = 10
dash_gap = 8
dash_color = "#BBBBBB"
dash_w = 2
# Vertical dashes: top edge (0 to offset_y) and bottom edge (offset_y+height to canvas_h)
for i in range(big_cols + 1):
x = offset_x + i * small_w * cell_px
# Top dashes
y = 0
while y < offset_y:
y2 = min(y + dash_len, offset_y)
cdraw.line([(x, y), (x, y2)], fill=dash_color, width=dash_w)
y += dash_len + dash_gap
# Bottom dashes
y = offset_y + height + pad
while y < canvas_h:
y2 = min(y + dash_len, canvas_h)
cdraw.line([(x, y), (x, y2)], fill=dash_color, width=dash_w)
y += dash_len + dash_gap
# Horizontal dashes: left edge (0 to offset_x) and right edge (offset_x+width to canvas_w)
for i in range(big_rows + 1):
y = offset_y + i * small_h * cell_px
# Left dashes
x = 0
while x < offset_x:
x2 = min(x + dash_len, offset_x)
cdraw.line([(x, y), (x2, y)], fill=dash_color, width=dash_w)
x += dash_len + dash_gap
# Right dashes
x = offset_x + width + pad
while x < canvas_w:
x2 = min(x + dash_len, canvas_w)
cdraw.line([(x, y), (x2, y)], fill=dash_color, width=dash_w)
x += dash_len + dash_gap
# Label absolute positions (in original 720x405 coordinates)
try:
font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 7 * scale)
except:
font = ImageFont.load_default()
cdraw = ImageDraw.Draw(canvas)
label_color = "#999999"
margin = 2 * scale
# Original offsets for labeling
orig_offset_x = 23
orig_offset_y = 33
orig_step_x = small_w * 7 # 112
orig_step_y = small_h * 7 # 56
# X labels along the top
big_step_x = small_w * cell_px
for i in range(big_cols + 1):
abs_x = offset_x + i * big_step_x
orig_val = orig_offset_x + i * orig_step_x
cdraw.text((abs_x + margin, offset_y - 12 * scale + 20), str(orig_val), fill=label_color, font=font)
# Y labels along the left
big_step_y = small_h * cell_px
for i in range(big_rows + 1):
abs_y = offset_y + i * big_step_y
orig_val = orig_offset_y + i * orig_step_y
cdraw.text((margin + 30, abs_y + margin), str(orig_val), fill=label_color, font=font)
# X labels at bottom for column bilateral edges (left & right edge of each column background)
try:
edge_font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 5 * scale)
except:
edge_font = ImageFont.load_default()
edge_label_color = "#999999"
bottom_label_y = offset_y + height + pad + 8 * scale - 35 # below the grid, moved up 35px
for i in range(big_cols):
# Left edge of column background: i * big_step_x + cell_px (1 cell inset)
left_px = offset_x + i * big_step_x + cell_px
left_orig = orig_offset_x + i * orig_step_x + 7 # +7 = 1 cell in original coords
# Right edge of column background: (i+1) * big_step_x - cell_px
right_px = offset_x + (i + 1) * big_step_x - cell_px
right_orig = orig_offset_x + (i + 1) * orig_step_x - 7 # -7 = 1 cell in original coords
# Draw left edge label (right-aligned to the edge)
left_text = str(left_orig)
left_bbox = cdraw.textbbox((0, 0), left_text, font=edge_font)
left_tw = left_bbox[2] - left_bbox[0]
cdraw.text((left_px - left_tw // 2, bottom_label_y), left_text, fill=edge_label_color, font=edge_font)
# Draw right edge label (left-aligned to the edge)
right_text = str(right_orig)
right_bbox = cdraw.textbbox((0, 0), right_text, font=edge_font)
right_tw = right_bbox[2] - right_bbox[0]
cdraw.text((right_px - right_tw // 2, bottom_label_y), right_text, fill=edge_label_color, font=edge_font)
canvas.save("/private/tmp/grid.png")
print(f"Grid {width}x{height} on {canvas_w}x{canvas_h} canvas (5x scale, labels in original coords)")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment