func renderMeme(ctx appengine.Context, w io.Writer, id, topText, botText string) error { // Read template. templateName := templateFile(id) reader, err := file.Open(ctx, gcsFilesApiPath(bucket, templateName)) if err != nil { return err } defer reader.Close() bgImg, err := jpeg.Decode(reader) if err != nil { return err } img := image.NewRGBA(bgImg.Bounds()) draw.Draw(img, bgImg.Bounds(), bgImg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(72) c.SetFont(font) c.SetClip(img.Bounds()) c.SetDst(img) c.SetHinting(freetype.FullHinting) drawFitCentered(c, topText, img, false) drawFitCentered(c, botText, img, true) err = jpeg.Encode(w, img, &jpeg.Options{Quality: 75}) if err != nil { return err } return nil }
func (a *Annotator) init() error { // load the font fontBytes, err := resources.Asset(fontfile) if err != nil { return err } font, err := freetype.ParseFont(fontBytes) if err != nil { return err } // Initialize the context. fg := image.White a.context = freetype.NewContext() a.context.SetDPI(dpi) a.context.SetFont(font) a.context.SetFontSize(size) a.context.SetClip(a.image.Bounds()) a.context.SetDst(a.image) a.context.SetSrc(fg) switch hinting { default: a.context.SetHinting(freetype.NoHinting) case "full": a.context.SetHinting(freetype.FullHinting) } return nil }
// textBox renders t into a tight fitting image func (ig *ImageGraphics) textBox(t string, size int) image.Image { // Initialize the context. fg := image.NewUniform(color.Alpha{0xff}) bg := image.NewUniform(color.Alpha{0x00}) canvas := image.NewAlpha(image.Rect(0, 0, 400, 2*size)) draw.Draw(canvas, canvas.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) c.SetFontSize(float64(size)) c.SetClip(canvas.Bounds()) c.SetDst(canvas) c.SetSrc(fg) // Draw the text. h := c.FUnitToPixelRU(ig.font.UnitsPerEm()) pt := freetype.Pt(0, h) extent, err := c.DrawString(t, pt) if err != nil { log.Println(err) return nil } // log.Printf("text %q, extent: %v", t, extent) return canvas.SubImage(image.Rect(0, 0, int(extent.X/256), h*5/4)) }
/** * Create a new Graphic context from an image */ func NewGraphicContext(img draw.Image) *ImageGraphicContext { var painter Painter switch selectImage := img.(type) { case *image.RGBA: painter = raster.NewRGBAPainter(selectImage) //case *image.NRGBA: // painter = NewNRGBAPainter(selectImage) default: panic("Image type not supported") } width, height := img.Bounds().Dx(), img.Bounds().Dy() dpi := 92 ftContext := freetype.NewContext() ftContext.SetDPI(dpi) ftContext.SetClip(img.Bounds()) ftContext.SetDst(img) gc := &ImageGraphicContext{ NewStackGraphicContext(), img, painter, raster.NewRasterizer(width, height), raster.NewRasterizer(width, height), ftContext, dpi, } return gc }
// textBox renders t into a tight fitting image func (ig *ImageGraphics) textBox(t string, font chart.Font) image.Image { // Initialize the context. fg := image.NewUniform(color.Alpha{0xff}) bg := image.NewUniform(color.Alpha{0x00}) width := ig.TextLen(t, font) size := ig.relFontsizeToPixel(font.Size) canvas := image.NewAlpha(image.Rect(0, 0, width, int(1.5*size+0.5))) draw.Draw(canvas, canvas.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) c.SetFontSize(size) c.SetClip(canvas.Bounds()) c.SetDst(canvas) c.SetSrc(fg) // Draw the text. h := c.FUnitToPixelRU(ig.font.UnitsPerEm()) pt := freetype.Pt(0, h) extent, err := c.DrawString(t, pt) if err != nil { log.Println(err) return nil } // log.Printf("text %q, extent: %v", t, extent) return canvas.SubImage(image.Rect(0, 0, int((extent.X+127)/256), h*5/4)) }
func (q *Quote) TextToImage() *image.RGBA { spacing := 1.5 var fontsize float64 = 8 // read font fontBytes, err := ioutil.ReadFile(os.Getenv("FONT_FILE")) checkErr(err) font, err := freetype.ParseFont(fontBytes) checkErr(err) // Initialize the context. fg, bg := image.White, image.Transparent // 755px by 378px is the size Vox uses rgba := image.NewRGBA(image.Rect(0, 0, 755, 378)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(300) c.SetFont(font) c.SetFontSize(fontsize) c.SetClip(rgba.Bounds()) c.SetDst(rgba) c.SetSrc(fg) // Draw the text pt := freetype.Pt(50, 50+int(c.PointToFix32(fontsize)>>8)) lines := strings.Split(q.Text, "\n") for _, s := range lines { _, err = c.DrawString(s, pt) checkErr(err) pt.Y += c.PointToFix32(fontsize * spacing) } return rgba }
// NewText creates a new Text object. The x and y positions represent the left // and bottom of text without tails. func NewText(x, y float64, font *Font, fontSize float64, message string) (*Text, error) { text := &Text{} text.x = x text.y = y - fontSize text.fontColor = image.NewUniform(color.RGBA{0, 0, 0, 255}) text.context = freetype.NewContext() text.context.SetDPI(dpi) text.context.SetFont(font.font) text.context.SetFontSize(fontSize) text.context.SetSrc(text.fontColor) text.context.SetHinting(freetype.FullHinting) text.fontSize = fontSize err := text.SetMessage(message) if err != nil { return text, err } return text, nil }
// 画一个带有text的图片 func (this *Signer) drawStringImage(text string) (image.Image, error) { fg, bg := image.Black, image.Transparent rgba := image.NewRGBA(image.Rect(0, 0, this.signPoint.X, this.signPoint.Y)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(this.Dpi) c.SetFont(this.font) c.SetFontSize(this.FontSize) c.SetClip(rgba.Bounds()) c.SetDst(rgba) c.SetSrc(fg) // Draw the text. pt := freetype.Pt(10, 10+int(c.PointToFix32(12)>>8)) for _, s := range strings.Split(text, "\r\n") { _, err := c.DrawString(s, pt) if err != nil { glog.Errorf("c.DrawString(%s) error(%v)", s, err) return nil, err } pt.Y += c.PointToFix32(12 * 1.5) } // fff, _ := os.Create("aaa.png") // defer fff.Close() // png.Encode(fff, rgba) return rgba, nil }
func getFont(path string, sizePts int) font { sizePx := int(float64(sizePts)/ptInch*pxInch + 0.5) if f, ok := fonts[path]; ok { f.size = sizePx return f } in, err := os.Open(path) if err != nil { panic(err) } defer in.Close() fdata, err := ioutil.ReadAll(in) if err != nil { panic(err) } f := font{ path: path, Context: freetype.NewContext(), } if f.Font, err = truetype.Parse(fdata); err != nil { panic(err) } f.SetFont(f.Font) f.SetDPI(pxInch) fonts[path] = f f.size = sizePx return f }
func nosuchtile(v ...interface{}) []byte { im := image.NewRGBA(image.Rect(0, 0, tilesize, tilesize)) col := color.RGBA{255, 0, 0, 255} for i := 0; i < tilesize; i++ { im.Set(i, 0, col) im.Set(i, tilesize-1, col) im.Set(0, i, col) im.Set(tilesize-1, i, col) } ctx := freetype.NewContext() ctx.SetDPI(72) ctx.SetFont(nstfont) ctx.SetFontSize(16) ctx.SetClip(im.Bounds()) ctx.SetDst(im) ctx.SetSrc(image.Black) for i, n := range v { _, err := ctx.DrawString(fmt.Sprint(n), freetype.Pt(30, 30+i*20)) if err != nil { fmt.Println(err) } } var buf bytes.Buffer err := png.Encode(&buf, im) if err != nil { fmt.Println(err) } return buf.Bytes() }
// Render draws rune r front the specified font at the specified dpi and scale. It returns a // grayscale image that is just large enough to contain the rune. func Render(font *truetype.Font, r rune, dpi, scale float64) (*image.Gray, error) { glyph := truetype.NewGlyphBuf() index := font.Index(r) glyph.Load(font, font.FUnitsPerEm(), index, truetype.FullHinting) ctx := freetype.NewContext() boxer := makeBoundingBoxer() ctx.SetSrc(image.NewUniform(color.White)) ctx.SetDst(boxer) ctx.SetClip(boxer.largeBounds) ctx.SetFontSize(250) ctx.SetDPI(dpi) ctx.SetFont(font) if err := glyph.Load(font, font.FUnitsPerEm(), font.Index(r), truetype.FullHinting); err != nil { return nil, fmt.Errorf("Unable to load glyph: %v\n", err) } var rp raster.Point rp.X = ctx.PointToFix32(0) rp.Y = ctx.PointToFix32(100) ctx.DrawString(string(r), rp) boxer.complete() g := gift.New( gift.Resize(int(float64(boxer.Bounds().Dx())*scale+0.5), int(float64(boxer.Bounds().Dy())*scale+0.5), gift.CubicResampling), ) dst := image.NewGray(g.Bounds(boxer.Bounds())) g.Draw(dst, boxer) return dst, nil }
// 画一个带有text的图片 func drawStringImage(text string, fontFile string) image.Image { fontBytes, err := ioutil.ReadFile(fontFile) if err != nil { log.Fatalln(err) } font, err := freetype.ParseFont(fontBytes) if err != nil { log.Fatalln(err) } fg, bg := image.Black, image.White rgba := image.NewRGBA(image.Rect(0, 0, 640, 480)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(72) c.SetFont(font) c.SetFontSize(12) c.SetClip(rgba.Bounds()) c.SetDst(rgba) c.SetSrc(fg) // Draw the text. pt := freetype.Pt(10, 10+int(c.PointToFix32(12)>>8)) for _, s := range strings.Split(text, "\r\n") { _, err = c.DrawString(s, pt) pt.Y += c.PointToFix32(12 * 1.5) } return rgba }
/* 生成验证码 bg:背景色 fg:前景色 length:字符长度 width:宽度 height:高度 size:字体大小 fontPath:字体文件路径 */ func GenerateCaptcha(bg, fg *image.Uniform, length int, width int, height int, size float64, fontPath string) *Captcha { fontBytes, err := ioutil.ReadFile(fontPath) if err != nil { panic(err) } font, err := truetype.Parse(fontBytes) if err != nil { panic(err) } cap := &Captcha{} cap.Text = randString(length) cap.Image = image.NewRGBA(image.Rect(0, 0, width, height)) draw.Draw(cap.Image, cap.Image.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetFont(font) c.SetFontSize(size) c.SetClip(cap.Image.Bounds()) c.SetDst(cap.Image) c.SetSrc(fg) pt := freetype.Pt(0, int(c.PointToFix32(size)>>8)) for _, s := range cap.Text { _, err = c.DrawString(string(s), pt) if err != nil { panic(err) return nil } pt.X += c.PointToFix32(size * 0.5) } return cap }
// Color in HEX format: FAFAFA func (g *Gummy) DrawText(text, textColor string, fontSize, xPosition, yPosition int) error { // Get black or white depending on the background if textColor == "" { c := (*g.Color).(color.RGBA) if blackWithBackground(float64(c.R), float64(c.G), float64(c.B)) { textColor = "000000" } else { textColor = "FFFFFF" } } fc := freetype.NewContext() fc.SetDst(g.Img) fc.SetFont(g.Font) fc.SetClip(g.Img.Bounds()) // Color parsing cr, _ := strconv.ParseUint(string(textColor[:2]), 16, 64) cg, _ := strconv.ParseUint(string(textColor[2:4]), 16, 64) cb, _ := strconv.ParseUint(string(textColor[4:]), 16, 64) c := image.NewUniform(color.RGBA{R: uint8(cr), G: uint8(cg), B: uint8(cb), A: 255}) fc.SetSrc(c) fc.SetFontSize(float64(fontSize)) _, err := fc.DrawString(text, freetype.Pt(xPosition, yPosition)) return err }
func generateAtlas(font *truetype.Font, scale int32, dpi float64, width, height float32) ([]Vector4, *image.RGBA, []float32) { var low rune = 32 var high rune = 127 glyphCount := int32(high - low + 1) offsets := make([]float32, glyphCount) bounds := font.Bounds(scale) gw := float32(bounds.XMax - bounds.XMin) gh := float32(bounds.YMax - bounds.YMin) imageWidth := glh.Pow2(uint32(gw * float32(glyphCount))) imageHeight := glh.Pow2(uint32(gh)) imageBounds := image.Rect(0, 0, int(imageWidth), int(imageHeight)) sx := float32(2) / width sy := float32(2) / height w := gw * sx h := gh * sy img := image.NewRGBA(imageBounds) c := freetype.NewContext() c.SetDst(img) c.SetClip(img.Bounds()) c.SetSrc(image.White) c.SetDPI(dpi) c.SetFontSize(float64(scale)) c.SetFont(font) var gi int32 var gx, gy float32 verts := make([]Vector4, 0) texWidth := float32(img.Bounds().Dx()) texHeight := float32(img.Bounds().Dy()) for ch := low; ch <= high; ch++ { index := font.Index(ch) metric := font.HMetric(scale, index) //the offset is used when drawing a string of glyphs - we will advance a glyph's quad by the width of all previous glyphs in the string offsets[gi] = float32(metric.AdvanceWidth) * sx //draw the glyph into the atlas at the correct location pt := freetype.Pt(int(gx), int(gy)+int(c.PointToFix32(float64(scale))>>8)) c.DrawString(string(ch), pt) tx1 := gx / texWidth ty1 := gy / texHeight tx2 := (gx + gw) / texWidth ty2 := (gy + gh) / texHeight //the x,y coordinates are the same for each quad; only the texture coordinates (stored in z,w) change. //an optimization would be to only store texture coords, but I haven't figured that out yet verts = append(verts, Vector4{-1, 1, tx1, ty1}, Vector4{-1 + (w), 1, tx2, ty1}, Vector4{-1, 1 - (h), tx1, ty2}, Vector4{-1 + (w), 1 - (h), tx2, ty2}) gx += gw gi++ } return verts, img, offsets }
// ftContext does the boiler plate to create a freetype context func ftContext(font *truetype.Font, fontSize float64) *freetype.Context { c := freetype.NewContext() c.SetDPI(72) c.SetFont(font) c.SetFontSize(fontSize) return c }
func makeImage(req *http.Request, caption, font string, pt, size, border, scale int, f func(x, y int) uint32) *image.RGBA { d := (size + 2*border) * scale csize := 0 if caption != "" { if pt == 0 { pt = 11 } csize = pt * 2 } c := image.NewRGBA(image.Rect(0, 0, d, d+csize)) // white u := &image.Uniform{C: color.White} draw.Draw(c, c.Bounds(), u, image.ZP, draw.Src) for y := 0; y < size; y++ { for x := 0; x < size; x++ { r := image.Rect((x+border)*scale, (y+border)*scale, (x+border+1)*scale, (y+border+1)*scale) rgba := f(x, y) u.C = color.RGBA{byte(rgba >> 24), byte(rgba >> 16), byte(rgba >> 8), byte(rgba)} draw.Draw(c, r, u, image.ZP, draw.Src) } } if csize != 0 { if font == "" { font = "data/luxisr.ttf" } ctxt := fs.NewContext(req) dat, _, err := ctxt.Read(font) if err != nil { panic(err) } tfont, err := freetype.ParseFont(dat) if err != nil { panic(err) } ft := freetype.NewContext() ft.SetDst(c) ft.SetDPI(100) ft.SetFont(tfont) ft.SetFontSize(float64(pt)) ft.SetSrc(image.NewUniform(color.Black)) ft.SetClip(image.Rect(0, 0, 0, 0)) wid, err := ft.DrawString(caption, freetype.Pt(0, 0)) if err != nil { panic(err) } p := freetype.Pt(d, d+3*pt/2) p.X -= wid.X p.X /= 2 ft.SetClip(c.Bounds()) ft.DrawString(caption, p) } return c }
func (t *Tiler) newTypeContext(im *image.RGBA, color color.RGBA) *freetype.Context { c := freetype.NewContext() c.SetDPI(72) c.SetFont(t.font) c.SetFontSize(t.FontSize) c.SetClip(im.Bounds()) c.SetDst(im) c.SetSrc(image.NewUniform(color)) return c }
func convertString2image(s string) (*image.RGBA, error) { if debug { fmt.Println("convertString2image") } dpi := float64(72.0) //fontfile := "../font/MS Gothic.ttf" //fontfile := "../font/VL.ttf" fontfile := fontName hinting := "none" size := float64(17) spacing := float64(0) // Read the font data. fontBytes, err := ioutil.ReadFile(fontfile) if err != nil { log.Println(err) return nil, err } font, err := freetype.ParseFont(fontBytes) if err != nil { log.Println(err) return nil, err } // Initialize the context. fg, bg := image.Black, image.White rgba := image.NewRGBA(image.Rect(0, 0, 16, 16)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(font) c.SetFontSize(size) c.SetClip(rgba.Bounds()) c.SetDst(rgba) c.SetSrc(fg) switch hinting { default: c.SetHinting(freetype.NoHinting) case "full": c.SetHinting(freetype.FullHinting) } // Draw the text. pt := freetype.Pt(-1, -3+int(c.PointToFix32(size)>>8)) _, err = c.DrawString(s, pt) if err != nil { log.Println(err) return nil, err } pt.Y += c.PointToFix32(size * spacing) return rgba, nil }
func DrawTextOnImage(text string, font *truetype.Font, img *image.NRGBA, size, x, y int) { c := freetype.NewContext() c.SetDPI(120) c.SetFont(font) c.SetFontSize(float64(size)) c.SetClip(img.Bounds()) c.SetDst(img) c.SetSrc(image.Black) pt := freetype.Pt(x, y+int(c.PointToFix32(float64(size))>>8)) c.DrawString(text, pt) }
func createContext(font *truetype.Font) *freetype.Context { ctx := freetype.NewContext() ctx.SetDPI(*dpi) ctx.SetFont(font) ctx.SetFontSize(*size) switch *hinting { default: ctx.SetHinting(freetype.NoHinting) case "full": ctx.SetHinting(freetype.FullHinting) } return ctx }
func Context(dst *image.Alpha, bold bool) *freetype.Context { c := freetype.NewContext() c.SetDPI(dpi) if bold { c.SetFont(bld) } else { c.SetFont(reg) } c.SetFontSize(size) c.SetClip(dst.Bounds()) c.SetDst(dst) c.SetSrc(image.Opaque) return c }
func NewRenderer() *Renderer { r := Renderer{} fontBytes, _ := ioutil.ReadFile(*fontfile) r.font, _ = freetype.ParseFont(fontBytes) r.img = image.NewRGBA(image.Rect(0, 0, *width, *height)) r.context = freetype.NewContext() r.context.SetDPI(*dpi) r.context.SetFont(r.font) r.context.SetFontSize(*size) r.context.SetClip(r.img.Bounds()) draw.Draw(r.img, r.img.Bounds(), &image.Uniform{color.RGBA{0, 0, 0, 255}}, image.ZP, draw.Src) r.context.SetDst(r.img) return &r }
func init() { con = freetype.NewContext() data, err := ioutil.ReadFile("C:/Windows/Fonts/simsun.ttc") if err != nil { fmt.Println("Can't load simsun.ttc") return } font, err := freetype.ParseFont(data) if err != nil { fmt.Println("Can't parse simsun.ttc") return } con.SetDPI(120) con.SetFont(font) con.SetFontSize(12) }
func MakeTextLine(font_name, text string, width int, r, g, b, a float64) *TextLine { var w TextLine w.EmbeddedWidget = &BasicWidget{CoreWidget: &w} font, ok := basic_fonts[font_name] if !ok { panic(fmt.Sprintf("Unable to find a font registered as '%s'.", font_name)) } w.font = font w.glyph_buf = truetype.NewGlyphBuf() w.next_text = text w.context = freetype.NewContext() w.context.SetDPI(132) w.context.SetFontSize(12) w.SetColor(r, g, b, a) w.Request_dims = Dims{width, 35} return &w }
// Capture draws virtual terminal and return paletted image func (g *GifGenerator) Capture(state *terminal.State) (paletted *image.Paletted, err error) { fb := font.Bounds(fontSize) cursorX, cursorY := state.Cursor() paletted = image.NewPaletted(image.Rect(0, 0, g.Col*int(fb.XMax-fb.XMin)+10, g.Row*int(fb.YMax-fb.YMin)+10), palette.WebSafe) c := freetype.NewContext() c.SetFontSize(fontSize) c.SetFont(font) c.SetDst(paletted) c.SetClip(paletted.Bounds()) for row := 0; row < g.Row; row++ { for col := 0; col < g.Col; col++ { ch, fg, bg := state.Cell(col, row) var uniform *image.Uniform // background color if bg != terminal.DefaultBG { if bg == terminal.DefaultFG { uniform = image.White } else { uniform = image.NewUniform(color.Term256{Val: uint8(bg)}) } } // cursor if state.CursorVisible() && (row == cursorY && col == cursorX) { uniform = image.White } if uniform != nil { draw.Draw(paletted, image.Rect(5+col*int(fb.XMax-fb.XMin), row*int(fb.YMax-fb.YMin)-int(fb.YMin), 5+(col+1)*int(fb.XMax-fb.XMin), (row+1)*int(fb.YMax-fb.YMin)-int(fb.YMin)), uniform, image.ZP, draw.Src) } // foreground color switch fg { case terminal.DefaultFG: c.SetSrc(image.White) case terminal.DefaultBG: c.SetSrc(image.Black) default: c.SetSrc(image.NewUniform(color.Term256{Val: uint8(fg)})) } _, err = c.DrawString(string(ch), freetype.Pt(5+col*int(fb.XMax-fb.XMin), (row+1)*int(fb.YMax-fb.YMin))) if err != nil { return } } } return paletted, nil }
// Create a new Graphic context from an image and a Painter (see Freetype-go) func NewGraphicContextWithPainter(img draw.Image, painter Painter) *ImageGraphicContext { width, height := img.Bounds().Dx(), img.Bounds().Dy() dpi := 92 ftContext := freetype.NewContext() ftContext.SetDPI(float64(dpi)) ftContext.SetClip(img.Bounds()) ftContext.SetDst(img) gc := &ImageGraphicContext{ NewStackGraphicContext(), img, painter, raster.NewRasterizer(width, height), raster.NewRasterizer(width, height), ftContext, dpi, } return gc }
func (ig *ImageGraphics) TextLen(s string, font chart.Font) int { c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) c.SetFontSize(ig.relFontsizeToPixel(font.Size)) var p raster.Point prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := ig.font.Index(rune) if hasPrev { p.X += c.FUnitToFix32(int(ig.font.Kerning(prev, index))) } p.X += c.FUnitToFix32(int(ig.font.HMetric(index).AdvanceWidth)) prev, hasPrev = index, true } return int((p.X + 127) / 256) }
func getRGBA(str string, font *truetype.Font) *image.RGBA { rgba := image.NewRGBA(image.Rect(0, 0, 18, 18)) draw.Draw(rgba, rgba.Bounds(), image.White, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(150) c.SetFont(font) c.SetFontSize(14) c.SetClip(rgba.Bounds()) c.SetDst(rgba) c.SetSrc(image.Black) c.SetHinting(freetype.NoHinting) pt := freetype.Pt(0, 18) _, err := c.DrawString(str, pt) if err != nil { log.Fatal(err) } return rgba }
func (ig *ImageGraphics) TextLen(s string, font chart.Font) int { c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) fontsize := ig.relFontsizeToPixel(font.Size) c.SetFontSize(fontsize) scale := int32(fontsize * dpi * (64.0 / 72.0)) var p raster.Point prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := ig.font.Index(rune) if hasPrev { p.X += raster.Fix32(ig.font.Kerning(scale, prev, index)) << 2 } p.X += raster.Fix32(ig.font.HMetric(scale, index).AdvanceWidth) << 2 prev, hasPrev = index, true } return int((p.X + 127) / 256) }