github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/examples/gtxt/outline_cheap/main.go (about) 1 //go:build gtxt 2 3 package main 4 5 import "os" 6 import "image" 7 import "image/color" 8 import "image/png" 9 import "path/filepath" 10 import "log" 11 import "fmt" 12 13 import "golang.org/x/image/math/fixed" 14 15 import "github.com/Kintar/etxt" 16 17 // Must be compiled with '-tags gtxt' 18 19 // This example draws text with a cheap and simple outline, made by 20 // repeatedly drawing text slightly shifted to the left, right, up 21 // and down. For higher quality outlines, see the OutlineRasterizer 22 // instead and the gtxt/outline example. 23 // 24 // If you want a more advanced example on how to draw glyphs individually, 25 // check gtxt/mirror instead. This example uses the renderer's DefaultDrawFunc, 26 // so it doesn't get into the grittiest details. 27 28 func main() { 29 // get font path 30 if len(os.Args) != 2 { 31 msg := "Usage: expects one argument with the path to the font to be used\n" 32 fmt.Fprint(os.Stderr, msg) 33 os.Exit(1) 34 } 35 36 // parse font 37 font, fontName, err := etxt.ParseFontFrom(os.Args[1]) 38 if err != nil { 39 log.Fatal(err) 40 } 41 fmt.Printf("Font loaded: %s\n", fontName) 42 43 // create cache 44 cache := etxt.NewDefaultCache(1024 * 1024 * 1024) // 1GB cache 45 46 // create and configure renderer 47 renderer := etxt.NewStdRenderer() 48 renderer.SetCacheHandler(cache.NewHandler()) 49 renderer.SetSizePx(36) 50 renderer.SetFont(font) 51 renderer.SetAlign(etxt.YCenter, etxt.XCenter) 52 renderer.SetColor(color.RGBA{0, 0, 0, 255}) // black 53 54 // create target image and fill it with white 55 outImage := image.NewRGBA(image.Rect(0, 0, 312, 64)) 56 for i := 0; i < 312*64*4; i++ { 57 outImage.Pix[i] = 255 58 } 59 60 // set target and start drawing each character... 61 renderer.SetTarget(outImage) 62 63 // The key idea is to draw text repeatedly, slightly shifted 64 // to the left, right, up, down... and finally draw the middle. 65 // We could also do this with separate Draw() calls, but Traverse 66 // should be more efficient here. 67 // 68 // We will still draw the main text on a separate call afterwards 69 // in order to avoid the background of a letter being overlayed 70 // on top of a previously drawn letter (won't happen on most fonts 71 // or sizes or glyph sequences, but it's possible in some cases). 72 renderer.Traverse("Cheap Outline!", fixed.P(156, 32), 73 func(dot fixed.Point26_6, _ rune, glyphIndex etxt.GlyphIndex) { 74 const DotShift = 1 << 6 // we want to shift the letters 1 pixel 75 // to create an outline, but since we are 76 // using fixed precision numbers with 6 77 // bits for the decimal part, we need to 78 // apply this shift for the number to be 79 // correct in fixed.Int26_6 format. 80 81 mask := renderer.LoadGlyphMask(glyphIndex, dot) 82 dot.X -= DotShift // shift left 83 renderer.DefaultDrawFunc(dot, mask, glyphIndex) 84 dot.X += DotShift * 2 // shift right 85 renderer.DefaultDrawFunc(dot, mask, glyphIndex) 86 dot.X -= DotShift // restore X to center 87 dot.Y -= DotShift // shift up 88 renderer.DefaultDrawFunc(dot, mask, glyphIndex) 89 dot.Y += DotShift * 2 // shift down 90 renderer.DefaultDrawFunc(dot, mask, glyphIndex) 91 }) 92 93 // finally draw the main text. you can try different colors, but 94 // white makes it look like there's only outline, so that's cool. 95 renderer.SetColor(color.RGBA{255, 255, 255, 255}) 96 renderer.Draw("Cheap Outline!", 156, 32) 97 98 // store result as png 99 filename, err := filepath.Abs("gtxt_outline_cheap.png") 100 if err != nil { 101 log.Fatal(err) 102 } 103 fmt.Printf("Output image: %s\n", filename) 104 file, err := os.Create(filename) 105 if err != nil { 106 log.Fatal(err) 107 } 108 err = png.Encode(file, outImage) 109 if err != nil { 110 log.Fatal(err) 111 } 112 err = file.Close() 113 if err != nil { 114 log.Fatal(err) 115 } 116 fmt.Print("Program exited successfully.\n") 117 }