Esempio n. 1
0
// Implements the Font interface.
func (f *TruetypeFont) Measure(i FontIndex) (*GlyphMetrics, error) {
	// Load into glyph buffer.
	if f.buf == nil {
		f.buf = truetype.NewGlyphBuf()
	}
	index := truetype.Index(i)
	scale := f.Font.FUnitsPerEm()
	err := f.buf.Load(f.Font, scale, index, f.Hinting)
	if err != nil {
		return nil, err
	}

	hMetric := f.Font.HMetric(scale, index)
	vMetric := f.Font.VMetric(scale, index)
	b := f.buf.B
	return &GlyphMetrics{
		Bounds: GlyphBounds{
			Min: Point{X: int(b.XMin), Y: int(b.YMin)},
			Max: Point{X: int(b.XMax), Y: int(b.YMax)},
		},
		BearingX: int(hMetric.LeftSideBearing),
		AdvanceX: int(hMetric.AdvanceWidth),
		BearingY: int(vMetric.TopSideBearing),
		AdvanceY: int(vMetric.AdvanceHeight),
	}, nil
}
Esempio n. 2
0
// 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
}
Esempio n. 3
0
func main() {
	flag.Parse()
	fmt.Printf("Loading fontfile %q\n", *fontfile)
	b, err := ioutil.ReadFile(*fontfile)
	if err != nil {
		log.Println(err)
		return
	}
	font, err := truetype.Parse(b)
	if err != nil {
		log.Println(err)
		return
	}
	fupe := font.FUnitsPerEm()
	printBounds(font.Bounds(fupe))
	fmt.Printf("FUnitsPerEm:%d\n\n", fupe)

	c0, c1 := 'A', 'V'

	i0 := font.Index(c0)
	hm := font.HMetric(fupe, i0)
	g := truetype.NewGlyphBuf()
	err = g.Load(font, fupe, i0, nil)
	if err != nil {
		log.Println(err)
		return
	}
	fmt.Printf("'%c' glyph\n", c0)
	fmt.Printf("AdvanceWidth:%d LeftSideBearing:%d\n", hm.AdvanceWidth, hm.LeftSideBearing)
	printGlyph(g)
	i1 := font.Index(c1)
	fmt.Printf("\n'%c', '%c' Kerning:%d\n", c0, c1, font.Kerning(fupe, i0, i1))
}
Esempio n. 4
0
// NewContext creates a new Context.
func NewContext() *Context {
	return &Context{
		r:        raster.NewRasterizer(0, 0),
		glyphBuf: truetype.NewGlyphBuf(),
		fontSize: 12,
		dpi:      72,
		scale:    12 << 6,
	}
}
Esempio n. 5
0
// NewGraphicContextWithPainter creates 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
	gc := &ImageGraphicContext{
		NewStackGraphicContext(),
		img,
		painter,
		raster.NewRasterizer(width, height),
		raster.NewRasterizer(width, height),
		truetype.NewGlyphBuf(),
		dpi,
	}
	return gc
}
Esempio n. 6
0
func (f *font) glyph(r rune) *glyph {
	if g, found := f.glyphs[r]; found {
		return g
	}
	idx := f.ttf.Index(r)
	gb := truetype.NewGlyphBuf()
	err := gb.Load(f.ttf, f.scale, idx, truetype.Hinting(truetype.FullHinting))
	if err != nil {
		panic(err)
	}

	g := glyph(*gb)
	f.glyphs[r] = &g
	return &g
}
Esempio n. 7
0
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
}
Esempio n. 8
0
func printGlyph(font *truetype.Font, c rune, resolution int32) {
	var idx = font.Index(c)
	var hm = font.HMetric(resolution, idx)
	var g = truetype.NewGlyphBuf()
	err := g.Load(font, resolution, idx, truetype.NoHinting)
	if err != nil {
		log.Println(err)
		return
	}
	fmt.Printf("'%c' glyph\n", c)
	fmt.Printf("AdvanceWidth:%d LeftSideBearing:%d\n", hm.AdvanceWidth, hm.LeftSideBearing)
	printGlyphCurve(g)

	c1 := 'A'
	i1 := font.Index(c1)
	fmt.Printf("\n'%c', '%c' Kerning:%d\n", c, c1, font.Kerning(resolution, idx, i1))
}
Esempio n. 9
0
// Implements the Font interface.
func (f *TruetypeFont) Lookup(i FontIndex) (glyphData interface{}, err error) {
	// Load into glyph buffer.
	if f.buf == nil {
		f.buf = truetype.NewGlyphBuf()
	}
	index := truetype.Index(i)
	scale := f.Font.FUnitsPerEm()
	err = f.buf.Load(f.Font, scale, index, f.Hinting)
	if err != nil {
		return nil, err
	}

	// Expand each contour.
	var (
		glyph QuadGlyph
		e0    int
	)
	for _, e1 := range f.buf.End {
		f.expandContour(&glyph, f.buf.Point[e0:e1])
		e0 = e1
	}
	return glyph, nil
}
Esempio n. 10
0
func genGlyphs(font *truetype.Font, size int, text string) (glyphs []*glyph) {

	scale := int32(float64(size) * dpi * (64.0 / 72.0))
	clip := image.Rect(0, 0, width, height)

	// Calculate the rasterizer's bounds to handle the largest glyph.
	b := font.Bounds(scale)
	xmin := int(b.XMin) >> 6
	ymin := -int(b.YMax) >> 6
	xmax := int(b.XMax+63) >> 6
	ymax := -int(b.YMin-63) >> 6

	r := raster.NewRasterizer(xmax-xmin, ymax-ymin)
	buf := truetype.NewGlyphBuf()

	for _, variant := range []string{strings.ToUpper(text), strings.ToLower(text)} {

		pt := Pt(30, 10+int(pointToFix32(float64(size))>>8))

		for _, char := range variant {

			idx := font.Index(char)
			buf.Load(font, scale, idx, truetype.FullHinting)

			// Calculate the integer-pixel bounds for the glyph.
			xmin := int(raster.Fix32(buf.B.XMin<<2)) >> 8
			ymin := int(-raster.Fix32(buf.B.YMax<<2)) >> 8
			xmax := int(raster.Fix32(buf.B.XMax<<2)+0xff) >> 8
			ymax := int(-raster.Fix32(buf.B.YMin<<2)+0xff) >> 8
			fx := raster.Fix32(-xmin << 8)
			fy := raster.Fix32(-ymin << 8)

			ix := int(pt.X >> 8)
			iy := int(pt.Y >> 8)

			// Rasterize the glyph's vectors.
			r.Clear()
			e0 := 0
			for _, e1 := range buf.End {
				drawContour(r, buf.Point[e0:e1], fx, fy)
				e0 = e1
			}

			mask := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin))
			r.Rasterize(raster.NewAlphaSrcPainter(mask))
			pt.X += raster.Fix32(buf.AdvanceWidth << 2)
			offset := image.Point{xmin + ix, ymin + iy}

			glyphRect := mask.Bounds().Add(offset)
			dr := clip.Intersect(glyphRect)
			mp := image.Point{0, dr.Min.Y - glyphRect.Min.Y}
			glyphs = append(glyphs, &glyph{
				mask: mask,
				mp:   mp,
				dr:   dr,
			})

		}
	}

	return

}
Esempio n. 11
0
func main() {
	flag.Parse()
	data, err := ioutil.ReadFile(*fontfile)
	if err != nil {
		fmt.Printf("Unable to read file: %v", err)
		os.Exit(1)
	}
	font, err := freetype.ParseFont(data)
	if err != nil {
		fmt.Printf("Unable to parse font file: %v", err)
		os.Exit(1)
	}

	all := *runes == "ALL"
	var usable []rune
	fmt.Printf("This font supports the following runes:\n")
	fmt.Printf("Rune, Val, Index\n")
	var gCheck truetype.GlyphBuf
	for r := rune(1); r < 65535; r++ {
		index := font.Index(r)
		if index == 0 {
			continue
		}
		err := gCheck.Load(font, 1, index, truetype.NoHinting)
		if err == nil {
			fmt.Printf("'%c': %d, %d\n", r, r, index)
		}
		if all {
			usable = append(usable, r)
		}
	}
	if all {
		*runes = string(usable)
	}

	rIn := make(chan rune)
	riOut := make(chan runeImage)
	var wg sync.WaitGroup

	// Send all of the runes along rIn then close it.
	go func() {
		for _, r := range *runes {
			fmt.Printf("Processing %c\n", r)
			rIn <- r
		}
		close(rIn)
	}()

	// Bring up *threads goroutines.  Each one reads from rIn, processes the rune and sends a
	// runeImage along riOut.
	for i := 0; i < *threads; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for r := range rIn {
				res, err := Render(font, r, *dpi, 0.05)
				if err != nil {
					fmt.Printf("Unable to render glyph: %v", err)
					os.Exit(1)
				}
				riOut <- runeImage{r: r, img: res}
			}
		}()
	}

	// Block until all of the above goroutines are done then close riOut.
	go func() {
		wg.Wait()
		close(riOut)
	}()

	// Take the results from riOut, put them into a slice and sort them.
	var ris runeImageSlice
	for ri := range riOut {
		ris = append(ris, ri)
	}
	sort.Sort(ris)

	// Now that runes are sorted, pack them.  The packing is simple, just fill up a row until the
	// next rune wouldn't fit, then go to the next row.  The runes are sorted first by largest
	// height then by smallest width, which isn't necessarily optimal, but it is good in general.
	// The +2 on several values here is so that there is a small buffer between runes so that we
	// don't accidentally draw part of one rune while render another.
	width := *width
	x, y := 0, 0
	cdy := ris[0].img.Bounds().Dy() + 2
	for _, ri := range ris {
		dx := ri.img.Bounds().Dx() + 2
		if x+dx > width {
			x = 0
			y += cdy
			cdy = ri.img.Bounds().Dy() + 2
		}
		x += dx
	}
	y += cdy
	height := 1
	for height < y {
		height *= 2
	}

	// Now that we know the position of all the runes in the atlas, actually draw them onto a single
	// image.
	atlas := image.NewGray(image.Rect(0, 0, width, height))
	x, y = 0, 0
	cdy = ris[0].img.Bounds().Dy() + 2
	var dict text.Dictionary
	dict.Runes = make(map[rune]text.RuneInfo)
	for _, ri := range ris {
		dx := ri.img.Bounds().Dx() + 2
		if x+dx > width {
			x = 0
			y += cdy
			cdy = ri.img.Bounds().Dy() + 2
		}
		dict.Runes[ri.r] = text.RuneInfo{PixBounds: ri.img.Bounds().Add(image.Point{x + 1, y + 1})}
		draw.Draw(atlas, dict.Runes[ri.r].PixBounds, ri.img, image.Point{}, draw.Over)
		x += dx
	}

	// Save the output.png file so that we can see what the atlas looks like.
	f, err := os.Create(fmt.Sprintf("%s.png", *output))
	if err != nil {
		fmt.Printf("Unable to make output file: %v", err)
		os.Exit(1)
	}
	err = png.Encode(f, atlas)
	if err != nil {
		fmt.Printf("Unable to encode png: %v", err)
		os.Exit(1)
	}
	f.Close()

	// There are several more values that need to go into a dictionary, so we'll go through all of
	// the runes that we're using and look up those values now.
	dict.Pix = atlas.Pix
	dict.Dx = int32(atlas.Bounds().Dx())
	dict.Dy = int32(atlas.Bounds().Dy())
	for _, r := range *runes {
		index := font.Index(r)
		ri := dict.Runes[r]
		ri.AdvanceHeight = int(font.VMetric(font.FUnitsPerEm(), index).AdvanceHeight)
		ri.TopSideBearing = int(font.VMetric(font.FUnitsPerEm(), index).TopSideBearing)
		ri.AdvanceWidth = int(font.HMetric(font.FUnitsPerEm(), index).AdvanceWidth)
		ri.LeftSideBearing = int(font.HMetric(font.FUnitsPerEm(), index).LeftSideBearing)
		glyph := truetype.NewGlyphBuf()
		glyph.Load(font, font.FUnitsPerEm(), index, truetype.FullHinting)
		ri.GlyphBounds.Min.X = int(glyph.B.XMin)
		ri.GlyphBounds.Min.Y = int(glyph.B.YMin)
		ri.GlyphBounds.Max.X = int(glyph.B.XMax)
		ri.GlyphBounds.Max.Y = int(glyph.B.YMax)
		dict.Runes[r] = ri
	}

	// Also store a mapping from rune pair to the kerning for that pair, if this font has that info.
	dict.Kerning = make(map[text.RunePair]int)
	for _, r0 := range *runes {
		for _, r1 := range *runes {
			kern := font.Kerning(font.FUnitsPerEm(), font.Index(r0), font.Index(r1))
			if kern == 0 {
				continue
			}
			dict.Kerning[text.RunePair{r0, r1}] = int(kern)
		}
	}
	dict.GlyphMax.Min.X = int(font.Bounds(font.FUnitsPerEm()).XMin)
	dict.GlyphMax.Min.Y = int(font.Bounds(font.FUnitsPerEm()).YMin)
	dict.GlyphMax.Max.X = int(font.Bounds(font.FUnitsPerEm()).XMax)
	dict.GlyphMax.Max.Y = int(font.Bounds(font.FUnitsPerEm()).YMax)

	// Now store the output.dict file so we can use it with text.LoadDictionary()
	{
		f, err := os.Create(fmt.Sprintf("%s.dict", *output))
		if err != nil {
			fmt.Printf("Failed to create output file: %v\n", err)
			os.Exit(1)
		}
		enc := gob.NewEncoder(f)
		err = enc.Encode(dict)
		if err != nil {
			fmt.Printf("Failed to encode data to output file: %v\n", err)
			os.Exit(1)
		}
		f.Close()
	}
}