github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/examples/gtxt/pattern/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 "github.com/Kintar/etxt" 14 15 import "golang.org/x/image/math/fixed" 16 17 // Must be compiled with '-tags gtxt' 18 19 // An example showcasing how to draw glyphs manually and applying a 20 // specific pattern effect. The manual glyph drawing part is similar to 21 // examples/gtxt/mirror. 22 23 func main() { 24 // get font path 25 if len(os.Args) != 2 { 26 msg := "Usage: expects one argument with the path to the font to be used\n" 27 fmt.Fprint(os.Stderr, msg) 28 os.Exit(1) 29 } 30 31 // parse font 32 font, fontName, err := etxt.ParseFontFrom(os.Args[1]) 33 if err != nil { 34 log.Fatal(err) 35 } 36 fmt.Printf("Font loaded: %s\n", fontName) 37 38 // create cache 39 cache := etxt.NewDefaultCache(1024 * 1024 * 1024) // 1GB cache 40 41 // create and configure renderer 42 renderer := etxt.NewStdRenderer() 43 renderer.SetCacheHandler(cache.NewHandler()) 44 renderer.SetSizePx(64) 45 renderer.SetFont(font) 46 renderer.SetAlign(etxt.YCenter, etxt.XCenter) 47 renderer.SetColor(color.RGBA{255, 255, 255, 255}) // white 48 49 // create target image and fill it with black 50 outImage := image.NewRGBA(image.Rect(0, 0, 360, 64)) 51 for i := 3; i < 360*64*4; i += 4 { 52 outImage.Pix[i] = 255 53 } 54 55 // set target and start drawing 56 renderer.SetTarget(outImage) 57 renderer.Traverse("PATTERN", fixed.P(180, 32), 58 func(dot fixed.Point26_6, _ rune, glyphIndex etxt.GlyphIndex) { 59 mask := renderer.LoadGlyphMask(glyphIndex, dot) 60 drawAsPattern(dot, mask, outImage) 61 }) 62 63 // store result as png 64 filename, err := filepath.Abs("gtxt_pattern.png") 65 if err != nil { 66 log.Fatal(err) 67 } 68 fmt.Printf("Output image: %s\n", filename) 69 file, err := os.Create(filename) 70 if err != nil { 71 log.Fatal(err) 72 } 73 err = png.Encode(file, outImage) 74 if err != nil { 75 log.Fatal(err) 76 } 77 err = file.Close() 78 if err != nil { 79 log.Fatal(err) 80 } 81 fmt.Print("Program exited successfully.\n") 82 } 83 84 func drawAsPattern(dot fixed.Point26_6, mask etxt.GlyphMask, target *image.RGBA) { 85 // to draw a mask into a target, we need to displace it by the 86 // current dot (drawing position) and be careful with clipping 87 srcRect, destRect := getDrawBounds(mask.Rect, target.Bounds(), dot) 88 if destRect.Empty() { 89 return 90 } // nothing to draw 91 92 // we now have two rects that are the same size but identify 93 // different regions of the mask and target images. we can use 94 // them to read from one and draw on the other. yay. 95 96 // we start by creating some helper variables to make iteration 97 // through the rects more pleasant 98 width := srcRect.Dx() 99 height := srcRect.Dy() 100 srcOffX := srcRect.Min.X 101 srcOffY := srcRect.Min.Y 102 destOffX := destRect.Min.X 103 destOffY := destRect.Min.Y 104 105 // iterate the rects and draw! 106 for y := 0; y < height; y++ { 107 for x := 0; x < width; x++ { 108 // pattern filtering, edit and make your own! 109 // e.g: 110 // >> (x + y) % 2 == 0 111 // >> x % 3 != 2 && y % 3 != 2 112 // >> x % 3 == 2 || y % 3 == 2 113 // >> x == y 114 // >> (width - x) % 5 == y % 5 115 // >> (y > height/2) && (x + y) % 2 == 0 116 discard := x%2 != 0 || y%2 != 0 117 if discard { 118 continue 119 } 120 121 // get mask alpha level 122 level := mask.AlphaAt(srcOffX+x, srcOffY+y).A 123 if level == 0 { 124 continue 125 } // non-filled part of the glyph 126 127 // now we finally can draw to the target 128 target.SetRGBA(destOffX+x, destOffY+y, color.RGBA{255, 255, 255, 255}) 129 } 130 } 131 } 132 133 // same as in gtxt/mirror 134 func getDrawBounds(srcRect, targetRect image.Rectangle, dot fixed.Point26_6) (image.Rectangle, image.Rectangle) { 135 shift := image.Pt(dot.X.Floor(), dot.Y.Floor()) 136 destRect := targetRect.Intersect(srcRect.Add(shift)) 137 shift.X, shift.Y = -shift.X, -shift.Y 138 return destRect.Add(shift), destRect 139 }