findfont.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright 2016 Florian Pigorsch. All rights reserved.
  2. //
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package findfont
  6. import (
  7. "fmt"
  8. "os"
  9. "os/user"
  10. "path/filepath"
  11. "strings"
  12. )
  13. // Find tries to locate the specified font file in the current directory as
  14. // well as in platform specific user and system font directories; if there is
  15. // no exact match, Find tries substring matching.
  16. func Find(fileName string) (filePath string, err error) {
  17. // check if fileName already points to a readable file
  18. if _, err := os.Stat(fileName); err == nil {
  19. return fileName, nil
  20. }
  21. // search in user and system directories
  22. return find(filepath.Base(fileName))
  23. }
  24. // List returns a list of all font files found on the system.
  25. func List() (filePaths []string) {
  26. pathList := []string{}
  27. walkF := func(path string, info os.FileInfo, err error) error {
  28. if err == nil {
  29. lowerPath := strings.ToLower(path)
  30. if !info.IsDir() && (strings.HasSuffix(lowerPath, ".ttf") || strings.HasSuffix(lowerPath, ".ttc") || strings.HasSuffix(lowerPath, ".otf")) {
  31. pathList = append(pathList, path)
  32. }
  33. }
  34. return nil
  35. }
  36. for _, dir := range getFontDirectories() {
  37. _ = filepath.Walk(dir, walkF)
  38. }
  39. return pathList
  40. }
  41. func stripExtension(fileName string) string {
  42. return strings.TrimSuffix(fileName, filepath.Ext(fileName))
  43. }
  44. func expandUser(path string) (expandedPath string) {
  45. if strings.HasPrefix(path, "~") {
  46. if u, err := user.Current(); err == nil {
  47. return strings.Replace(path, "~", u.HomeDir, -1)
  48. }
  49. }
  50. return path
  51. }
  52. func find(needle string) (filePath string, err error) {
  53. lowerNeedle := strings.ToLower(needle)
  54. lowerNeedleBase := stripExtension(lowerNeedle)
  55. match := ""
  56. partial := ""
  57. partialScore := -1
  58. walkF := func(path string, info os.FileInfo, err error) error {
  59. // we have already found a match -> nothing to do
  60. if match != "" {
  61. return nil
  62. }
  63. if err != nil {
  64. return nil
  65. }
  66. lowerPath := strings.ToLower(info.Name())
  67. if !info.IsDir() && (strings.HasSuffix(lowerPath, ".ttf") || strings.HasSuffix(lowerPath, ".ttc") || strings.HasSuffix(lowerPath, ".otf")) {
  68. lowerBase := stripExtension(lowerPath)
  69. if lowerPath == lowerNeedle {
  70. // exact match
  71. match = path
  72. } else if strings.Contains(lowerBase, lowerNeedleBase) {
  73. // partial match
  74. score := len(lowerBase) - len(lowerNeedle)
  75. if partialScore < 0 || score < partialScore {
  76. partialScore = score
  77. partial = path
  78. }
  79. }
  80. }
  81. return nil
  82. }
  83. for _, dir := range getFontDirectories() {
  84. _ = filepath.Walk(dir, walkF)
  85. if match != "" {
  86. return match, nil
  87. }
  88. }
  89. if partial != "" {
  90. return partial, nil
  91. }
  92. return "", fmt.Errorf("cannot find font '%s' in user or system directories", needle)
  93. }