func main() { flag.Parse() font, err := loadFont() if err != nil { log.Println(err) return } fontHeight := int(createContext(font).PointToFix32(*size) >> 8) // two points to output the text and its shadow ptA := freetype.Pt(*indent+1, *indent+1+fontHeight) ptB := freetype.Pt(*indent, *indent+fontHeight) proxy := goproxy.NewProxyHttpServer() proxy.OnResponse().Do(goproxy_image.HandleImage(func(img image.Image, ctx *goproxy.ProxyCtx) image.Image { outImage := image.NewRGBA(img.Bounds()) draw.Copy(outImage, image.ZP, img, img.Bounds(), nil) text := fmt.Sprintf("%dx%d", img.Bounds().Dx(), img.Bounds().Dy()) fontContext := createContext(font) fontContext.SetClip(img.Bounds()) fontContext.SetDst(outImage) drawString(image.White, fontContext, ptA, text) drawString(image.Black, fontContext, ptB, text) return outImage })) proxy.Verbose = *verbose log.Fatal(http.ListenAndServe(":"+*port, proxy)) }
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 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() }
func (a *Annotator) DrawInfoBox() error { tStart, tEnd := a.table.TimeStart, a.table.TimeEnd // tDuration := humanize.RelTime(*tStart, *tEnd, "", "") tPixel := (tEnd.Unix() - tStart.Unix()) / int64(a.table.Integrations) fStart, fEnd := a.table.HzLow, a.table.HzHigh fBandwidth := fEnd - fStart fPixel := fBandwidth / float64(a.table.Bins) perPixel := fmt.Sprintf("%s x %d seconds", a.humanHz(fPixel), tPixel) // positioning imgSize := a.table.Image().Bounds().Size() top, left := imgSize.Y-75, 3 strings := []string{ "Scan start: " + tStart.String(), "Scan end: " + tEnd.String(), // "Scan duration: " + tDuration, fmt.Sprintf("Band: %s to %s", a.humanHz(fStart), a.humanHz(fEnd)), fmt.Sprintf("Bandwidth: %s", a.humanHz(fBandwidth)), "1 pixel = " + perPixel, } // drawing pt := freetype.Pt(left, top) for _, s := range strings { _, _ = a.context.DrawString(s, pt) pt.Y += a.context.PointToFix32(size * spacing) } return nil }
// 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 (gc *ImageGraphicContext) FillString(text string) (cursor float64) { gc.freetype.SetSrc(image.NewUniform(gc.Current.StrokeColor)) // Draw the text. x, y := gc.Current.Path.LastPoint() gc.Current.Tr.Transform(&x, &y) x0, fontSize := 0.0, gc.Current.FontSize gc.Current.Tr.VectorTransform(&x0, &fontSize) font := GetFont(gc.Current.FontData) if font == nil { font = GetFont(defaultFontData) } if font == nil { return 0 } gc.freetype.SetFont(font) gc.freetype.SetFontSize(fontSize) pt := freetype.Pt(int(x), int(y)) p, err := gc.freetype.DrawString(text, pt) if err != nil { log.Println(err) } x1, _ := gc.Current.Path.LastPoint() x2, y2 := float64(p.X)/256, float64(p.Y)/256 gc.Current.Tr.InverseTransform(&x2, &y2) width := x2 - x1 return width }
// 画一个带有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 }
/* 生成验证码 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 }
// 画一个带有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 }
// 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)) }
// 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 }
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 }
func renderString(s string, c *freetype.Context) (*image.RGBA, int) { estWidth := 8 * len(s) dst := image.NewRGBA(image.Rect(0, 0, estWidth, h)) c.SetDst(dst) c.SetClip(dst.Bounds()) c.SetSrc(&image.Uniform{C: shadow}) pt := freetype.Pt(0, 13) c.DrawString(s, pt) c.SetSrc(image.White) pt = freetype.Pt(0, 12) pt, _ = c.DrawString(s, pt) return dst, getTextOffset(pt) }
func drawBorderedText(c *freetype.Context, text string, x, y int) { // God-awful hack to add a 2px black border around the text. c.SetSrc(image.Black) c.DrawString(text, freetype.Pt(x-2, y-2)) c.DrawString(text, freetype.Pt(x, y-2)) c.DrawString(text, freetype.Pt(x+2, y-2)) c.DrawString(text, freetype.Pt(x-2, y)) c.DrawString(text, freetype.Pt(x+2, y)) c.DrawString(text, freetype.Pt(x-2, y+2)) c.DrawString(text, freetype.Pt(x, y+2)) c.DrawString(text, freetype.Pt(x+2, y+2)) c.SetSrc(image.White) c.DrawString(text, freetype.Pt(x, y)) }
func (r *Renderer) DrawKanji(kanji *Kanji, x int, y int) { pt := freetype.Pt(x, y-int(r.fontsize/10.0)) pt.Y += r.context.PointToFix32(r.fontsize) r.context.SetSrc(&image.Uniform{kanji.Color()}) for _, s := range kanji.character { r.context.DrawString(string(s), pt) } r.context.SetClip(r.img.Bounds()) }
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 (w *TextEditLine) findOffsetAtIndex(index int) float64 { pt := freetype.Pt(0, 0) if index > len(w.text) { index = len(w.text) } if index < 0 { index = 0 } adv, _ := w.context.DrawString(w.text[:index], pt) return float64(adv.X>>8) * w.scale }
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 (box *Box) RenderText(context *Context, x int, y int) { pt := freetype.Pt(x, y) pt.Y += context.FontContext.PointToFix32(18.0) context.FontContext.SetSrc(&image.Uniform{color.RGBA{255, 255, 255, 255}}) for _, s := range box.Content { context.FontContext.DrawString(string(s), pt) pt.X += context.FontContext.PointToFix32(18.0) } context.FontContext.SetClip(context.Img.Bounds()) }
func initBadge() { m.Get("/badge/:web/:name/:p/download.png", func(w http.ResponseWriter, r *http.Request) { var err error img := image.NewNRGBA(image.Rect(0, 0, 140, 18)) fontBytes, err := ioutil.ReadFile(fontFile) if err != nil { return } font, err := freetype.ParseFont(fontBytes) if err != nil { return } left, right := img.Bounds(), img.Bounds() const middle = 60 left.Max = image.Pt(middle, 18) right.Min = image.Pt(middle, 0) // fill left(black) right(green) draw.Draw(img, left, &image.Uniform{black}, image.ZP, draw.Src) draw.Draw(img, right, &image.Uniform{green}, image.ZP, draw.Src) // draw "gobuild.io | download" c := freetype.NewContext() c.SetDPI(fontDPI) c.SetFont(font) c.SetFontSize(fontSize) c.SetClip(img.Bounds()) c.SetDst(img) c.SetSrc(image.White) pt := freetype.Pt(7, 12) _, err = c.DrawString("gobuild.io", pt) // 10 chars width = 60px if err != nil { return } c.SetSrc(image.Black) pt = freetype.Pt(middle+18, 12) _, err = c.DrawString("download", pt) w.Header().Set("Content-Type", "image/png") png.Encode(w, img) }) }
func BadgeEncode(w io.Writer, message string) (err error) { // draw "gobuild.io | download" webname := "GOBUILD" const middle = 65 const gap = 8 img := image.NewNRGBA(image.Rect(0, 0, middle+(len(message)+1)*7+gap*2, 18)) fontBytes, err := ioutil.ReadFile(fontFile) if err != nil { return } font, err := freetype.ParseFont(fontBytes) if err != nil { return } left, right := img.Bounds(), img.Bounds() left.Max = image.Pt(middle, 18) right.Min = image.Pt(middle, 0) // fill left(black) right(green) draw.Draw(img, left, &image.Uniform{black}, image.ZP, draw.Src) draw.Draw(img, right, &image.Uniform{green}, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(fontDPI) c.SetFont(font) c.SetFontSize(fontSize) c.SetClip(img.Bounds()) c.SetDst(img) c.SetSrc(image.White) pt := freetype.Pt(gap, 12) _, err = c.DrawString(webname, pt) // 10 chars width = 60px if err != nil { return } c.SetSrc(image.Black) pt = freetype.Pt(middle+gap, 13) _, err = c.DrawString(message, pt) // w.Header().Set("Content-Type", "image/png") return png.Encode(w, img) }
func (a *Annotator) DrawYScale() error { log.WithFields(log.Fields{ "timestart": a.table.TimeStart.String(), "timeend": a.table.TimeEnd.String(), }).Debug("annotate Y scale") start, end := a.table.TimeStart, a.table.TimeEnd // how many samples? count := int(math.Floor(float64(a.table.Integrations) / float64(100))) uStart := start.Unix() uEnd := end.Unix() secsPerLabel := int(math.Floor(float64(uEnd-uStart) / float64(count))) pxPerLabel := int(math.Floor(float64(a.table.Integrations) / float64(count))) log.WithFields(log.Fields{ "labels": count, "secsPerLabel": secsPerLabel, "pxPerLabel": pxPerLabel, }).Debug("annotate Y scale") for si := 0; si < count; si++ { secs := time.Duration(secsPerLabel * si * int(time.Second)) px := si * pxPerLabel var str string = "" if si == 0 { str = start.String() } else { point := start.Add(secs) str = point.Format("15:04:05") } // draw a guideline on the exact time for i := 0; i < 75; i++ { a.image.Set(i, px, image.White) } // draw the text, 3 px margin to the line pt := freetype.Pt(3, px-3) _, _ = a.context.DrawString(str, pt) } return nil }
func (f *font) draw(s string, col color.Color) *image.NRGBA { width := f.width(s) height, _, descent := f.extents() img := image.NewNRGBA(image.Rect(0, 0, width, height)) f.SetFontSize(float64(f.size)) f.SetSrc(image.NewUniform(col)) f.SetClip(img.Bounds()) f.SetDst(img) if _, err := f.DrawString(s, freetype.Pt(0, height+descent)); err != nil { panic(err) } return img }
func (text *Text) findTextDimensions() (int, int, error) { tempRGBA := image.NewRGBA(image.Rect(0, 0, 1, 1)) draw.Draw(tempRGBA, tempRGBA.Bounds(), image.Transparent, image.ZP, draw.Src) text.context.SetDst(tempRGBA) text.context.SetClip(tempRGBA.Bounds()) pt := freetype.Pt(0, int(text.context.PointToFix32(text.fontSize)>>8)) endPos, err := text.context.DrawString(text.message, pt) if err != nil { return 0, 0, err } return int(endPos.X >> 8), int(text.context.PointToFix32(text.fontSize*2) >> 8), nil }
func main() { file, err := os.Create(`out.png`) if err != nil { return } defer file.Close() con.SetDPI(72) ori = freetype.Pt(10, 100) _, err = con.DrawString(str, ori) con.SetDPI(108) ori = freetype.Pt(10, 200) _, err = con.DrawString(str, ori) con.SetDPI(144) ori = freetype.Pt(10, 300) _, err = con.DrawString(str, ori) con.SetDPI(180) ori = freetype.Pt(10, 400) _, err = con.DrawString(str, ori) con.SetSrc(red) con.SetDPI(72) con.SetFontSize(20) ori = freetype.Pt(510, 100) _, err = con.DrawString(str, ori) con.SetFontSize(30) ori = freetype.Pt(510, 200) _, err = con.DrawString(str, ori) con.SetFontSize(40) ori = freetype.Pt(510, 300) _, err = con.DrawString(str, ori) con.SetFontSize(50) ori = freetype.Pt(510, 400) _, err = con.DrawString(str, ori) png.Encode(file, img) }
// 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 }
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 }
// Render renders the text in the given font and returns an image // of the formatted string. func (font Font) Render(format string, vls ...interface{}) (img Image, err error) { str := fmt.Sprintf(format, vls...) width, height, descent := font.textSize(str) rgba := image.NewNRGBA(image.Rect(0, 0, width, height)) draw.Draw(rgba, rgba.Bounds(), image.Black, image.ZP, draw.Src) font.ctx.SetDst(rgba) font.ctx.SetClip(rgba.Bounds()) pt := freetype.Pt(0, height+descent) pt, err = font.ctx.DrawString(str, pt) if err != nil { return } img = MakeImage(rgba) return }
// 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) bb := ig.font.Bounds(int32(size)) // TODO: Ugly, manual, heuristic hack to get "nicer" text for common latin characters bb.YMin++ if size >= 15 { bb.YMin++ bb.YMax-- } if size >= 20 { bb.YMax-- } if size >= 25 { bb.YMin++ bb.YMax-- } dy := int(bb.YMax - bb.YMin) canvas := image.NewAlpha(image.Rect(0, 0, width, dy)) 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. pt := freetype.Pt(0, dy+int(bb.YMin)-1) 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), dy)) }