func BenchmarkDrawString(b *testing.B) { data, err := ioutil.ReadFile("../licenses/gpl.txt") if err != nil { b.Fatal(err) } lines := strings.Split(string(data), "\n") data, err = ioutil.ReadFile("../testdata/luxisr.ttf") if err != nil { b.Fatal(err) } f, err := Parse(data) if err != nil { b.Fatal(err) } dst := image.NewRGBA(image.Rect(0, 0, 800, 600)) draw.Draw(dst, dst.Bounds(), image.White, image.ZP, draw.Src) d := &font.Drawer{ Dst: dst, Src: image.Black, Face: NewFace(f, nil), } b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { for j, line := range lines { d.Dot = fixed.P(0, (j*16)%600) d.DrawString(line) } } }
func main() { // nGlyphs is the number of glyphs to generate: 95 characters in the range // [0x20, 0x7e], plus the replacement character. const nGlyphs = 95 + 1 // The particular font (unicode.7x13.font) leaves the right-most column // empty in its ASCII glyphs. We don't have to include that column in the // generated glyphs, so we subtract one off the effective width. const width, height, ascent = 7 - 1, 13, 11 readFile := func(name string) ([]byte, error) { return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name))) } fontData, err := readFile("unicode.7x13.font") if err != nil { log.Fatalf("readFile: %v", err) } face, err := plan9font.ParseFont(fontData, readFile) if err != nil { log.Fatalf("plan9font.ParseFont: %v", err) } dst := image.NewRGBA(image.Rect(0, 0, width, nGlyphs*height)) draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src) d := &font.Drawer{ Dst: dst, Src: image.White, Face: face, } for i := 0; i < nGlyphs; i++ { r := '\ufffd' if i < nGlyphs-1 { r = 0x20 + rune(i) } d.Dot = fixed.P(0, height*i+ascent) d.DrawString(string(r)) } w := bytes.NewBuffer(nil) w.WriteString(preamble) fmt.Fprintf(w, "// mask7x13 contains %d %d×%d glyphs in %d Pix bytes.\n", nGlyphs, width, height, nGlyphs*width*height) fmt.Fprintf(w, "var mask7x13 = &image.Alpha{\n") fmt.Fprintf(w, " Stride: %d,\n", width) fmt.Fprintf(w, " Rect: image.Rectangle{Max: image.Point{%d, %d*%d}},\n", width, nGlyphs, height) fmt.Fprintf(w, " Pix: []byte{\n") b := dst.Bounds() for y := b.Min.Y; y < b.Max.Y; y++ { if y%height == 0 { if y != 0 { w.WriteByte('\n') } i := y / height if i < nGlyphs-1 { i += 0x20 fmt.Fprintf(w, "// %#2x %q\n", i, rune(i)) } else { fmt.Fprintf(w, "// U+FFFD REPLACEMENT CHARACTER\n") } } for x := b.Min.X; x < b.Max.X; x++ { if dst.RGBAAt(x, y).R > 0 { w.WriteString("0xff,") } else { w.WriteString("0x00,") } } w.WriteByte('\n') } w.WriteString("},\n}\n") fmted, err := format.Source(w.Bytes()) if err != nil { log.Fatalf("format.Source: %v", err) } if err := ioutil.WriteFile("data.go", fmted, 0644); err != nil { log.Fatalf("ioutil.WriteFile: %v", err) } }
func ExampleParseFont() { readFile := func(name string) ([]byte, error) { return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name))) } fontData, err := readFile("unicode.7x13.font") if err != nil { log.Fatal(err) } face, err := plan9font.ParseFont(fontData, readFile) if err != nil { log.Fatal(err) } // TODO: derive the ascent from the face's metrics. const ascent = 11 dst := image.NewRGBA(image.Rect(0, 0, 4*7, 13)) draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src) d := &font.Drawer{ Dst: dst, Src: image.White, Face: face, Dot: fixed.P(0, ascent), } // Draw: // - U+0053 LATIN CAPITAL LETTER S // - U+03A3 GREEK CAPITAL LETTER SIGMA // - U+222B INTEGRAL // - U+3055 HIRAGANA LETTER SA // The testdata does not contain the CJK subfont files, so U+3055 HIRAGANA // LETTER SA (さ) should be rendered as U+FFFD REPLACEMENT CHARACTER (�). // // The missing subfont file will trigger an "open // ../testdata/shinonome/k12.3000: no such file or directory" log message. // This is expected and can be ignored. d.DrawString("SΣ∫さ") // Convert the dst image to ASCII art. var out []byte b := dst.Bounds() for y := b.Min.Y; y < b.Max.Y; y++ { out = append(out, '0'+byte(y%10), ' ') for x := b.Min.X; x < b.Max.X; x++ { if dst.RGBAAt(x, y).R > 0 { out = append(out, 'X') } else { out = append(out, '.') } } // Highlight the last row before the baseline. Glyphs like 'S' without // descenders should not affect any pixels whose Y coordinate is >= the // baseline. if y == ascent-1 { out = append(out, '_') } out = append(out, '\n') } os.Stdout.Write(out) // Output: // 0 ..................X......... // 1 .................X.X........ // 2 .XXXX..XXXXXX....X.....XXX.. // 3 X....X.X.........X....XX.XX. // 4 X.......X........X....X.X.X. // 5 X........X.......X....XXX.X. // 6 .XXXX.....X......X....XX.XX. // 7 .....X...X.......X....XX.XX. // 8 .....X..X........X....XXXXX. // 9 X....X.X.........X....XX.XX. // 0 .XXXX..XXXXXX....X.....XXX.._ // 1 ...............X.X.......... // 2 ................X........... }