Skip to content

Instantly share code, notes, and snippets.

@joncombe
Created February 2, 2019 05:16
Show Gist options
  • Save joncombe/d4cf406fd3e56e8660e630085012b6b1 to your computer and use it in GitHub Desktop.
Save joncombe/d4cf406fd3e56e8660e630085012b6b1 to your computer and use it in GitHub Desktop.
A simple python script to generate a "rating indicator" stars PNG image and CSS
import math
import os
from PIL import Image, ImageDraw
"""
A very simple script to generate a row of star images which can be
used in a rating indicator (e.g. 4 out of 5 stars), and some css to
go with it..
Usage example:
<div class="rating rating-7"></div>
"rating-7" = 7 out of 10, but displayed as 3.5 stars out of 5
"""
size = 19
border_size = 0.3
fattiness = 0.45
bg_color = (255, 255, 255, 0)
selected_bg = (255, 204, 0, 255)
selected_fg = None
unselected_bg = (205, 200, 190, 255)
unselected_fg = (255, 255, 255, 255)
def get_point(center_x, center_y, radius, angle):
radians = math.radians(angle - 90)
x = center_x + radius * math.cos(radians)
y = center_y + radius * math.sin(radians)
return x, y
def draw_star(draw, center_x, center_y, outer_radius, inner_radius, color):
points = [
(outer_radius, 0),
(inner_radius, 36),
(outer_radius, 72),
(inner_radius, 108),
(outer_radius, 144),
(inner_radius, 180),
(outer_radius, 216),
(inner_radius, 252),
(outer_radius, 288),
(inner_radius, 324),
]
coords = []
for p in points:
coord = get_point(center_x, center_y, p[0], p[1])
coords.append(coord)
draw.polygon(coords, color)
def create_image(size, selected, fattiness, img_color, bg_color, fg_color=None, border_size=None):
# create a much larger size image
new_size = size * 11
im = Image.new('RGBA', (new_size, new_size), img_color)
draw = ImageDraw.Draw(im)
# draw background star
outer = new_size / 2
draw_star(draw, outer, outer * 1.08, outer * 1.08, outer * fattiness, bg_color)
# draw foreground star
if fg_color and fg_color != bg_color:
inner = outer * (1 - border_size)
draw_star(draw, outer, outer * 1.08, inner * 1.08, inner * fattiness, fg_color)
# reduce size back to normal size (to force anti-aliasing) and save
im.thumbnail((size, size))
im.save('selected.png' if selected else 'unselected.png', 'PNG')
def create_stars(size, bg_color):
# load these stars into memory
# why save and reload? because we chop one in half: a very unelegant solution but much easier this way
im = Image.new('RGBA', (size * 19, size), bg_color)
selected = Image.open('selected.png')
unselected = Image.open('unselected.png')
# add selected stars #1
for i in range(0, 5):
box = (i * size, 0, (i + 1) * size, size)
im.paste(selected, box)
# add unselected stars #1
for i in range(5, 10):
box = (i * size, 0, (i + 1) * size, size)
im.paste(unselected, box)
# add selected stars #2
for i in range(10, 14):
box = (i * size, 0, (i + 1) * size, size)
im.paste(selected, box)
# add unselected stars #2
for i in range(14, 19):
box = (i * size, 0, (i + 1) * size, size)
im.paste(unselected, box)
# draw the half star
box = (14 * size, 0, int(14.5 * size), size)
crop = (0, 0, int(size / 2), size)
im.paste(selected.crop(crop), box)
# save and tidy up
im.save('stars.png', 'PNG')
os.remove('selected.png')
os.remove('unselected.png')
def create_css(size):
css = """.rating {
background-image: url('stars.png');
display: inline-block;
height: %spx;
overflow: hidden;
width: %spx;
}
.rating > div {
float: left;
height: %spx;
width: %spx;
}
.rating-vote {
cursor: pointer;
}
// "full" stars
.rating-0 { background-position: -%spx 0; }
.rating-2 { background-position: -%spx 0; }
.rating-4 { background-position: -%spx 0; }
.rating-6 { background-position: -%spx 0; }
.rating-8 { background-position: -%spx 0; }
.rating-10 { background-position: 0px 0; }
// "half" stars
.rating-1 { background-position: -%spx 0; }
.rating-3 { background-position: -%spx 0; }
.rating-5 { background-position: -%spx 0; }
.rating-7 { background-position: -%spx 0; }
.rating-9 { background-position: -%spx 0; }
""" % (
size,
size * 5,
size,
size,
size * 5,
size * 4,
size * 3,
size * 2,
size * 1,
size * 14,
size * 13,
size * 12,
size * 11,
size * 10,
)
f = open('rating.css', 'w')
f.write(css)
# run
create_image(size, True, fattiness, bg_color, selected_bg)
create_image(size, False, fattiness, bg_color, unselected_bg, unselected_fg, border_size)
create_stars(size, bg_color)
create_css(size)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment