|
1 | 1 | using Random
|
2 |
| -SansSerifFonts = ["Trebuchet MS", "Heiti TC", "微軟正黑體", "Arial Unicode MS", "Droid Fallback Sans", "sans-serif", "Helvetica", "Verdana", "Hei", |
3 |
| - "Arial", "Tahoma", "Microsoft Yahei", "Comic Sans MS", "Impact", "Segoe Script", "STHeiti", "Apple LiGothic", "MingLiU", "Ubuntu", "Segoe UI", |
4 |
| - "DejaVu Sans", "DejaVu Sans Mono", "Noto Sans CJK", "Arial Black", "Gadget", "cursive", "Charcoal", "Lucida Sans Unicode", "Lucida Grande", "Geneva"] |
5 |
| -SerifFonts = ["Baskerville", "Times New Roman", "Times", "華康儷金黑 Std", "華康儷宋 Std", "DFLiKingHeiStd-W8", "DFLiSongStd-W5", "DejaVu Serif", "SimSun", |
6 |
| - "Hiragino Mincho Pro", "LiSong Pro", "新細明體", "serif", "Georgia", "STSong", "FangSong", "KaiTi", "STKaiti", "Courier", "Courier New", "monospace", |
7 |
| - "Palatino Linotype", "Book Antiqua", "Palatino", "Lucida Console", "Monaco"] |
8 |
| -CandiFonts = union(SansSerifFonts, SerifFonts) |
9 |
| -CandiWeights = ["", " Regular", " Normal", " Medium", " Bold", " Light"] |
10 |
| -function checkfonts(fonts::AbstractVector) |
11 |
| - fname = tempname() |
12 |
| - r = Bool[] |
13 |
| - open(fname, "w") do f |
14 |
| - redirect_stderr(f) do |
15 |
| - p = position(f) |
16 |
| - for font in fonts |
17 |
| - err = false |
18 |
| - try |
19 |
| - rendertext("a", 1 + rand(), font=font) # 相同字体相同字号仅warning一次,故首次执行最准 |
20 |
| - catch |
21 |
| - err = true |
22 |
| - end |
23 |
| - # flush(f) # https://en.cppreference.com/w/cpp/io/c/fseek The standard C++ file streams guarantee both flushing and unshifting |
24 |
| - seekend(f) |
25 |
| - p2 = position(f) |
26 |
| - push!(r, (p2 == p) && !err) |
27 |
| - p = p2 |
| 2 | +import Fontconfig: list, Pattern |
| 3 | +using StopWords |
| 4 | + |
| 5 | +FontCandidates::Dict{String, Vector{String}} = Dict{String, Vector{String}}() |
| 6 | +WeightCandidates::Vector{String} = ["", " Regular", " Normal", " Medium", " Bold", " Light"] |
| 7 | + |
| 8 | +function listfonts(lang="") |
| 9 | + if !isempty(lang) |
| 10 | + ps = list(Pattern(lang=lang)) |
| 11 | + else |
| 12 | + ps = list(Pattern()) |
| 13 | + end |
| 14 | + names = String[] |
| 15 | + for p in ps |
| 16 | + name = string(p) |
| 17 | + b = findfirst("\"", name) |
| 18 | + e = findfirst(":", name) |
| 19 | + if b !== nothing && e !== nothing |
| 20 | + b = nextind(name, first(b), 1) |
| 21 | + e = prevind(name, first(e), 1) |
| 22 | + if 0 < b < e < length(name) |
| 23 | + push!(names, name[b:e]) |
28 | 24 | end
|
29 | 25 | end
|
30 | 26 | end
|
31 |
| - return r |
| 27 | + return names |
32 | 28 | end
|
33 |
| -checkfonts(f) = checkfonts([f]) |> only |
34 |
| -function filterfonts(;fonts=CandiFonts, weights=CandiWeights) |
35 |
| - candi = ["$f$w" for w in weights, f in fonts] |> vec |
36 |
| - candi[checkfonts(candi)] |
| 29 | +function reverse_dict(d) |
| 30 | + rd = Dict{String, Vector{String}}() |
| 31 | + for (k, v) in d |
| 32 | + get!(rd, v) do |
| 33 | + String[] |
| 34 | + end |
| 35 | + push!(rd[v], k) |
| 36 | + end |
| 37 | + return rd |
37 | 38 | end
|
38 |
| -if Sys.iswindows() |
39 |
| - AvailableFonts = [""] |
40 |
| -else |
41 |
| - AvailableFonts = filterfonts() |
42 |
| - push!(AvailableFonts, "") |
| 39 | +const id_part1 = reverse_dict(StopWords.part1_id) |
| 40 | +const mid_iid = reverse_dict(StopWords.iid_mid) |
| 41 | +function expandlangcode(c) |
| 42 | + c in StopWords.id_all || (c = get(StopWords.name_id, c, c)) |
| 43 | + c in StopWords.id_all || (c = get(StopWords.name_id, titlecase(c), c)) |
| 44 | + cs = [] |
| 45 | + for c1 in Iterators.flatten((get(mid_iid, c, []), [c])) |
| 46 | + for c2 in Iterators.flatten((get(id_part1, c1, []), [c1])) |
| 47 | + push!(cs, c2) |
| 48 | + end |
| 49 | + end |
| 50 | + cs |
| 51 | +end |
| 52 | +function fontsof(lang) |
| 53 | + union((listfonts(l) for l in expandlangcode(lang))...) |
| 54 | +end |
| 55 | +function getfonts(lang) |
| 56 | + if haskey(FontCandidates, lang) |
| 57 | + return FontCandidates[lang] |
| 58 | + else |
| 59 | + fs = fontsof(lang) |
| 60 | + push!(fs, "") |
| 61 | + FontCandidates[lang] = fs |
| 62 | + return fs |
| 63 | + end |
43 | 64 | end
|
44 | 65 |
|
45 | 66 | Schemes_colorbrewer = filter(s -> occursin("colorbrewer", colorschemes[s].category), collect(keys(colorschemes)))
|
@@ -333,11 +354,13 @@ function randomlinecolor(colors)
|
333 | 354 | linecolor
|
334 | 355 | end
|
335 | 356 | randomoutline() = rand((0, 0, 0, rand(2:10)))
|
336 |
| -function randomfonts() |
| 357 | +function randomfonts(lang="") |
337 | 358 | if rand() < 0.8
|
338 |
| - fonts = rand(AvailableFonts) |
| 359 | + fonts = rand(getfonts(lang)) |
| 360 | + fonts = fonts * rand(WeightCandidates) |
339 | 361 | else
|
340 |
| - fonts = rand(AvailableFonts, 2 + floor(Int, 2randexp())) |
| 362 | + fonts = rand(getfonts(lang), 2 + floor(Int, 2randexp())) |
| 363 | + fonts = [f * rand(WeightCandidates) for f in fonts] |
341 | 364 | rand() > 0.5 && (fonts = tuple(fonts...))
|
342 | 365 | end
|
343 | 366 | @show fonts
|
|
0 commit comments