func NewSDFFont3(fontPath string, size float64, dpi int, readonly bool, firstRune, lastRune rune, sdfSize float64, scanRange int) (*Font, error) { fontBytes, err := ioutil.ReadFile(fontPath) if err != nil { return nil, err } font, err := freetype.ParseFont(fontBytes) if err != nil { return nil, err } fontBytes = nil c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(font) c.SetFontSize(sdfSize) c.SetSrc(image.White) ratio := sdfSize / size text := "" for i := firstRune; i < lastRune+1; i++ { text += string(i) } rects := make([]image.Rectangle, 0) LetterArray := make(map[rune]*LetterInfo) for _, r := range text { index := font.Index(r) mask, offset, err := c.Glyph(index, freetype.Pt(0, 0)) if err != nil { fmt.Println("Rune generation error:", err) continue } bd := mask.Bounds() AdvanceWidth := c.FUnitToFix32(int(font.HMetric(index).AdvanceWidth)).Float() LeftSideBearing := c.FUnitToFix32(int(font.HMetric(index).LeftSideBearing)).Float() AdvanceWidth = AdvanceWidth / float32(sdfSize) LeftSideBearing = LeftSideBearing / float32(sdfSize) YOffset := (float32(-offset.Y) - float32(mask.Bounds().Max.Y)) / float32(sdfSize) relativeWidth := float32(bd.Dx()) / float32(sdfSize) relativeHeight := float32(bd.Dy()) / float32(sdfSize) sdfBounds := mask.Bounds() sdfBounds.Max.X = int(float64(sdfBounds.Max.X)/ratio) + 2 sdfBounds.Max.Y = int(float64(sdfBounds.Max.Y)/ratio) + 2 rects = append(rects, sdfBounds) LetterArray[r] = &LetterInfo{sdfBounds, YOffset, LeftSideBearing, AdvanceWidth, relativeWidth, relativeHeight} } ay, ax, e := FindOptimalSize(10, rects...) if e != nil { return nil, e } dst := image.NewRGBA(image.Rect(0, 0, int(ax), int(ay))) node := NewBin(int(ax), int(ay), Padding) rects, e = node.InsertArray(rects) if e != nil { return nil, e } rectIndex := 0 for _, r := range text { index := font.Index(r) mask, _, err := c.Glyph(index, freetype.Pt(0, 0)) if err != nil { fmt.Println("Rune generation error:", err) continue } rect := rects[rectIndex] newMask := image.NewAlpha(rect) //Note: this is slow we need to find better algorithm for xx := 0; xx < newMask.Bounds().Dx(); xx++ { for yy := 0; yy < newMask.Bounds().Dy(); yy++ { alpha := FindSDFAlpha(mask, int(float64(xx)*ratio), int(float64(yy)*ratio), scanRange) newMask.SetAlpha(xx, yy, color.Alpha{uint8(alpha)}) } } draw.Draw(dst, rect, newMask, image.ZP, draw.Src) LetterArray[r].Rect = rect rectIndex++ } texture, err := NewTexture(dst, dst.Pix) if err != nil { return nil, err } if readonly { texture.SetReadOnly() } texture.SetFiltering(Linear, Linear) return &Font{texture, LetterArray, size, dpi, true}, nil }
func NewFont2(fontPath string, size float64, dpi int, readonly bool, firstRune, lastRune rune) (*Font, error) { fontBytes, err := ioutil.ReadFile(fontPath) if err != nil { return nil, err } font, err := freetype.ParseFont(fontBytes) if err != nil { return nil, err } fontBytes = nil c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(font) c.SetFontSize(size) c.SetSrc(image.White) text := "" for i := firstRune; i < lastRune+1; i++ { text += string(i) } rects := make([]image.Rectangle, 0) LetterArray := make(map[rune]*LetterInfo) for _, r := range text { index := font.Index(r) mask, offset, err := c.Glyph(index, freetype.Pt(0, 0)) if err != nil { fmt.Println("Rune generation error:", err) continue } bd := mask.Bounds() AdvanceWidth := c.FUnitToFix32(int(font.HMetric(index).AdvanceWidth)).Float() LeftSideBearing := c.FUnitToFix32(int(font.HMetric(index).LeftSideBearing)).Float() AdvanceWidth = AdvanceWidth / float32(size) LeftSideBearing = LeftSideBearing / float32(size) YOffset := (float32(-offset.Y) - float32(mask.Bounds().Max.Y)) / float32(size) relativeWidth := float32(bd.Dx()) / float32(size) relativeHeight := float32(bd.Dy()) / float32(size) rects = append(rects, mask.Bounds()) LetterArray[r] = &LetterInfo{bd, YOffset, LeftSideBearing, AdvanceWidth, relativeWidth, relativeHeight} } ay, ax, e := FindOptimalSize(10, rects...) if e != nil { return nil, e } dst := image.NewRGBA(image.Rect(0, 0, int(ax), int(ay))) node := NewBin(int(ax), int(ay), Padding) rects, e = node.InsertArray(rects) if e != nil { return nil, e } rectIndex := 0 for _, r := range text { index := font.Index(r) mask, _, err := c.Glyph(index, freetype.Pt(0, 0)) if err != nil { fmt.Println("Rune generation error:", err) continue } rect := rects[rectIndex] draw.Draw(dst, rect, mask, image.ZP, draw.Src) LetterArray[r].Rect = rect rectIndex++ } texture, err := NewTexture(dst, dst.Pix) if err != nil { return nil, err } if readonly { texture.SetReadOnly() } texture.SetFiltering(Linear, Linear) return &Font{texture, LetterArray, size, dpi, false}, nil }