|
发表于 2023-10-3 08:40:06
|
显示全部楼层
声明:这里的优化专用于 geogebra 导出的 svg 优化,不适用其它 svg 文件,也不能重复应用于已经优化过的 geogebra 导出的 svg 。
更进一步,画各个点的代码改用 <circle> 语句,原来的 28k 文件现在进一步压缩为 2k,而整个图形(近乎)保持不变。
这里说的近乎保持不变(已知问题),主要有以下几点:
1)小数点精度这里始终保持 2 位;
2)不再区分自由点和非自由点,每个点始终用 blue 填充;
3) 某些点的位置及大小(font-size)发生微小变化。(bug,一般,暂时视作可忽略)
4)中文文本或 latex 文本内容可能显示会有些问题。(bug, 严重,暂时视作规避并待改进)
新代码如下(func main 不变就不贴出了)
- func sc(fname string) { input, err := ioutil.ReadFile(fname) content := string(input) prevx, prevy := 0.0, 0.0 // 这里 content 和 input 能保持一致,但后面对 content 进行 replace 之后,就不一致了 s := strings.Index(content, "viewBox=") i := s+1 k := 0 for k != 2 { if input[i] == ' ' { k++ } i++ } n := i for content[n] != ' ' { n++ } s1 := content[i:n] n++ i = n for content[n] != '"' { n++ } s2 := content[i:n] //fmt.Println(s1, s2) v1, _ := strconv.ParseFloat(string(s1), 32) v2, _ := strconv.ParseFloat(string(s2), 32) // fmt.Println(v1, v2) content = strings.Replace(content, "clipPath", "aaaaa", -1) content = strings.Replace(content, `stroke-linecap="round"`, "", -1) content = strings.Replace(content, `stroke-linejoin="round"`, "", -1) re, _ := regexp.Compile(` clip-path="[^"].*"`) content = re.ReplaceAllString(content, "") re, _ = regexp.Compile(`\.(\d\d)(\d+)`) content = re.ReplaceAllString(content, ".$1") dom, err := goquery.NewDocumentFromReader(strings.NewReader(content)) // 筛选含有transform属性的g元素并删除 // dom.Find(`g[transform]`).Each(func(i int, s *goquery.Selection) { // parent := s.Parent() // parent.Get(0).RemoveChild(s.Get(0)) // }) dom.Find(`image`).Each(func(i int, s *goquery.Selection) { parent := s.Parent() parent.Get(0).RemoveChild(s.Get(0)) }) // 似乎不支持 dom.Find(`clipPath`),故先人为改成 aaaaa dom.Find(`aaaaa`).Each(func(i int, s *goquery.Selection) { parent := s.Parent() parent.Get(0).RemoveChild(s.Get(0)) }) dom.Find(`path`).Each(func(i int, s *goquery.Selection) { parent := s.Parent() str, _ := parent.Html() if strings.Index(str, "<path d="M") >= 0 { dstr, _ := s.Attr("d") reg := regexp.MustCompile(`<path d="M ([\-0-9.]+) ([\-0-9.]+)`) p := reg.FindStringSubmatch(str) if len(p) > 1 { d1, _ := strconv.ParseFloat(string(p[1]), 32) d2, _ := strconv.ParseFloat(string(p[2]), 32) if d1 > v1 || d2 > v2 { //fmt.Println(d1, v1, d2, v2) parent.Get(0).RemoveChild(s.Get(0)) } else if strings.Index(dstr, "Q ") > 0 { reg := regexp.MustCompile(`<title>(.*)</title>.*\n.*<desc>(.*)</desc>`) p := reg.FindStringSubmatch(str) if len(p) > 0 { label := p[1] i := strings.Index(label, " ") if i >= 0 { label = label[i+1:] //fmt.Println("#" + p[1][:i] + "#") if p[1][:i] == "点" { // 若标签如 M_2 之类的,表示带下标的 $M_2$ 格式 if strings.Index(label, "_") < 0 { st := fmt.Sprintf(`<text x="%.2f" y="%.2f">%s</text>`, d1, d2, label) parent.SetHtml(st) //fmt.Println(p[1]) } } } else { st := fmt.Sprintf(`<text x="%.2f" y="%.2f">%s</text>`, d1, d2, p[2]) parent.SetHtml(st) } } } else if strings.Index(dstr, "C ") > 0 { // 将画点的代码改为用 <circle> 指令 reg := regexp.MustCompile(`<title>(.*)</title>.*\n.*<desc>(.*)</desc>`) p := reg.FindStringSubmatch(str) if len(p) > 0 { label := p[1] i := strings.Index(label, " ") if i >= 0 { label = label[i+1:] //fmt.Println("#" + p[1][:i] + "#") if p[1][:i] == "点" { if d1 == prevx && d2 == prevy { parent.Get(0).RemoveChild(s.Get(0)) } else { prevx, prevy = d1, d2 st := fmt.Sprintf(`<circle cx="%.2f" cy="%.2f" r="5" fill="blue"/> `, d1-3.0, d2) parent.SetHtml(st) } } } else { //这种情况需要进一步跟踪 // st := fmt.Sprintf(`<text x="%.2f" y="%.2f">%s</text>`, d1, d2, p[2]) // parent.SetHtml(st) } } } } } }) dom.Find(`html`).Each(func(i int, selection *goquery.Selection) { outstr, _ := selection.Html() ioutil.WriteFile(fname, []byte(outstr[19:len(outstr)-29]), 0666) })}
复制代码 |
|