Open cormullion opened 3 years ago
A workaround is to get these files separately, then convert to PNG, then run the script again (which I did to make the image above).
Perhaps one can iterate through all images in the folder, check the file
output and then use convert
to convert them? I don't know what tools Julia has for that, but bash should be able to do it in a few lines.
That's probably doable. With Images might be more portable, although file
is probably not available on Windows...
Or we could say: "Do you want your organization to be in our list? Make sure your icon's a PNG?" ... 😄
This version converts stray JPEG icons to PNG. I found that FileIO.query()
can look for "magic bytes"...
newer version below
This is awesome! Is it possible to align the names and either shorten the long ones or overflow to next line? Basically have everything fit to a grid?
Another nice feature would be the aspect ratio of the whole image - to make it fit on different types of screens.
Here's my screenshot from Finder. A bit of a hack, but they naturally have worked hard on placement...
I'll add aspect ratio tomorrow. And I think we can do better than Apple's crappy line breaking here...! 😃
Yes, we can certainly do better than Apple's line breaking. I almost wonder why they don't do that already.
Another version, with more attention to layout.
using Luxor, Images, FileIO
# script to make a grid of org logos
"""
get_nrows_ncols(N;
aspectratio=MathConstants.golden)
Return nrows, ncols for a list of length N to be arranged in
`aspectratio`.
"""
function get_nrows_ncols(N;
aspectratio=MathConstants.golden)
currentratio = a = b = N
for i in 1:N
a₁ = i
b₁ = convert(Int, ceil(N / a₁))
ratio = a₁/b₁
if abs(ratio - aspectratio) < abs(currentratio - aspectratio)
a = a₁
b = b₁
currentratio = ratio
end
end
return a, b
end
"""
textsplitcamelcasecentered(t, pos, width)
Draw text on a number of rows by splitting text at each uppercase letter.
"""
function textsplitcamelcasecentered(t, pos, width;
leading = 12)
# convert camelcase string
t1 = split(replace(t, r"([[:upper:]])" => s" \1"), ' ', keepempty=false)
t1 = join(t1, "\n")
tlines = textlines(t1, width)
y = pos.y
for i in 1:length(tlines)
wd = replace(tlines[i], " " => "")
te = textextents(wd)
text(wd, Point(pos.x, y), halign=:center)
y += leading
end
end
"""
buildimagedict!(orgnamelist, workingdir, imagedict)
Make a dictionary, use text list of organization names.
Download PNG images from github.
Store them in `workingdir`.
Fill and return dictionary `imagedict`.
"""
function buildimagedict!(orgnamelist, workingdir, imagedict)
orgnames = open(orgnamelist) do f
split(read(f, String))
end
sort!(orgnames, lt = (a, b) -> lowercase(a) < lowercase(b))
for o in orgnames
# download file if we haven't already
if !isfile(workingdir * o * ".png")
@info "downloading icon for $o"
download("https://github.com/" * o * ".png", workingdir * o * ".png")
end
end
iconlist = filter(f -> endswith(f, ".png"), readdir(workingdir))
for iconfile in iconlist
path = joinpath(workingdir, iconfile)
# add Cairo/Luxor image to dictionary
try
q = query(path)
if typeof(q) == File{DataFormat{:JPEG}}
@info " Converting $path to PNG..."
img = load(path)
save(path, img)
end
imagedict[iconfile] = readpng(path)
catch e
# will fail if github gives us a JPEG instead of a PNG
@warn "skipping $iconfile"
println("\t", e)
end
end
return imagedict
end
"""
draworgicon(imagedict, key)
Draw the icon at current origin. Since they might be transparent,
place on white background.
"""
function draworgicon(imagedict, key;
size=300)
@layer begin
sethue("white")
squircle(O, size/2, size/2, :fill, rt=0.1)
squircle(O, size/2, size/2, :clip, rt=0.1)
img = imagedict[key]
w, h = img.width, img.height
sf = max(w, h)
scale(size/sf * 0.95)
placeimage(img, O, centered=true, 1)
clipreset()
end
end
function main(fname, w, h;
orgnames = "/tmp/orgnames.txt",
workingdir = "/tmp/julia-org-logos/",
aspectratio = MathConstants.golden)
if !isdir(workingdir)
mkdir(workingdir)
end
# build the dictionary
imagedict = Dict{String, Any}()
buildimagedict!(orgnames, workingdir, imagedict)
# start the drawing
d = Drawing(w, h, fname)
origin()
background(0.1, 0.1, 0.2)
labelfontsize = 12
ncols, nrows = get_nrows_ncols(length(imagedict), aspectratio=aspectratio)
tiles = Tiler(w, h, nrows, ncols, margin=20)
@info "grid is $nrows rows by $ncols columns"
@info "to hold $(length(imagedict)) icons"
fontsize(labelfontsize)
for (n, k) in enumerate(sort(collect(keys(imagedict))))
@layer begin
translate(first(tiles[n]))
S = min(tiles.tileheight, tiles.tilewidth)/2
draworgicon(imagedict, k, size = S)
sethue("white")
txt = replace(k, ".png" => "")
txtpos = O + (0, tiles.tileheight/2 - labelfontsize)
textsplitcamelcasecentered(txt, txtpos, tiles.tilewidth, leading = 12)
end
end
finish()
return d
end
main("/tmp/julia-orgs-grid.svg", 1400, 1000, aspectratio=MathConstants.golden)
This Julia script builds a grid of organization logos. There are a few issues.
Running this the first time shows a few icons that are actually JPEGs, which Cairo/Luxor doesn't handle:
A workaround is to get these files separately, then convert to PNG, then run the script again (which I did to make the image above).