// rasterize returns the advance width, glyph mask and integer-pixel offset // to render the given glyph at the given sub-pixel offsets. // The 24.8 fixed point arguments fx and fy must be in the range [0, 1). func (c *Context) rasterize(glyph truetype.Index, fx, fy raster.Fix32) ( raster.Fix32, *image.Alpha, image.Point, error) { if err := c.glyphBuf.Load(c.font, c.scale, glyph, truetype.Hinting(c.hinting)); err != nil { return 0, nil, image.Point{}, err } // Calculate the integer-pixel bounds for the glyph. xmin := int(fx+raster.Fix32(c.glyphBuf.B.XMin<<2)) >> 8 ymin := int(fy-raster.Fix32(c.glyphBuf.B.YMax<<2)) >> 8 xmax := int(fx+raster.Fix32(c.glyphBuf.B.XMax<<2)+0xff) >> 8 ymax := int(fy-raster.Fix32(c.glyphBuf.B.YMin<<2)+0xff) >> 8 if xmin > xmax || ymin > ymax { return 0, nil, image.Point{}, errors.New("freetype: negative sized glyph") } // A TrueType's glyph's nodes can have negative co-ordinates, but the // rasterizer clips anything left of x=0 or above y=0. xmin and ymin // are the pixel offsets, based on the font's FUnit metrics, that let // a negative co-ordinate in TrueType space be non-negative in // rasterizer space. xmin and ymin are typically <= 0. fx += raster.Fix32(-xmin << 8) fy += raster.Fix32(-ymin << 8) // Rasterize the glyph's vectors. c.r.Clear() e0 := 0 for _, e1 := range c.glyphBuf.End { c.drawContour(c.glyphBuf.Point[e0:e1], fx, fy) e0 = e1 } a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin)) c.r.Rasterize(raster.NewAlphaSrcPainter(a)) return raster.Fix32(c.glyphBuf.AdvanceWidth << 2), a, image.Point{xmin, ymin}, nil }
// rasterize returns the advance width, glyph mask and integer-pixel offset // to render the given glyph at the given sub-pixel offsets. // The 26.6 fixed point arguments fx and fy must be in the range [0, 1). func (c *Context) rasterize(glyph truetype.Index, fx, fy fixed.Int26_6) ( fixed.Int26_6, *image.Alpha, image.Point, error) { if err := c.glyphBuf.Load(c.f, c.scale, glyph, c.hinting); err != nil { return 0, nil, image.Point{}, err } // Calculate the integer-pixel bounds for the glyph. xmin := int(fx+c.glyphBuf.Bounds.Min.X) >> 6 ymin := int(fy-c.glyphBuf.Bounds.Max.Y) >> 6 xmax := int(fx+c.glyphBuf.Bounds.Max.X+0x3f) >> 6 ymax := int(fy-c.glyphBuf.Bounds.Min.Y+0x3f) >> 6 if xmin > xmax || ymin > ymax { return 0, nil, image.Point{}, errors.New("freetype: negative sized glyph") } // A TrueType's glyph's nodes can have negative co-ordinates, but the // rasterizer clips anything left of x=0 or above y=0. xmin and ymin are // the pixel offsets, based on the font's FUnit metrics, that let a // negative co-ordinate in TrueType space be non-negative in rasterizer // space. xmin and ymin are typically <= 0. fx -= fixed.Int26_6(xmin << 6) fy -= fixed.Int26_6(ymin << 6) // Rasterize the glyph's vectors. c.r.Clear() e0 := 0 for _, e1 := range c.glyphBuf.Ends { c.drawContour(c.glyphBuf.Points[e0:e1], fx, fy) e0 = e1 } a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin)) c.r.Rasterize(raster.NewAlphaSrcPainter(a)) return c.glyphBuf.AdvanceWidth, a, image.Point{xmin, ymin}, nil }
func main() { // Draw a rounded corner that is one pixel wide. r := raster.NewRasterizer(50, 50) r.Start(p(5, 5)) r.Add1(p(5, 25)) r.Add2(p(5, 45), p(25, 45)) r.Add1(p(45, 45)) r.Add1(p(45, 44)) r.Add1(p(26, 44)) r.Add2(p(6, 44), p(6, 24)) r.Add1(p(6, 5)) r.Add1(p(5, 5)) // Rasterize that curve multiple times at different gammas. const ( w = 600 h = 200 ) rgba := image.NewRGBA(image.Rect(0, 0, w, h)) draw.Draw(rgba, image.Rect(0, 0, w, h/2), image.Black, image.ZP, draw.Src) draw.Draw(rgba, image.Rect(0, h/2, w, h), image.White, image.ZP, draw.Src) mask := image.NewAlpha(image.Rect(0, 0, 50, 50)) painter := raster.NewAlphaSrcPainter(mask) gammas := []float64{1.0 / 10.0, 1.0 / 3.0, 1.0 / 2.0, 2.0 / 3.0, 4.0 / 5.0, 1.0, 5.0 / 4.0, 3.0 / 2.0, 2.0, 3.0, 10.0} for i, g := range gammas { draw.Draw(mask, mask.Bounds(), image.Transparent, image.ZP, draw.Src) r.Rasterize(raster.NewGammaCorrectionPainter(painter, g)) x, y := 50*i+25, 25 draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.White, image.ZP, mask, image.ZP, draw.Over) y += 100 draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.Black, image.ZP, mask, image.ZP, draw.Over) } // Save that RGBA image to disk. f, err := os.Create("out.png") if err != nil { log.Println(err) os.Exit(1) } defer f.Close() b := bufio.NewWriter(f) err = png.Encode(b, rgba) if err != nil { log.Println(err) os.Exit(1) } err = b.Flush() if err != nil { log.Println(err) os.Exit(1) } fmt.Println("Wrote out.png OK.") }
func (p *glyphPage) add(rune rune, g *glyph) bool { if _, found := p.offsets[rune]; found { panic("Glyph already added to glyph page") } w, h := g.size(p.resolution).WH() x, y := p.nextPoint.X, p.nextPoint.Y if x+w > p.size.W { // Row full, start new line x = 0 y += p.rowHeight + glyphPadding p.rowHeight = 0 } if y+h > p.size.H { return false // Page full } // Build the raster contours p.rast.Clear() fx := -raster.Fix32((int64(g.B.XMin) * int64(p.resolution)) >> 14) fy := +raster.Fix32((int64(g.B.YMax) * int64(p.resolution)) >> 14) e0 := 0 for _, e1 := range g.End { p.drawContour(g.Point[e0:e1], fx, fy) e0 = e1 } // Perform the rasterization a := &image.Alpha{ Pix: p.image.Pix[x+y*p.image.Stride:], Stride: p.image.Stride, Rect: image.Rect(0, 0, w, h), } p.rast.Rasterize(raster.NewAlphaSrcPainter(a)) p.offsets[rune] = math.Point{X: x, Y: y} p.nextPoint = math.Point{X: x + w + glyphPadding, Y: y} if h > p.rowHeight { p.rowHeight = h } p.tex = nil return true }
func main() { // Rasterize the contours to a mask image. const ( w = 400 h = 400 ) r := raster.NewRasterizer(w, h) contour(r, outside) contour(r, inside) mask := image.NewAlpha(image.Rect(0, 0, w, h)) p := raster.NewAlphaSrcPainter(mask) r.Rasterize(p) // Draw the mask image (in gray) onto an RGBA image. rgba := image.NewRGBA(image.Rect(0, 0, w, h)) gray := image.NewUniform(color.Alpha{0x1f}) draw.Draw(rgba, rgba.Bounds(), image.Black, image.ZP, draw.Src) draw.DrawMask(rgba, rgba.Bounds(), gray, image.ZP, mask, image.ZP, draw.Over) showNodes(rgba, outside) showNodes(rgba, inside) // Save that RGBA image to disk. outFile, err := os.Create("out.png") if err != nil { log.Println(err) os.Exit(1) } defer outFile.Close() b := bufio.NewWriter(outFile) err = png.Encode(b, rgba) if err != nil { log.Println(err) os.Exit(1) } err = b.Flush() if err != nil { log.Println(err) os.Exit(1) } fmt.Println("Wrote out.png OK.") }