load(); } return self::$instance; } public function load(string $lang='en') { exec("fc-list -v", $out, $ret); $meta = []; $curr = []; foreach ($out as $line) { if (trim($line)) { $curr[] = $line; } else { $meta[] = $curr; $curr = []; } } foreach ($meta as $font) { $this->parseMeta($font, $lang); } } private function parseMeta(array $meta, string $lang) { $coll = []; foreach ($meta as $line) { if (9 != ord($line[0]) or strpos($line,": ") === false or ctype_digit($line[1])) { continue; } list ($key, $values) = explode(": ", substr($line, 1), 2); if (preg_match('/.+lang$/', $key)) { $base = substr($key, 0, -4); $baseMeta = $coll[$base]; $vals = str_getcsv($baseMeta, ' ', '"'); $langs = str_getcsv($values, ' ', '"'); $keep = []; while (count($langs)>0) { $l = $this->parseValue(array_shift($langs)); $v = $this->parseValue(array_shift($vals)); if ($l == $lang) { $keep[] = $v; } } $coll[$base] = $keep; } else { $coll[$key] = $values; } } foreach ($coll as $key=>$values) { if (is_array($values)) { continue; } $coll[$key] = $this->parseValue($values); } $langs = explode("|", $coll['lang']); if (!in_array($lang, $langs)) { return; } $this->fonts[] = (object)$coll; } private function parseValue($value) { if (substr($value, -3, 3) == "(s)") { $value = substr($value, 0, -3); if ($value && $value[0] == '"') { $value = substr($value, 1, strpos($value, '"', 2)-1); } } if (substr($value, -3, 3) == "(i)") { $value = intval($value); } return $value; } public function findFont($family, $styles='regular') { $styles = explode(" ",$styles); foreach ($this->fonts as $font) { $families = array_map("strtolower", (array)$font->family); if (!in_array(strtolower($family), $families)) { continue; } $fontStyles = array_map("strtolower", $font->style); foreach ($styles as $style) { if (!in_array($style, $fontStyles)) { continue(2); } } if (count(array_diff($fontStyles, $styles))>0) { continue; } return $font->file; } } }